Compare commits

...

574 Commits
7.0.0 ... 7.2.1

Author SHA1 Message Date
Athou
2e1e5257b4 release 7.2.1 2026-08-03 09:06:32 +02:00
Athou
bc6e767953 prevent XXS in third party apps
CommaFeed React client already strips malicious "javascript:" urls but we might as well not store those in the database
2026-08-03 08:47:01 +02:00
Jérémie Panzer
b9eceaae73 Merge pull request #2255 from Athou/renovate/vite-8.x
chore(deps): update dependency vite to v8.2.0
2026-08-03 08:46:22 +02:00
renovate[bot]
8ad9ba7d74 chore(deps): update react monorepo 2026-08-03 01:41:07 +00:00
renovate[bot]
10bb4b7936 chore(deps): update dependency vite to v8.2.0 2026-08-02 12:46:43 +00:00
renovate[bot]
ab3127cef9 chore(deps): update dependency @vitejs/plugin-react to v6.0.5 2026-08-02 12:46:33 +00:00
Athou
5d64e2f21e correctly handle root favicons for non-default ports 2026-08-02 07:26:44 +02:00
renovate[bot]
e404c9ce3b chore(deps): update dependency npm to v12.0.2 2026-08-01 22:16:06 +00:00
Jérémie Panzer
0c5a71650c Merge pull request #2254 from Athou/renovate/axios-1.x
fix(deps): update dependency axios to v1.19.0
2026-08-02 00:15:20 +02:00
renovate[bot]
8ce9eb8537 fix(deps): update dependency axios to v1.19.0 2026-08-01 20:46:05 +00:00
renovate[bot]
1ce0e4af97 chore(deps): update dependency jsdom to v30.0.1 2026-08-01 10:11:03 +00:00
Jérémie Panzer
44ad42a8a5 Merge pull request #2252 from Athou/renovate/patch-react-router-monorepo
fix(deps): update dependency react-router-dom to v7.18.2
2026-08-01 12:09:31 +02:00
Jérémie Panzer
f213726c40 Merge pull request #2251 from Athou/renovate/react-draggable-4.7.x
fix(deps): update dependency react-draggable to v4.7.1
2026-08-01 12:09:08 +02:00
renovate[bot]
972d424846 fix(deps): update dependency react-router-dom to v7.18.2 2026-08-01 09:19:12 +00:00
renovate[bot]
6049263137 fix(deps): update dependency react-draggable to v4.7.1 2026-08-01 09:19:02 +00:00
Athou
ae2dc7f066 update google java format and let renovate know about it 2026-08-01 11:17:50 +02:00
Athou
503d129f22 increase timeout even more because tests are still flaky 2026-08-01 11:13:41 +02:00
renovate[bot]
543ec3bbb1 fix(deps): update dependency org.apache.httpcomponents.client5:httpclient5 to v5.6.3 2026-07-31 17:48:01 +00:00
renovate[bot]
bed45127c4 chore(deps): update dependency @biomejs/biome to v2.5.6 2026-07-31 15:42:20 +00:00
Jérémie Panzer
71f10b0a62 Merge pull request #2250 from Athou/renovate/patch-react-querybuilder
fix(deps): update react-querybuilder to v8.21.2
2026-07-31 07:42:57 +02:00
renovate[bot]
cb235289c4 fix(deps): update react-querybuilder to v8.21.2 2026-07-31 03:05:02 +00:00
renovate[bot]
0b07c65320 chore(deps): update dependency io.quarkiverse.playwright:quarkus-playwright to v2.3.8 2026-07-30 23:29:02 +00:00
Jérémie Panzer
868f65d7c9 Merge pull request #2249 from Athou/renovate/jsdom-30.x
chore(deps): update dependency jsdom to v30
2026-07-30 11:02:50 +02:00
Jérémie Panzer
07715383f4 Merge pull request #2248 from Athou/renovate/mantine-monorepo
fix(deps): update mantine monorepo to v9.5.0
2026-07-30 11:02:48 +02:00
renovate[bot]
29d10debdb chore(deps): update dependency jsdom to v30 2026-07-30 08:36:37 +00:00
renovate[bot]
cd640da960 fix(deps): update mantine monorepo to v9.5.0 2026-07-30 08:36:26 +00:00
Jérémie Panzer
56ecb4a2f4 Merge pull request #2247 from Athou/renovate/org.jsoup-jsoup-1.x
fix(deps): update dependency org.jsoup:jsoup to v1.23.1
2026-07-30 07:23:53 +02:00
renovate[bot]
00161fd549 fix(deps): update dependency org.jsoup:jsoup to v1.23.1 2026-07-30 04:54:33 +00:00
renovate[bot]
a602ce17cd fix(deps): update dependency io.github.hakky54:ayza-for-apache5 to v10.0.6 2026-07-29 23:04:12 +00:00
renovate[bot]
672588d08b chore(deps): update node.js to v24.18.1 2026-07-29 21:06:29 +00:00
renovate[bot]
5fa2579275 chore(deps): update dependency com.github.eirslett:frontend-maven-plugin to v2.0.2 2026-07-29 20:12:39 +00:00
Jérémie Panzer
09bc317797 Merge pull request #2246 from Athou/renovate/org.mock-server-mockserver-junit-jupiter-7.x
chore(deps): update dependency org.mock-server:mockserver-junit-jupiter to v7.5.0
2026-07-29 22:12:10 +02:00
renovate[bot]
440c1ada50 chore(deps): update dependency org.mock-server:mockserver-junit-jupiter to v7.5.0 2026-07-29 18:38:26 +00:00
Athou
911a5ca099 reorder imports using google java format 2026-07-29 20:36:03 +02:00
Jérémie Panzer
65017f6b76 Merge pull request #2244 from Athou/renovate/quarkus.version
fix(deps): update quarkus.version to v3.38.0
2026-07-29 20:33:12 +02:00
Athou
64fb5ef3a2 fix warning 2026-07-29 18:24:14 +02:00
Jérémie Panzer
dda389a50f Merge pull request #2245 from Athou/renovate/react-querybuilder
fix(deps): update react-querybuilder to v8.21.0
2026-07-29 17:15:10 +02:00
renovate[bot]
419ad4fb6a fix(deps): update react-querybuilder to v8.21.0 2026-07-29 14:10:05 +00:00
Jérémie Panzer
ebae46f06b Merge pull request #2243 from Athou/renovate/docker-login-action-4.x
chore(deps): update docker/login-action action to v4.6.0
2026-07-29 16:09:58 +02:00
renovate[bot]
ac25accb31 fix(deps): update quarkus.version to v3.38.0 2026-07-29 14:09:50 +00:00
Jérémie Panzer
3c7eb90e50 Merge pull request #2242 from Athou/renovate/com.diffplug.spotless-spotless-maven-plugin-3.x
chore(deps): update dependency com.diffplug.spotless:spotless-maven-plugin to v3.9.0
2026-07-29 16:09:03 +02:00
renovate[bot]
4b3973f3fa chore(deps): update docker/login-action action to v4.6.0 2026-07-29 12:34:35 +00:00
renovate[bot]
6ddbe40c3c chore(deps): update dependency com.diffplug.spotless:spotless-maven-plugin to v3.9.0 2026-07-29 12:34:30 +00:00
Jérémie Panzer
d5164750e4 Merge pull request #2241 from Athou/renovate/linguijs-monorepo
fix(deps): update linguijs monorepo to v6.6.0
2026-07-27 17:40:01 +02:00
renovate[bot]
822fbd8add fix(deps): update linguijs monorepo to v6.6.0 2026-07-27 14:46:27 +00:00
Jérémie Panzer
3a341d0707 Merge pull request #2240 from Athou/renovate/com.puppycrawl.tools-checkstyle-13.x
chore(deps): update dependency com.puppycrawl.tools:checkstyle to v13.9.0
2026-07-27 07:42:59 +02:00
renovate[bot]
23884fcbda chore(deps): update dependency com.puppycrawl.tools:checkstyle to v13.9.0 2026-07-27 05:15:46 +00:00
renovate[bot]
3b16674f98 chore(deps): lock file maintenance 2026-07-27 00:51:21 +00:00
renovate[bot]
d5eb3e1bb1 chore(deps): update dependency vite-plugin-checker to v0.14.5 2026-07-25 13:00:37 +00:00
renovate[bot]
8d47b38fd4 chore(deps): update dependency @vitejs/plugin-react to v6.0.4 2026-07-25 05:45:24 +00:00
renovate[bot]
04fb3282fa fix(deps): update react monorepo to v19.2.8 2026-07-25 00:34:50 +00:00
renovate[bot]
bcce130b82 chore(deps): update docker/login-action action to v4.5.1 2026-07-24 20:05:24 +00:00
renovate[bot]
e5d336f6ba fix(deps): update mantine monorepo to v9.4.2 2026-07-24 11:08:55 +00:00
renovate[bot]
2d741f6e1e chore(deps): update dependency @biomejs/biome to v2.5.5 2026-07-24 10:03:13 +00:00
Jérémie Panzer
2968dff118 Merge pull request #2237 from Athou/renovate/major-testing-library-monorepo
chore(deps): update dependency @testing-library/jest-dom to v7
2026-07-23 22:25:02 +02:00
renovate[bot]
0c244ec154 chore(deps): update dependency @testing-library/jest-dom to v7 2026-07-23 19:50:05 +00:00
Jérémie Panzer
34cd337992 Merge pull request #2235 from Athou/renovate/monaco-editor-0.x
fix(deps): update dependency monaco-editor to v0.56.0
2026-07-23 21:49:33 +02:00
Jérémie Panzer
1703cb7b93 Merge pull request #2236 from Athou/renovate/docker-login-action-4.x
chore(deps): update docker/login-action action to v4.5.0
2026-07-23 21:00:06 +02:00
Athou
dc89faa4a1 adapt to new paths 2026-07-23 20:58:07 +02:00
renovate[bot]
3eccfe8ccc chore(deps): update docker/login-action action to v4.5.0 2026-07-23 17:29:45 +00:00
renovate[bot]
6e34f6831c fix(deps): update dependency monaco-editor to v0.56.0 2026-07-23 14:01:52 +00:00
renovate[bot]
b7ebcd6a23 fix(deps): update quarkus.version to v3.37.4 2026-07-23 10:00:31 +00:00
Jérémie Panzer
8b7efe056d Merge pull request #2234 from Athou/renovate/fontsource-monorepo
fix(deps): update dependency @fontsource/open-sans to v5.3.0
2026-07-22 08:33:33 +02:00
renovate[bot]
87cb392516 fix(deps): update dependency @fontsource/open-sans to v5.3.0 2026-07-22 05:25:49 +00:00
Jérémie Panzer
aa11cb48f2 Merge pull request #2233 from Athou/renovate/querydsl.version
fix(deps): update querydsl.version to v7.5
2026-07-21 23:31:17 +02:00
renovate[bot]
36a29a393c fix(deps): update querydsl.version to v7.5 2026-07-21 21:08:45 +00:00
renovate[bot]
99f1b45866 chore(deps): update actions/checkout action to v7.0.1 2026-07-21 02:00:56 +00:00
renovate[bot]
9e8d529af3 chore(deps): lock file maintenance 2026-07-20 03:58:17 +00:00
renovate[bot]
bb80641b40 chore(deps): update dependency vite to v8.1.5 2026-07-19 10:03:19 +00:00
renovate[bot]
a2ed16c6fd chore(deps): update dependency @biomejs/biome to v2.5.4 2026-07-18 04:35:49 +00:00
renovate[bot]
4f10f57837 fix(deps): update quarkus.version to v3.37.3 2026-07-15 21:27:37 +00:00
Jérémie Panzer
28f40cd6fe Merge pull request #2230 from Athou/renovate/graalvm-setup-graalvm-1.6.x
chore(deps): update graalvm/setup-graalvm action to v1.6.3
2026-07-14 22:21:04 +02:00
renovate[bot]
89a84a0c83 chore(deps): update graalvm/setup-graalvm action to v1.6.3 2026-07-14 10:01:24 +00:00
Jérémie Panzer
ebcda50a34 Merge pull request #2229 from Athou/renovate/actions-setup-node-7.x
chore(deps): update actions/setup-node action to v7
2026-07-14 09:09:34 +02:00
renovate[bot]
8640e62b77 chore(deps): update actions/setup-node action to v7 2026-07-14 06:21:50 +00:00
Jérémie Panzer
d0418eea89 Merge pull request #2227 from Athou/renovate/actions-setup-node-6.x
chore(deps): update actions/setup-node action to v6.5.0
2026-07-14 08:20:45 +02:00
Jérémie Panzer
41ba067daf Merge pull request #2228 from Athou/renovate/debian-13.x
chore(deps): update debian docker tag to v13.6
2026-07-14 08:19:52 +02:00
renovate[bot]
53346997b6 chore(deps): update debian docker tag to v13.6 2026-07-14 05:14:26 +00:00
renovate[bot]
87a632761e chore(deps): update actions/setup-node action to v6.5.0 2026-07-14 05:14:22 +00:00
renovate[bot]
998ebc43a3 chore(deps): update dependency npm to v12.0.1 2026-07-13 19:32:59 +00:00
renovate[bot]
945e312c41 chore(deps): update dependency vite to v8.1.4 2026-07-12 07:51:07 +00:00
Jérémie Panzer
963a562100 Merge pull request #2224 from Athou/renovate/typescript-7.x
chore(deps): update dependency typescript to v7
2026-07-12 09:49:47 +02:00
Athou
4be961b68b temporary disable checker plugin until TypeScript 7 exposes a stable api 2026-07-12 08:59:24 +02:00
Jérémie Panzer
02a9140c13 Merge pull request #2226 from Athou/renovate/com.puppycrawl.tools-checkstyle-13.x
chore(deps): update dependency com.puppycrawl.tools:checkstyle to v13.8.0
2026-07-12 08:52:40 +02:00
renovate[bot]
5ea60ce6d6 chore(deps): update dependency com.puppycrawl.tools:checkstyle to v13.8.0 2026-07-12 06:03:35 +00:00
Jérémie Panzer
e9e7be0fc6 Merge pull request #2225 from Athou/renovate/npm-12.x
chore(deps): update dependency npm to v12
2026-07-12 04:39:00 +02:00
renovate[bot]
60c30f2683 chore(deps): update dependency npm to v12 2026-07-11 23:25:34 +00:00
renovate[bot]
a17e69d37d chore(deps): update dependency typescript to v7 2026-07-11 17:37:46 +00:00
renovate[bot]
157f75d33e chore(deps): update dependency @biomejs/biome to v2.5.3 2026-07-11 10:52:37 +00:00
Athou
30a14c73ff specify that docker/podman can be used if graalvm is not found 2026-07-11 09:09:27 +02:00
Athou
27cece3afb release 7.2.0 2026-07-10 10:47:30 +02:00
Jérémie Panzer
8124ecb51f Merge pull request #2222 from Athou/renovate/linguijs-monorepo
fix(deps): update linguijs monorepo to v6.5.0
2026-07-10 08:19:14 +02:00
renovate[bot]
e67c4c8670 fix(deps): update linguijs monorepo to v6.5.0 2026-07-09 16:48:53 +00:00
renovate[bot]
fcc6798d63 fix(deps): update dependency style-to-object to v2.0.2 2026-07-09 16:48:41 +00:00
renovate[bot]
d313ebfc69 chore(deps): update dependency vitest to v4.1.10 2026-07-09 08:48:42 +00:00
renovate[bot]
6edb8f00f6 fix(deps): update quarkus.version to v3.37.2 2026-07-08 20:59:14 +00:00
renovate[bot]
98a261d457 fix(deps): update dependency style-to-object to v2.0.1 2026-07-07 21:44:59 +00:00
renovate[bot]
e97a69f475 chore(deps): update graalvm/setup-graalvm action to v1.6.2 2026-07-07 18:59:06 +00:00
Jérémie Panzer
e9dc284b26 Merge pull request #2221 from Athou/renovate/graalvm-setup-graalvm-1.6.x
chore(deps): update graalvm/setup-graalvm action to v1.6.1
2026-07-07 09:24:17 +02:00
renovate[bot]
856c52c64b chore(deps): update graalvm/setup-graalvm action to v1.6.1 2026-07-06 23:03:42 +00:00
renovate[bot]
386a4a32ef chore(deps): lock file maintenance 2026-07-06 01:33:25 +00:00
renovate[bot]
dbdb40ff01 chore(deps): update dependency vite to v8.1.3 (#2220)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-07-05 12:54:36 +00:00
Athou
1bd9b71215 use google java formatter to avoid downloading eclipse during build 2026-07-05 11:14:17 +02:00
Athou
f4dc279ec9 lombok is required at runtime for sneakyThrow 2026-07-05 09:02:57 +02:00
Athou
ca8438623d prevent access to ULA and CGNAT addresses 2026-07-05 08:48:02 +02:00
Jérémie Panzer
b81aac71f5 Merge pull request #2218 from Athou/renovate/biomejs-biome-2.5.x
chore(deps): update dependency @biomejs/biome to v2.5.2
2026-07-05 08:07:39 +02:00
Jérémie Panzer
a4e0d28fa2 Merge pull request #2219 from Athou/renovate/org.mock-server-mockserver-junit-jupiter-7.x
chore(deps): update dependency org.mock-server:mockserver-junit-jupiter to v7.4.0
2026-07-05 08:07:05 +02:00
renovate[bot]
56d4e4bbb1 chore(deps): update dependency org.mock-server:mockserver-junit-jupiter to v7.4.0 2026-07-04 20:37:01 +00:00
renovate[bot]
af1d10529b chore(deps): update dependency @biomejs/biome to v2.5.2 2026-07-04 16:40:46 +00:00
Athou
a5f84a3f6d search now also works for starred entries (#2217) 2026-07-04 17:57:08 +02:00
renovate[bot]
69dfbc81cc chore(deps): update dependency vite to v8.1.2 2026-07-04 01:29:31 +00:00
Jérémie Panzer
34408ccdb0 Merge pull request #2215 from Athou/renovate/react-icons-5.x
fix(deps): update dependency react-icons to v5.7.0
2026-07-04 03:28:52 +02:00
renovate[bot]
b0522a6e5d fix(deps): update dependency react-icons to v5.7.0 2026-07-03 20:43:38 +00:00
renovate[bot]
2a559a07c0 chore(deps): update dependency org.apache.maven.plugins:maven-help-plugin to v3.5.2 2026-07-03 20:43:16 +00:00
Athou
bdf2a6a915 the Pocket service has been discontinued 2026-07-03 22:40:38 +02:00
Jérémie Panzer
e814f75872 Merge pull request #2216 from Athou/renovate/graalvm-setup-graalvm-1.x
chore(deps): update graalvm/setup-graalvm action to v1.6.0
2026-07-03 20:16:57 +02:00
renovate[bot]
c0e0791854 chore(deps): update graalvm/setup-graalvm action to v1.6.0 2026-07-03 16:40:35 +00:00
renovate[bot]
17dbdb66bf chore(deps): update dependency vite to v8.1.1 2026-07-03 15:25:47 +00:00
Jérémie Panzer
6e3e9add36 Merge pull request #2214 from Athou/renovate/docker-login-action-4.x
chore(deps): update docker/login-action action to v4.4.0
2026-07-03 17:24:52 +02:00
renovate[bot]
5b25011853 chore(deps): update docker/login-action action to v4.4.0 2026-07-03 14:46:14 +00:00
Jérémie Panzer
804b24b2d6 Merge pull request #2213 from Athou/renovate/npm-11.x
chore(deps): update dependency npm to v11.18.0
2026-07-03 07:19:00 +02:00
renovate[bot]
de98b0f7c2 fix(deps): update dependency react-router-dom to v7.18.1 2026-07-02 23:52:17 +00:00
renovate[bot]
709de70fa9 chore(deps): update dependency npm to v11.18.0 2026-07-02 18:37:34 +00:00
renovate[bot]
1b7bc11f9d chore(deps): update ibm-semeru-runtimes:open-jdk-25.0.3.0-jre docker digest to 43ec947 2026-07-02 14:59:22 +00:00
Jérémie Panzer
bbcaacf3dd Merge pull request #2212 from Athou/renovate/docker-setup-buildx-action-4.x
chore(deps): update docker/setup-buildx-action action to v4.2.0
2026-07-02 16:58:33 +02:00
renovate[bot]
e816b1262c chore(deps): update docker/setup-buildx-action action to v4.2.0 2026-07-02 11:32:24 +00:00
Jérémie Panzer
fc019333dc Merge pull request #2211 from Athou/renovate/docker-login-action-4.x
chore(deps): update docker/login-action action to v4.3.0
2026-07-02 13:31:37 +02:00
renovate[bot]
56b0ddbc34 chore(deps): update docker/login-action action to v4.3.0 2026-07-02 09:08:11 +00:00
renovate[bot]
bb74d27d52 fix(deps): update quarkus.version to v3.37.1 2026-07-02 05:24:05 +00:00
Jérémie Panzer
7b1d19ca71 Merge pull request #2210 from Athou/renovate/docker-setup-qemu-action-4.x
chore(deps): update docker/setup-qemu-action action to v4.2.0
2026-07-02 07:23:33 +02:00
Jérémie Panzer
af961678bd Merge pull request #2209 from Athou/renovate/docker-build-push-action-7.x
chore(deps): update docker/build-push-action action to v7.3.0
2026-07-02 07:23:24 +02:00
Jérémie Panzer
1579242644 Merge pull request #2208 from Athou/renovate/org.mock-server-mockserver-junit-jupiter-7.x
chore(deps): update dependency org.mock-server:mockserver-junit-jupiter to v7.3.0
2026-07-02 07:23:18 +02:00
renovate[bot]
2a45f5c596 chore(deps): update docker/setup-qemu-action action to v4.2.0 2026-07-02 01:00:10 +00:00
renovate[bot]
c4560c49b0 chore(deps): update docker/build-push-action action to v7.3.0 2026-07-02 01:00:05 +00:00
Athou
2b7f75d9ef fix tests 2026-07-02 02:56:08 +02:00
renovate[bot]
5f68bcbd46 chore(deps): update dependency org.mock-server:mockserver-junit-jupiter to v7.3.0 2026-07-01 23:54:29 +00:00
renovate[bot]
c93c072259 fix(deps): update mantine monorepo to v9.4.1 2026-07-01 23:54:20 +00:00
Jérémie Panzer
516344a993 Merge pull request #2206 from Athou/renovate/com.diffplug.spotless-spotless-maven-plugin-3.x
chore(deps): update dependency com.diffplug.spotless:spotless-maven-plugin to v3.8.0
2026-06-30 08:15:35 +02:00
renovate[bot]
4d42fe5a0b chore(deps): update dependency com.diffplug.spotless:spotless-maven-plugin to v3.8.0 2026-06-30 05:11:59 +00:00
renovate[bot]
47bf132fff fix(deps): update dependency org.apache.httpcomponents.client5:httpclient5 to v5.6.2 2026-06-29 23:55:24 +00:00
renovate[bot]
04a9d48505 chore(deps): update dependency io.quarkiverse.playwright:quarkus-playwright to v2.3.7 2026-06-29 19:44:00 +00:00
renovate[bot]
3716ddcf15 chore(deps): lock file maintenance 2026-06-29 03:37:40 +00:00
Jérémie Panzer
6c3ab40cb6 Merge pull request #2205 from Athou/renovate/com.puppycrawl.tools-checkstyle-13.x
chore(deps): update dependency com.puppycrawl.tools:checkstyle to v13.7.0
2026-06-29 05:35:54 +02:00
renovate[bot]
b7270974e5 chore(deps): update dependency com.puppycrawl.tools:checkstyle to v13.7.0 2026-06-28 18:05:25 +00:00
renovate[bot]
9bfc53e77a fix(deps): update react-querybuilder to v8.20.2 2026-06-28 18:05:20 +00:00
renovate[bot]
f34fac8d17 chore(deps): update dependency @vitejs/plugin-react to v6.0.3 2026-06-26 13:36:32 +00:00
Jérémie Panzer
555c11649e Merge pull request #2204 from Athou/renovate/vite-8.x
chore(deps): update dependency vite to v8.1.0
2026-06-26 15:35:39 +02:00
Jérémie Panzer
c308c5d606 Merge pull request #2182 from Athou/renovate/biomejs-biome-2.x
chore(deps): update dependency @biomejs/biome to v2.5.1
2026-06-26 15:35:34 +02:00
Athou
54e9615994 add svg titles 2026-06-26 14:10:54 +02:00
renovate[bot]
b0b3b323fd chore(deps): update dependency vite to v8.1.0 2026-06-26 12:01:42 +00:00
renovate[bot]
f740a0b8ba chore(deps): update dependency @biomejs/biome to v2.5.1 2026-06-26 12:01:31 +00:00
renovate[bot]
e154675e72 fix(deps): update dependency axios to v1.18.1 2026-06-25 18:30:55 +00:00
Jérémie Panzer
2b3d3261de Merge pull request #2203 from Athou/renovate/mantine-monorepo
fix(deps): update mantine monorepo to v9.4.0
2026-06-25 20:30:14 +02:00
renovate[bot]
fab525ca56 fix(deps): update mantine monorepo to v9.4.0 2026-06-25 17:09:08 +00:00
Jérémie Panzer
1c273d1c1a Merge pull request #2201 from Athou/renovate/quarkus.version
fix(deps): update quarkus.version to v3.37.0
2026-06-24 19:04:03 +02:00
renovate[bot]
90d684367c fix(deps): update quarkus.version to v3.37.0 2026-06-24 15:22:44 +00:00
renovate[bot]
1ffc544ab0 chore(deps): update debian:13.5 docker digest to d07d1b5 2026-06-24 07:28:54 +00:00
Jérémie Panzer
cde0cceee1 Merge pull request #2200 from Athou/renovate/node-24.x
chore(deps): update node.js to v24.18.0
2026-06-24 09:28:15 +02:00
renovate[bot]
1604fbc55c chore(deps): update node.js to v24.18.0 2026-06-24 00:45:25 +00:00
Jérémie Panzer
6f586e8866 Merge pull request #2199 from Athou/renovate/org.mock-server-mockserver-junit-jupiter-7.x
chore(deps): update dependency org.mock-server:mockserver-junit-jupiter to v7.2.0
2026-06-23 09:14:52 +02:00
renovate[bot]
c53455ad61 chore(deps): update dependency org.mock-server:mockserver-junit-jupiter to v7.2.0 2026-06-22 22:13:00 +00:00
renovate[bot]
77b3c609f3 chore(deps): lock file maintenance 2026-06-22 05:10:43 +00:00
Jérémie Panzer
3b84598d99 Merge pull request #2197 from Athou/renovate/react-draggable-4.x
fix(deps): update dependency react-draggable to v4.7.0
2026-06-22 07:09:06 +02:00
renovate[bot]
6f536c0981 fix(deps): update dependency react-draggable to v4.7.0 2026-06-21 21:36:40 +00:00
renovate[bot]
1f881ea252 fix(deps): update react-querybuilder to v8.20.1 2026-06-21 21:36:29 +00:00
Jérémie Panzer
b14df1b3cb Merge pull request #2196 from Athou/renovate/react-querybuilder
fix(deps): update react-querybuilder to v8.20.0
2026-06-21 15:23:57 +02:00
renovate[bot]
e13763baa3 fix(deps): update react-querybuilder to v8.20.0 2026-06-21 09:52:35 +00:00
Jérémie Panzer
502ef67a71 Merge pull request #2192 from Athou/renovate/vite-plugin-checker-0.14.x
chore(deps): update dependency vite-plugin-checker to v0.14.4
2026-06-20 21:21:29 +02:00
renovate[bot]
05cab626df chore(deps): update dependency vite-plugin-checker to v0.14.4 2026-06-20 17:53:07 +00:00
renovate[bot]
c7d54af7ad fix(deps): update mantine monorepo to v9.3.2 2026-06-19 22:03:44 +00:00
Jérémie Panzer
ad195fcd80 Merge pull request #2194 from Athou/renovate/react-router-monorepo
fix(deps): update react-router monorepo to v7.18.0
2026-06-20 00:02:36 +02:00
renovate[bot]
b87c68d598 fix(deps): update react-router monorepo to v7.18.0 2026-06-19 19:03:39 +00:00
Jérémie Panzer
33af37ed2e Merge pull request #2191 from Athou/renovate/linguijs-monorepo
fix(deps): update linguijs monorepo to v6.4.0
2026-06-19 12:16:44 +02:00
renovate[bot]
c4113fc92b fix(deps): update linguijs monorepo to v6.4.0 2026-06-19 09:49:58 +00:00
renovate[bot]
ed40025d26 fix(deps): update quarkus.version to v3.36.3 2026-06-19 03:23:19 +00:00
Jérémie Panzer
752008a551 Merge pull request #2190 from Athou/renovate/actions-checkout-7.x
chore(deps): update actions/checkout action to v7
2026-06-19 05:22:13 +02:00
renovate[bot]
a8bf970dca chore(deps): update actions/checkout action to v7 2026-06-18 20:43:45 +00:00
renovate[bot]
5b94bcdfdd chore(deps): update vitest monorepo to v4.1.9 2026-06-18 09:31:04 +00:00
Jérémie Panzer
a66a0e9485 Merge pull request #2187 from Athou/renovate/graalvm-setup-graalvm-1.5.x
chore(deps): update graalvm/setup-graalvm action to v1.5.6
2026-06-18 11:26:32 +02:00
renovate[bot]
80755e15b8 chore(deps): update graalvm/setup-graalvm action to v1.5.6 2026-06-18 06:49:13 +00:00
Jérémie Panzer
8cede0c6e0 Merge pull request #2188 from Athou/renovate/axios-1.x
fix(deps): update dependency axios to v1.18.0
2026-06-18 08:45:44 +02:00
Jérémie Panzer
9556f0f7d2 Merge pull request #2189 from Athou/renovate/node-24.x
chore(deps): update node.js to v24.17.0
2026-06-18 08:45:36 +02:00
renovate[bot]
1b80f3060c chore(deps): update node.js to v24.17.0 2026-06-18 05:41:34 +00:00
renovate[bot]
00811f0be3 fix(deps): update dependency axios to v1.18.0 2026-06-17 22:02:57 +00:00
Jérémie Panzer
0fdfc2c59c Merge pull request #2186 from Athou/renovate/style-to-object-2.x
fix(deps): update dependency style-to-object to v2
2026-06-17 17:46:31 +02:00
renovate[bot]
8d25562a76 fix(deps): update dependency style-to-object to v2 2026-06-17 14:14:50 +00:00
Jérémie Panzer
1d0d9d4be6 Merge pull request #2185 from Athou/renovate/com.diffplug.spotless-spotless-maven-plugin-3.x
chore(deps): update dependency com.diffplug.spotless:spotless-maven-plugin to v3.7.0
2026-06-16 11:46:39 +02:00
renovate[bot]
9ed4559625 chore(deps): update dependency com.diffplug.spotless:spotless-maven-plugin to v3.7.0 2026-06-16 09:09:09 +00:00
renovate[bot]
2a53e8f15d chore(deps): update graalvm/setup-graalvm action to v1.5.5 2026-06-16 03:56:30 +00:00
Jérémie Panzer
15fbd18f31 Merge pull request #2184 from Athou/renovate/querydsl.version
fix(deps): update querydsl.version to v7.4.0
2026-06-16 05:55:32 +02:00
renovate[bot]
2c248a7ca1 fix(deps): update querydsl.version to v7.4.0 2026-06-15 21:52:53 +00:00
Jérémie Panzer
94d8fdb4ab Merge pull request #2183 from Athou/renovate/org.mock-server-mockserver-junit-jupiter-7.x
chore(deps): update dependency org.mock-server:mockserver-junit-jupiter to v7.1.0
2026-06-15 23:45:05 +02:00
renovate[bot]
3596439ed4 chore(deps): update dependency org.mock-server:mockserver-junit-jupiter to v7.1.0 2026-06-15 20:48:14 +00:00
Jérémie Panzer
bc732a52ce Merge pull request #2179 from Athou/renovate/npm-11.x
chore(deps): update dependency npm to v11.17.0
2026-06-15 13:21:46 +02:00
renovate[bot]
ef096899a2 chore(deps): update dependency npm to v11.17.0 2026-06-15 09:48:49 +00:00
Jérémie Panzer
bf4bcf740e Merge pull request #2180 from Athou/renovate/com.puppycrawl.tools-checkstyle-13.x
chore(deps): update dependency com.puppycrawl.tools:checkstyle to v13.6.0
2026-06-15 11:39:11 +02:00
renovate[bot]
679281ac26 chore(deps): update dependency com.puppycrawl.tools:checkstyle to v13.6.0 2026-06-15 06:12:58 +00:00
renovate[bot]
bde3d1408b fix(deps): update react-querybuilder to v8.19.1 2026-06-14 05:09:50 +00:00
Jérémie Panzer
3621a96d3f Merge pull request #2178 from Athou/renovate/linguijs-monorepo
fix(deps): update linguijs monorepo to v6.3.0
2026-06-13 19:01:49 +02:00
renovate[bot]
6583ad114f fix(deps): update linguijs monorepo to v6.3.0 2026-06-13 15:48:28 +00:00
renovate[bot]
f4e42165bf fix(deps): update dependency dev.cel:cel to v0.13.1 2026-06-13 12:21:08 +00:00
Athou
00d7be735a static random fields should not be used with graalvm as they are seeded at compile time and thus not random anymore 2026-06-13 12:03:50 +02:00
Athou
1388fba8e4 apply xml cleaning to opml files 2026-06-13 11:32:57 +02:00
Athou
c43644861f use a secure algorithm to generate image urls so that only server-side generated urls can be used 2026-06-13 11:21:16 +02:00
renovate[bot]
831ca599b8 chore(deps): update dependency com.github.eirslett:frontend-maven-plugin to v2.0.1 2026-06-12 16:36:09 +00:00
Athou
43fbd03292 remove husky and lint-staged 2026-06-12 10:12:47 +02:00
Athou
1efd04f6c5 fix wrapping of long titles 2026-06-12 10:10:02 +02:00
Jérémie Panzer
e89ccfd74b Merge pull request #2177 from Athou/renovate/patch-protobuf-monorepo
fix(deps): update protobuf monorepo to v4.35.1
2026-06-12 09:53:06 +02:00
renovate[bot]
622486160c fix(deps): update protobuf monorepo to v4.35.1 2026-06-12 05:26:54 +00:00
renovate[bot]
6d172cae9e fix(deps): update quarkus.version to v3.36.2 2026-06-12 04:36:06 +00:00
renovate[bot]
91b60fb147 fix(deps): update mantine monorepo to v9.3.1 2026-06-12 01:54:16 +00:00
renovate[bot]
3f9b7f48d5 chore(deps): update dependency io.quarkiverse.playwright:quarkus-playwright to v2.3.5 2026-06-11 19:27:17 +00:00
renovate[bot]
3599fdec65 chore(deps): update debian:13.5 docker digest to fe7312b 2026-06-11 16:02:59 +00:00
Jérémie Panzer
00e86974b3 Merge pull request #2176 from Athou/renovate/react-querybuilder
fix(deps): update react-querybuilder to v8.19.0
2026-06-11 05:37:46 +02:00
renovate[bot]
2aa897eb80 fix(deps): update react-querybuilder to v8.19.0 2026-06-11 03:11:56 +00:00
renovate[bot]
ce9706b860 chore(deps): update react monorepo to v19.2.17 2026-06-08 22:49:26 +00:00
Jérémie Panzer
e140dfe556 Merge pull request #2174 from Athou/renovate/react-router-monorepo
fix(deps): update react-router monorepo to v7.17.0
2026-06-08 08:01:57 +02:00
renovate[bot]
4a1b845ac2 chore(deps): lock file maintenance 2026-06-08 01:47:00 +00:00
renovate[bot]
573f8af57e fix(deps): update react-router monorepo to v7.17.0 2026-06-07 17:15:57 +00:00
Jérémie Panzer
33445c93e8 Merge pull request #2173 from Athou/renovate/org.mock-server-mockserver-junit-jupiter-7.x
chore(deps): update dependency org.mock-server:mockserver-junit-jupiter to v7
2026-06-07 08:44:16 +02:00
Athou
f7fcb659f7 fix build 2026-06-07 07:34:00 +02:00
renovate[bot]
b0aa723c2f chore(deps): update dependency org.mock-server:mockserver-junit-jupiter to v7 2026-06-06 17:58:01 +00:00
Jérémie Panzer
48dca41738 Merge pull request #2172 from Athou/renovate/axios-1.x
fix(deps): update dependency axios to v1.17.0
2026-06-06 15:55:32 +02:00
renovate[bot]
873d6f487f fix(deps): update dependency axios to v1.17.0 2026-06-06 09:44:37 +00:00
Jérémie Panzer
c8d73b129e Merge pull request #2156 from Athou/renovate/querydsl.version
fix(deps): update querydsl.version to v7.3.0
2026-06-06 06:27:00 +02:00
renovate[bot]
c63e9e1cd2 fix(deps): update querydsl.version to v7.3.0 2026-06-05 21:47:04 +00:00
Jérémie Panzer
def2ad84bb Merge pull request #2171 from Athou/renovate/mantine-monorepo
fix(deps): update mantine monorepo to v9.3.0
2026-06-05 15:24:57 +02:00
renovate[bot]
52510e9817 fix(deps): update mantine monorepo to v9.3.0 2026-06-05 10:33:10 +00:00
renovate[bot]
69a95488ce fix(deps): update react monorepo 2026-06-04 22:50:59 +00:00
Jérémie Panzer
636841f647 Merge pull request #2170 from Athou/renovate/linguijs-monorepo
fix(deps): update linguijs monorepo to v6.2.0
2026-06-04 18:13:54 +02:00
renovate[bot]
1ea521236c fix(deps): update linguijs monorepo to v6.2.0 2026-06-04 13:37:49 +00:00
renovate[bot]
6966efeda5 chore(deps): update dependency vite to v8.0.16 2026-06-04 10:09:32 +00:00
Jérémie Panzer
66ad0c3548 Merge pull request #2169 from Athou/renovate/react-querybuilder
fix(deps): update react-querybuilder to v8.18.0
2026-06-04 12:00:32 +02:00
renovate[bot]
e061ccbf79 chore(deps): update vitest monorepo to v4.1.8 2026-06-04 09:08:43 +00:00
renovate[bot]
30cc6a111d chore(deps): update dependency vite to v8.0.15 2026-06-04 04:46:24 +00:00
renovate[bot]
8416ce5124 fix(deps): update react-querybuilder to v8.18.0 2026-06-04 01:33:04 +00:00
renovate[bot]
0cacfe391b fix(deps): update quarkus.version to v3.36.1 (#2168)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-06-03 18:16:42 +00:00
renovate[bot]
c0eaab48cd chore(deps): update graalvm/setup-graalvm action to v1.5.4 2026-06-03 15:05:10 +00:00
renovate[bot]
c696bc3545 chore(deps): update dependency lint-staged to v17.0.7 2026-06-03 14:05:03 +00:00
renovate[bot]
72505954a9 chore(deps): update dependency lint-staged to v17.0.6 2026-06-02 18:11:51 +00:00
renovate[bot]
49159dba5c chore(deps): update actions/checkout action to v6.0.3 2026-06-02 17:34:01 +00:00
renovate[bot]
41e2d89abc chore(deps): update ibm-semeru-runtimes:open-jdk-25.0.3.0-jre docker digest to 9ff5b13 2026-06-02 16:48:04 +00:00
Jérémie Panzer
6e7de97d93 Merge pull request #2167 from Athou/renovate/react-draggable-4.x
fix(deps): update dependency react-draggable to v4.6.0
2026-06-02 05:57:46 +02:00
renovate[bot]
2f20e6b498 fix(deps): update dependency react-draggable to v4.6.0 2026-06-01 20:10:53 +00:00
Jérémie Panzer
ecf9158fd7 Merge pull request #2166 from Athou/renovate/react-router-monorepo
fix(deps): update dependency react-router-dom to v7.16.0
2026-06-01 07:19:20 +02:00
renovate[bot]
dc7e7321f3 fix(deps): update dependency react-router-dom to v7.16.0 2026-05-31 21:24:56 +00:00
Jérémie Panzer
0f087ad2a0 Merge pull request #2165 from Athou/renovate/react-querybuilder
fix(deps): update react-querybuilder to v8.17.0
2026-05-31 08:06:48 +02:00
renovate[bot]
ff19a6e9eb fix(deps): update react-querybuilder to v8.17.0 2026-05-31 04:53:55 +00:00
renovate[bot]
8cec0c0779 fix(deps): update mantine monorepo to v9.2.2 2026-05-30 21:42:00 +00:00
Jérémie Panzer
314384f8e7 Merge pull request #2164 from Athou/renovate/npm-11.x
chore(deps): update dependency npm to v11.16.0
2026-05-30 23:40:36 +02:00
Jérémie Panzer
6c75ad95ad Merge pull request #2163 from Athou/renovate/com.puppycrawl.tools-checkstyle-13.x
chore(deps): update dependency com.puppycrawl.tools:checkstyle to v13.5.0
2026-05-30 23:40:02 +02:00
renovate[bot]
76e3b3caff chore(deps): update dependency npm to v11.16.0 2026-05-30 20:56:38 +00:00
renovate[bot]
c8f71480c9 chore(deps): update dependency com.puppycrawl.tools:checkstyle to v13.5.0 2026-05-30 20:56:33 +00:00
renovate[bot]
9172a0cf9c chore(deps): update dependency @biomejs/biome to v2.4.16 2026-05-30 18:07:43 +00:00
renovate[bot]
eb476c6023 fix(deps): update react-querybuilder to v8.16.2 2026-05-30 00:38:03 +00:00
Jérémie Panzer
da4f3bd38e Merge pull request #2162 from Athou/renovate/vite-plugin-checker-0.x
chore(deps): update dependency vite-plugin-checker to v0.14.1
2026-05-29 19:13:53 +02:00
renovate[bot]
c65d628a36 chore(deps): update dependency vite-plugin-checker to v0.14.1 2026-05-29 15:43:11 +00:00
renovate[bot]
589b8c3afc fix(deps): update dependency dayjs to v1.11.21 2026-05-29 05:49:39 +00:00
Jérémie Panzer
2684051da0 Merge pull request #2161 from Athou/renovate/org.apache.maven.plugins-maven-surefire-plugin-3.5.x
chore(deps): update dependency org.apache.maven.plugins:maven-surefire-plugin to v3.5.6
2026-05-28 13:07:25 +02:00
renovate[bot]
200db68d05 chore(deps): update dependency org.apache.maven.plugins:maven-surefire-plugin to v3.5.6 2026-05-28 02:37:33 +00:00
renovate[bot]
f6d8d32a01 chore(deps): update dependency org.apache.maven.plugins:maven-failsafe-plugin to v3.5.6 2026-05-27 22:55:28 +00:00
Jérémie Panzer
72d5af5bb0 Merge pull request #2160 from Athou/renovate/docker-setup-qemu-action-4.x
chore(deps): update docker/setup-qemu-action action to v4.1.0
2026-05-27 21:58:58 +02:00
Jérémie Panzer
aabbc54cbb Merge pull request #2159 from Athou/renovate/com.diffplug.spotless-spotless-maven-plugin-3.x
chore(deps): update dependency com.diffplug.spotless:spotless-maven-plugin to v3.6.0
2026-05-27 21:58:50 +02:00
renovate[bot]
09b523bf56 chore(deps): update docker/setup-qemu-action action to v4.1.0 2026-05-27 19:09:41 +00:00
renovate[bot]
5dc7f522bf chore(deps): update dependency com.diffplug.spotless:spotless-maven-plugin to v3.6.0 2026-05-27 16:16:17 +00:00
Jérémie Panzer
fd58a42824 Merge pull request #2158 from Athou/renovate/quarkus.version
fix(deps): update quarkus.version to v3.36.0
2026-05-27 12:58:43 +02:00
Jérémie Panzer
0a6d1c85ed Merge pull request #2157 from Athou/renovate/org.mock-server-mockserver-junit-jupiter-6.x
chore(deps): update dependency org.mock-server:mockserver-junit-jupiter to v6.1.0
2026-05-27 12:58:40 +02:00
renovate[bot]
13f84a260c fix(deps): update quarkus.version to v3.36.0 2026-05-27 09:38:52 +00:00
renovate[bot]
4132ad9a97 chore(deps): update dependency org.mock-server:mockserver-junit-jupiter to v6.1.0 2026-05-27 09:38:46 +00:00
Athou
1faba92ecc remove unused relationships 2026-05-27 07:28:19 +02:00
renovate[bot]
b93fc86663 fix(deps): update dependency io.dropwizard.metrics:metrics-json to v4.2.39 2026-05-26 00:28:53 +00:00
renovate[bot]
7123036e8d chore(deps): lock file maintenance 2026-05-25 02:01:46 +00:00
Jérémie Panzer
cce4ea4dc6 Merge pull request #2155 from Athou/renovate/linguijs-monorepo
fix(deps): update linguijs monorepo to v6.1.0
2026-05-25 01:49:13 +02:00
renovate[bot]
b8f7df1555 fix(deps): update linguijs monorepo to v6.1.0 2026-05-24 13:45:25 +00:00
renovate[bot]
ba8cc0477c chore(deps): update dependency vite to v8.0.14 2026-05-24 09:26:55 +00:00
Jérémie Panzer
010026bc88 Merge pull request #2154 from Athou/renovate/npm-11.x
chore(deps): update dependency npm to v11.15.0
2026-05-24 07:07:15 +02:00
renovate[bot]
a1ba34caf2 chore(deps): update dependency npm to v11.15.0 2026-05-23 20:45:10 +00:00
renovate[bot]
1214380bee chore(deps): update dependency vitest to v4.1.7 2026-05-23 12:43:21 +00:00
Athou
03eb09c68c limit the number of favicon retries 2026-05-23 11:17:59 +02:00
renovate[bot]
055d503862 chore(deps): update dependency @types/react to v19.2.15 2026-05-22 23:03:14 +00:00
Athou
5755ff762b Trie is thread-safe, no need to recreate one every time 2026-05-22 20:29:48 +02:00
Jérémie Panzer
88e24787e8 Merge pull request #2153 from Athou/renovate/docker-setup-buildx-action-4.x
chore(deps): update docker/setup-buildx-action action to v4.1.0
2026-05-22 20:25:02 +02:00
renovate[bot]
ed32d07ac4 chore(deps): update docker/setup-buildx-action action to v4.1.0 2026-05-22 18:04:22 +00:00
Jérémie Panzer
3a917fcebe Merge pull request #2152 from Athou/renovate/docker-login-action-4.x
chore(deps): update docker/login-action action to v4.2.0
2026-05-22 15:41:58 +02:00
renovate[bot]
3535068ca8 chore(deps): update docker/login-action action to v4.2.0 2026-05-22 13:03:48 +00:00
Jérémie Panzer
4c39d4b96b Merge pull request #2150 from Athou/renovate/docker-build-push-action-7.x
chore(deps): update docker/build-push-action action to v7.2.0
2026-05-21 21:27:31 +02:00
renovate[bot]
8e864c6793 chore(deps): update docker/build-push-action action to v7.2.0 2026-05-21 18:41:32 +00:00
Jérémie Panzer
aeffecced3 Merge pull request #2151 from Athou/renovate/node-24.x
chore(deps): update node.js to v24.16.0
2026-05-21 19:54:18 +02:00
renovate[bot]
4be42dc1e2 chore(deps): update node.js to v24.16.0 2026-05-21 17:03:21 +00:00
Jérémie Panzer
bdf6c62c29 Merge pull request #2149 from Athou/renovate/org.mock-server-mockserver-junit-jupiter-6.x
chore(deps): update dependency org.mock-server:mockserver-junit-jupiter to v6
2026-05-21 07:37:36 +02:00
Athou
a4592e5199 fix tests 2026-05-21 04:48:43 +02:00
renovate[bot]
a5268f082d chore(deps): update dependency org.mock-server:mockserver-junit-jupiter to v6 2026-05-20 19:50:45 +00:00
Jérémie Panzer
b556e72922 Merge pull request #2148 from Athou/renovate/patch-quarkus.version
fix(deps): update quarkus.version to v3.35.4
2026-05-20 21:50:23 +02:00
renovate[bot]
3602d2533a fix(deps): update quarkus.version to v3.35.4 2026-05-20 15:46:05 +00:00
Jérémie Panzer
681f2c766a Merge pull request #2147 from Athou/renovate/mindsers-changelog-reader-action-2.x
chore(deps): update mindsers/changelog-reader-action action to v2.4.0
2026-05-20 14:11:52 +02:00
renovate[bot]
6e0a136cd1 chore(deps): update mindsers/changelog-reader-action action to v2.4.0 2026-05-20 10:37:59 +00:00
Jérémie Panzer
9e9945a1cc Merge pull request #2146 from Athou/renovate/debian-13.5
chore(deps): update debian:13.5 docker digest to 4ae6766
2026-05-20 08:46:39 +02:00
renovate[bot]
3368cead8b chore(deps): update debian:13.5 docker digest to 4ae6766 2026-05-20 04:16:03 +00:00
Jérémie Panzer
a7b5126b4a Merge pull request #2145 from Athou/renovate/protobuf-monorepo
fix(deps): update dependency com.google.protobuf:protobuf-java to v4.35.0
2026-05-20 06:15:49 +02:00
Jérémie Panzer
a9ef1a03dc Merge pull request #2144 from Athou/renovate/debian-13.x
chore(deps): update debian docker tag to v13.5
2026-05-20 06:15:22 +02:00
Jérémie Panzer
bc0ec8dbfa Merge pull request #2143 from Athou/renovate/mindsers-changelog-reader-action-2.x
chore(deps): update mindsers/changelog-reader-action action to v2.3.0
2026-05-20 06:15:02 +02:00
renovate[bot]
7bef009922 fix(deps): update dependency com.google.protobuf:protobuf-java to v4.35.0 2026-05-20 01:03:49 +00:00
renovate[bot]
9a467bc27b chore(deps): update debian docker tag to v13.5 2026-05-20 01:03:45 +00:00
renovate[bot]
e3934c9403 chore(deps): update mindsers/changelog-reader-action action to v2.3.0 2026-05-19 22:42:24 +00:00
renovate[bot]
af337aa4d0 chore(deps): update dependency lint-staged to v17.0.5 2026-05-19 13:45:40 +00:00
Jérémie Panzer
313d3a01ec Merge pull request #2141 from Athou/renovate/reduxjs-toolkit-2.x
fix(deps): update dependency @reduxjs/toolkit to v2.12.0
2026-05-19 07:20:37 +02:00
Jérémie Panzer
feb9876cf5 Merge pull request #2142 from Athou/renovate/react-redux-9.x
fix(deps): update dependency react-redux to v9.3.0
2026-05-19 07:20:32 +02:00
renovate[bot]
9c3a5cb820 fix(deps): update dependency react-redux to v9.3.0 2026-05-18 19:12:38 +00:00
renovate[bot]
e219f781bf fix(deps): update dependency @reduxjs/toolkit to v2.12.0 2026-05-18 19:12:29 +00:00
renovate[bot]
21ecd6ae05 chore(deps): lock file maintenance 2026-05-18 00:37:57 +00:00
renovate[bot]
2449902c3d chore(deps): update dependency @vitejs/plugin-react to v6.0.2 2026-05-17 20:56:33 +00:00
renovate[bot]
c1a55037ba chore(deps): update dependency maven to v3.9.16 2026-05-17 19:48:01 +00:00
Jérémie Panzer
646a8122c0 Merge pull request #2140 from Athou/renovate/patch-react-router-monorepo
fix(deps): update dependency react-router-dom to v7.15.1
2026-05-17 21:47:37 +02:00
renovate[bot]
edc4e6c508 fix(deps): update dependency react-router-dom to v7.15.1 2026-05-17 18:40:58 +00:00
renovate[bot]
5ddeb7b156 fix(deps): update mantine monorepo to v9.2.1 2026-05-17 17:25:02 +00:00
renovate[bot]
306624e55f chore(deps): update dependency vite to v8.0.13 2026-05-17 12:41:35 +00:00
renovate[bot]
6a9ca65cbc fix(deps): update react-querybuilder to v8.16.1 2026-05-16 21:39:23 +00:00
renovate[bot]
7db0026a0c fix(deps): update dependency axios to v1.16.1 2026-05-16 16:37:50 +00:00
Jérémie Panzer
7358705248 Merge pull request #2137 from Athou/renovate/mantine-monorepo
fix(deps): update mantine monorepo to v9.2.0
2026-05-16 07:58:01 +02:00
Jérémie Panzer
0b9ee2eec9 Merge pull request #2139 from Athou/renovate/dev.cel-cel-0.x
fix(deps): update dependency dev.cel:cel to v0.13.0
2026-05-16 07:57:48 +02:00
renovate[bot]
42eaf7fc39 fix(deps): update dependency dev.cel:cel to v0.13.0 2026-05-16 01:25:48 +00:00
renovate[bot]
6783cac9b4 chore(deps): update dependency com.diffplug.spotless:spotless-maven-plugin to v3.5.1 2026-05-16 01:25:45 +00:00
renovate[bot]
628106ce88 fix(deps): update dependency tss-react to v4.9.21 2026-05-15 16:29:21 +00:00
Jérémie Panzer
1ce69b31a7 Merge pull request #2136 from Athou/renovate/yaml-2.x
chore(deps): update dependency yaml to v2.9.0
2026-05-15 08:01:15 +02:00
Jérémie Panzer
912ac11842 Merge pull request #2138 from Athou/renovate/com.diffplug.spotless-spotless-maven-plugin-3.x
chore(deps): update dependency com.diffplug.spotless:spotless-maven-plugin to v3.5.0
2026-05-15 07:57:38 +02:00
renovate[bot]
5f2fad560c chore(deps): update dependency yaml to v2.9.0 2026-05-14 21:28:25 +00:00
renovate[bot]
b300f364a7 chore(deps): update dependency com.diffplug.spotless:spotless-maven-plugin to v3.5.0 2026-05-14 21:28:13 +00:00
renovate[bot]
049ec41d13 fix(deps): update mantine monorepo to v9.2.0 2026-05-14 16:49:16 +00:00
renovate[bot]
f0d17bc84e chore(deps): update dependency vitest to v4.1.6 2026-05-14 16:49:07 +00:00
renovate[bot]
cc442d7409 chore(deps): update dependency vite to v8.0.12 2026-05-14 08:51:10 +00:00
renovate[bot]
80bac26f21 fix(deps): update quarkus.version to v3.35.3 2026-05-13 17:00:07 +00:00
renovate[bot]
015c39e6f4 chore(deps): update dependency lint-staged to v17.0.4 2026-05-12 21:11:12 +00:00
renovate[bot]
e0ec3a4ebd chore(deps): update dependency @biomejs/biome to v2.4.15 2026-05-12 17:27:19 +00:00
renovate[bot]
a022de5cc3 chore(deps): update dependency npm to v11.14.1 2026-05-11 20:50:59 +00:00
renovate[bot]
a7b5e1e18c chore(deps): update dependency lint-staged to v17.0.3 2026-05-11 17:57:10 +00:00
renovate[bot]
b8695df1c8 fix(deps): update dependency io.github.hakky54:ayza-for-apache5 to v10.0.5 2026-05-11 11:10:01 +00:00
renovate[bot]
5e4382d1d2 chore(deps): lock file maintenance 2026-05-11 01:26:50 +00:00
Athou
ce983f4906 fix flaky test 2026-05-10 21:19:35 +02:00
Athou
4a8be29616 add support for declared icons in feeds (#2048) 2026-05-10 21:05:33 +02:00
renovate[bot]
1622eb642a chore(deps): update dependency vite to v8.0.11 2026-05-10 10:37:18 +00:00
Jérémie Panzer
422d992484 Merge pull request #2135 from Athou/renovate/npm-11.x
chore(deps): update dependency npm to v11.14.0
2026-05-10 12:36:28 +02:00
renovate[bot]
1065af1233 chore(deps): update dependency npm to v11.14.0 2026-05-09 20:56:38 +00:00
renovate[bot]
dde39d83be fix(deps): update react monorepo to v19.2.6 2026-05-09 16:44:07 +00:00
Jérémie Panzer
94fe7617bf Merge pull request #2134 from Athou/renovate/lint-staged-17.x
chore(deps): update dependency lint-staged to v17
2026-05-09 17:08:52 +02:00
Jérémie Panzer
e781d85b7c Merge pull request #2133 from Athou/renovate/react-router-monorepo
fix(deps): update dependency react-router-dom to v7.15.0
2026-05-09 17:08:35 +02:00
renovate[bot]
c30c9ca380 chore(deps): update dependency lint-staged to v17 2026-05-09 13:42:20 +00:00
renovate[bot]
c395916af9 chore(deps): update debian:13.4 docker digest to e2d08da 2026-05-09 04:41:33 +00:00
renovate[bot]
1a4037e360 fix(deps): update dependency react-router-dom to v7.15.0 2026-05-08 16:51:27 +00:00
Athou
f207bfaddd format empty records and anonymous types as a single line 2026-05-08 17:56:26 +02:00
Jérémie Panzer
3dd298c0c8 Merge pull request #2132 from Athou/renovate/react-querybuilder
fix(deps): update react-querybuilder to v8.16.0 (minor)
2026-05-08 08:29:30 +02:00
renovate[bot]
8e2e4da7c3 fix(deps): update react-querybuilder to v8.16.0 2026-05-08 05:58:29 +00:00
renovate[bot]
418e3c109c chore(deps): update graalvm/setup-graalvm action to v1.5.3 2026-05-06 18:39:48 +00:00
Jérémie Panzer
cfda63a609 Merge pull request #2131 from Athou/renovate/axios-1.x
fix(deps): update dependency axios to v1.16.0
2026-05-06 07:22:28 +02:00
renovate[bot]
ba68276bfb fix(deps): update dependency axios to v1.16.0 2026-05-05 19:30:57 +00:00
renovate[bot]
97c700024a chore(deps): update dependency yaml to v2.8.4 2026-05-05 10:10:38 +00:00
renovate[bot]
d4f67d726c chore(deps): update dependency @biomejs/biome to v2.4.14 2026-05-04 20:37:34 +00:00
Jérémie Panzer
ea87fa3e5a Merge pull request #2130 from Athou/renovate/io.quarkiverse.playwright-quarkus-playwright-2.3.x
chore(deps): update dependency io.quarkiverse.playwright:quarkus-playwright to v2.3.4
2026-05-04 22:36:37 +02:00
renovate[bot]
d12d247b3e chore(deps): update dependency io.quarkiverse.playwright:quarkus-playwright to v2.3.4 2026-05-04 20:07:06 +00:00
renovate[bot]
c4a23915bd fix(deps): update quarkus.version to v3.35.2 2026-05-04 19:06:39 +00:00
Athou
8645c57d13 simplify settings thunks 2026-05-04 08:03:57 +02:00
Jérémie Panzer
b170e0bc17 Merge pull request #2129 from Athou/renovate/patch-linguijs-monorepo
fix(deps): update linguijs monorepo to v6.0.1 (patch)
2026-05-04 08:03:53 +02:00
renovate[bot]
4199f514f9 fix(deps): update linguijs monorepo to v6.0.1 2026-05-04 05:28:51 +00:00
renovate[bot]
c96efb3bb4 chore(deps): lock file maintenance 2026-05-04 00:57:15 +00:00
renovate[bot]
d5571e0196 chore(deps): update dependency jsdom to v29.1.1 2026-05-03 09:41:32 +00:00
Athou
9f7f87b4ae move handlers in Layout because they actually only apply to the reader pages 2026-05-02 15:04:33 +02:00
renovate[bot]
4b03fce85d chore(deps): update dependency com.puppycrawl.tools:checkstyle to v13.4.2 2026-05-02 06:12:23 +00:00
renovate[bot]
4b28d1c635 chore(deps): update ibm-semeru-runtimes docker tag to open-jdk-25.0.3.0-jre 2026-05-01 11:59:50 +00:00
Jérémie Panzer
a5e803177f Merge pull request #2128 from Athou/renovate/quarkus.version
fix(deps): update quarkus.version to v3.35.1 (minor)
2026-05-01 13:59:25 +02:00
renovate[bot]
9462f284a4 fix(deps): update quarkus.version to v3.35.1 2026-05-01 11:33:13 +00:00
renovate[bot]
4b0f6bd61b fix(deps): update mantine monorepo to v9.1.1 2026-04-30 21:05:02 +00:00
Jérémie Panzer
d6c85214ef Merge pull request #2127 from Athou/renovate/jsdom-29.x
chore(deps): update dependency jsdom to v29.1.0
2026-04-30 07:18:31 +02:00
renovate[bot]
de770cf801 chore(deps): update dependency jsdom to v29.1.0 2026-04-30 04:39:54 +00:00
renovate[bot]
dae0f740c2 chore(deps): update dependency com.puppycrawl.tools:checkstyle to v13.4.1 2026-04-27 17:36:06 +00:00
Athou
9452c3e74c remove warning 2026-04-27 18:01:02 +02:00
Athou
f826f1d543 create comparator only once 2026-04-27 18:01:02 +02:00
Athou
fd13c80e5a allow reuse of TLS connections 2026-04-27 17:52:40 +02:00
Athou
75871348d5 compile pattern once 2026-04-27 17:46:50 +02:00
renovate[bot]
0140e88595 chore(deps): lock file maintenance 2026-04-27 00:53:02 +00:00
renovate[bot]
e620b1254b chore(deps): update dependency @biomejs/biome to v2.4.13 2026-04-26 17:49:57 +00:00
Jérémie Panzer
77cfcf6c58 Merge pull request #2123 from Athou/renovate/major-linguijs-monorepo
fix(deps): update linguijs monorepo to v6 (major)
2026-04-26 16:07:22 +02:00
Athou
04e9df3d0a the format and the formatOptions fields have been removed 2026-04-26 15:43:42 +02:00
renovate[bot]
a953134089 chore(deps): update dependency vite to v8.0.10 2026-04-26 06:27:27 +00:00
Jérémie Panzer
88b9c0d783 Merge pull request #2125 from Athou/renovate/npm-11.x
chore(deps): update dependency npm to v11.13.0
2026-04-26 08:26:50 +02:00
renovate[bot]
ff7e0ba95b chore(deps): update dependency npm to v11.13.0 2026-04-25 20:53:09 +00:00
renovate[bot]
53dfbcaf00 fix(deps): update linguijs monorepo to v6 2026-04-25 13:00:15 +00:00
renovate[bot]
d8fca22c00 fix(deps): update dependency react-router-dom to v7.14.2 (#2122)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-04-25 05:15:30 +00:00
renovate[bot]
4fb5963bd9 fix(deps): update dependency axios to v1.15.2 2026-04-24 19:10:13 +00:00
Jérémie Panzer
862d81f446 Merge pull request #2121 from Athou/renovate/mantine-monorepo
fix(deps): update mantine monorepo to v9.1.0 (minor)
2026-04-24 21:09:22 +02:00
renovate[bot]
8ae7943b94 fix(deps): update mantine monorepo to v9.1.0 2026-04-24 17:36:15 +00:00
renovate[bot]
46e947d779 chore(deps): update dependency vitest to v4.1.5 2026-04-24 14:58:06 +00:00
renovate[bot]
7780d6020f chore(deps): update dependency vite to v8.0.9 2026-04-23 07:05:57 +00:00
renovate[bot]
e5803b46f2 fix(deps): update quarkus.version to v3.34.6 2026-04-22 22:04:58 +00:00
renovate[bot]
d776090298 fix(deps): update dependency axios to v1.15.1 2026-04-22 18:11:13 +00:00
renovate[bot]
f2f3111d49 chore(deps): update debian:13.4 docker digest to 35b8ff7 2026-04-22 06:50:35 +00:00
renovate[bot]
dff1b957cd fix(deps): update dependency org.projectlombok:lombok to v1.18.46 2026-04-22 01:21:16 +00:00
Athou
b1ec50c3cb increase timeout to prevent flaky tests 2026-04-20 11:06:03 +02:00
renovate[bot]
85aa188287 chore(deps): lock file maintenance 2026-04-20 08:11:06 +00:00
renovate[bot]
e7d6526da9 fix(deps): update dependency org.jsoup:jsoup to v1.22.2 2026-04-20 07:28:37 +00:00
Jérémie Panzer
d67c6fcc00 Merge pull request #2119 from Athou/renovate/actions-setup-node-6.x
chore(deps): update actions/setup-node action to v6.4.0
2026-04-20 09:25:22 +02:00
renovate[bot]
d9bf084300 chore(deps): update actions/setup-node action to v6.4.0 2026-04-20 06:58:42 +00:00
Athou
da3977b0e2 fix error message not correctly returned 2026-04-20 08:39:24 +02:00
renovate[bot]
7df930bccc chore(deps): update dependency typescript to v6.0.3 2026-04-20 00:42:50 +00:00
renovate[bot]
11f73a1a53 fix(deps): update dependency org.apache.httpcomponents.client5:httpclient5 to v5.6.1 2026-04-19 12:22:35 +00:00
Jérémie Panzer
2bbcd55e48 Merge pull request #2118 from Athou/renovate/react-querybuilder
fix(deps): update react-querybuilder to v8.15.0 (minor)
2026-04-19 14:21:37 +02:00
renovate[bot]
43890b8d5c fix(deps): update react-querybuilder to v8.15.0 2026-04-19 11:54:36 +00:00
Athou
b6b8e3741b group react-querybuilder and @react-querybuilder/mantine together 2026-04-19 13:53:45 +02:00
Jérémie Panzer
c39f00c336 Merge pull request #2114 from Athou/renovate/vite-plugin-checker-0.x
chore(deps): update dependency vite-plugin-checker to v0.13.0
2026-04-19 08:04:06 +02:00
renovate[bot]
e48eaacfef chore(deps): update dependency vite-plugin-checker to v0.13.0 2026-04-18 13:49:45 +00:00
renovate[bot]
6d97691388 chore(deps): update dependency @biomejs/biome to v2.4.12 2026-04-17 21:33:53 +00:00
renovate[bot]
d64cc996bc chore(deps): update dependency maven to v3.9.15 2026-04-17 14:05:43 +00:00
renovate[bot]
617d66c9b9 fix(deps): update quarkus.version to v3.34.5 2026-04-17 05:06:55 +00:00
Jérémie Panzer
0fc50d2105 Merge pull request #2113 from Athou/renovate/rolldown-plugin-babel-0.2.x
fix(deps): update dependency @rolldown/plugin-babel to v0.2.3
2026-04-17 07:06:29 +02:00
renovate[bot]
2bb9f28569 fix(deps): update dependency @rolldown/plugin-babel to v0.2.3 2026-04-17 01:09:52 +00:00
renovate[bot]
c1580b8359 fix(deps): update dependency react-router-dom to v7.14.1 2026-04-16 21:56:46 +00:00
Jérémie Panzer
dde235825d Merge pull request #2111 from Athou/renovate/patch-mantine-monorepo
fix(deps): update mantine monorepo to v9.0.2 (patch)
2026-04-16 19:07:20 +02:00
renovate[bot]
eac13b4025 fix(deps): update mantine monorepo to v9.0.2 2026-04-16 15:40:07 +00:00
Athou
59cc9c2706 add explicit dependency 2026-04-16 17:38:54 +02:00
Athou
40e20a0d33 use exact versions 2026-04-16 16:25:54 +02:00
Jérémie Panzer
a42679acaa Merge pull request #2112 from Athou/renovate/node-24.x
chore(deps): update node.js to v24.15.0
2026-04-16 13:28:55 +02:00
renovate[bot]
fd2e8fcdb8 chore(deps): update node.js to v24.15.0 2026-04-16 10:57:14 +00:00
Athou
ebd5a15152 cache npm dependencies during CI build 2026-04-15 09:22:04 +02:00
Athou
6cdd110304 release 7.1.0 2026-04-15 07:45:15 +02:00
Jérémie Panzer
3181cda2e0 Merge pull request #2110 from Athou/renovate/actions-upload-pages-artifact-5.x
chore(deps): update actions/upload-pages-artifact action to v5
2026-04-14 09:21:31 +02:00
renovate[bot]
2659c7fc02 chore(deps): update actions/upload-pages-artifact action to v5 2026-04-14 06:47:52 +00:00
renovate[bot]
5747ae3429 fix(deps): update dependency axios to ^1.15.0 2026-04-13 05:02:56 +00:00
renovate[bot]
8d60be0e3f chore(deps): lock file maintenance 2026-04-13 01:02:19 +00:00
renovate[bot]
7e3f801a5a chore(deps): update dependency @biomejs/biome to v2.4.11 2026-04-12 16:59:32 +00:00
renovate[bot]
687ef53c65 chore(deps): update dependency vitest to ^4.1.4 2026-04-12 08:58:19 +00:00
renovate[bot]
a1fe9e727e chore(deps): update dependency vite to ^8.0.8 2026-04-12 04:30:28 +00:00
renovate[bot]
6d625c88d3 fix(deps): update react monorepo to ^19.2.5 2026-04-11 20:26:25 +00:00
renovate[bot]
c314e2de6b chore(deps): update dependency vitest to ^4.1.3 2026-04-11 01:40:15 +00:00
renovate[bot]
bd08b95390 chore(deps): update actions/upload-artifact digest to 043fb46 2026-04-10 21:11:12 +00:00
renovate[bot]
aed0cca7e1 chore(deps): update dependency vite to ^8.0.7 2026-04-10 16:53:01 +00:00
renovate[bot]
7d7761fb8d chore(deps): update docker/build-push-action digest to bcafcac 2026-04-10 13:24:27 +00:00
Athou
6d2fb5acc2 refactor 2026-04-10 15:17:27 +02:00
Athou
ec35d846cf Merge branch 'perf/batch-guid-check-on-feed-refresh' of https://github.com/ingokegel/commafeed into ingokegel-perf/batch-guid-check-on-feed-refresh 2026-04-10 14:22:32 +02:00
Ingo Kegel
1d23907652 Use batched IN clause for GUID existence check during feed refresh
Instead of fetching all existing GUID hashes for a feed from the database only check the GUIDs present in the current feed XML using a SQL IN clause. GUIDs are partitioned into batches of 1000.

Also adds an integration test verifying that refreshing an up-to-date feed does not create duplicate entries.
2026-04-10 10:13:37 +02:00
renovate[bot]
efc6c10ace fix(deps): update quarkus.version to v3.34.3 2026-04-08 19:39:10 +00:00
renovate[bot]
47a8ad5244 chore(deps): update debian:13.4 docker digest to 3352c2e 2026-04-07 06:43:23 +00:00
Athou
5d879c4619 update all dependencies 2026-04-07 08:42:07 +02:00
Jérémie Panzer
6e0dd3d064 Merge pull request #2094 from Athou/renovate/typescript-6.x
chore(deps): update dependency typescript to v6
2026-04-07 03:23:40 +02:00
Athou
4657a403d0 adapt to typescript 6.0 api 2026-04-07 02:42:44 +02:00
Jérémie Panzer
bf09a07fe2 Merge pull request #2108 from Athou/renovate/org.passay-passay-2.x
fix(deps): update dependency org.passay:passay to v2
2026-04-07 02:28:34 +02:00
Jérémie Panzer
927802ca88 Merge pull request #2096 from Athou/renovate/com.puppycrawl.tools-checkstyle-13.x
chore(deps): update dependency com.puppycrawl.tools:checkstyle to v13.4.0
2026-04-07 02:13:55 +02:00
Athou
3d5bc9ef0e adapt to passay 2.0 api 2026-04-07 02:11:37 +02:00
Jérémie Panzer
706ad7e44d Merge pull request #2107 from Athou/renovate/react-router-monorepo
fix(deps): update dependency react-router-dom to ^7.14.0
2026-04-07 02:06:30 +02:00
Jérémie Panzer
88206f521b Merge pull request #2102 from Athou/renovate/io.github.git-commit-id-git-commit-id-maven-plugin-10.x
chore(deps): update dependency io.github.git-commit-id:git-commit-id-maven-plugin to v10
2026-04-06 20:27:07 +02:00
renovate[bot]
af786b4c11 fix(deps): update dependency org.passay:passay to v2 2026-04-06 18:26:35 +00:00
renovate[bot]
d4c749c997 fix(deps): update dependency react-router-dom to ^7.14.0 2026-04-06 18:26:28 +00:00
Jérémie Panzer
b5aa25cd0b Merge pull request #2093 from Athou/renovate/actions-deploy-pages-5.x
chore(deps): update actions/deploy-pages action to v5
2026-04-06 20:25:27 +02:00
Jérémie Panzer
ae49fb6dad Merge pull request #2092 from Athou/renovate/quarkus.version
fix(deps): update quarkus.version to v3.34.2 (minor)
2026-04-06 20:25:17 +02:00
Jérémie Panzer
3e24d17951 Merge pull request #2090 from Athou/renovate/npm-11.x
chore(deps): update dependency npm to v11.12.1
2026-04-06 20:25:06 +02:00
renovate[bot]
22030e6907 chore(deps): update dependency io.github.git-commit-id:git-commit-id-maven-plugin to v10 2026-04-03 13:24:55 +00:00
renovate[bot]
39fdcb9af3 chore(deps): update dependency @biomejs/biome to v2.4.10 2026-04-02 20:55:13 +00:00
renovate[bot]
866998f98b chore(deps): update docker/login-action digest to 4907a6d 2026-04-02 18:53:38 +00:00
renovate[bot]
0fa71f76e8 fix(deps): update quarkus.version to v3.34.2 2026-04-02 13:57:27 +00:00
renovate[bot]
317f655128 chore(deps): update graalvm/setup-graalvm digest to 60c2672 2026-04-02 09:27:39 +00:00
renovate[bot]
a871426f31 chore(deps): update dependency typescript to v6 2026-04-01 17:58:10 +00:00
renovate[bot]
2caf9ff38a chore(deps): update dependency com.puppycrawl.tools:checkstyle to v13.4.0 2026-04-01 17:57:52 +00:00
renovate[bot]
1de3a57d50 chore(deps): update graalvm/setup-graalvm digest to 2149f39 2026-03-31 14:12:33 +00:00
renovate[bot]
bed1355d63 fix(deps): update linguijs monorepo to ^5.9.4 (#2101)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-31 05:49:21 +00:00
renovate[bot]
189f9b4f26 fix(deps): update dependency axios to ^1.14.0 2026-03-30 20:50:54 +00:00
renovate[bot]
931b5a22e6 chore(deps): lock file maintenance 2026-03-30 05:50:15 +00:00
renovate[bot]
4c9e0a8b74 fix(deps): update dependency @react-querybuilder/mantine to ^8.14.3 (#2098)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-30 05:48:48 +00:00
renovate[bot]
589472314b chore(deps): update dependency npm to v11.12.1 2026-03-29 21:36:53 +00:00
renovate[bot]
f11657fdee fix(deps): update dependency react-querybuilder to ^8.14.3 2026-03-29 21:36:40 +00:00
renovate[bot]
e4ec081357 chore(deps): update dependency vitest to ^4.1.2 2026-03-29 16:49:20 +00:00
renovate[bot]
9e55527a2b chore(deps): update dependency vite to ^8.0.3 2026-03-29 09:18:01 +00:00
renovate[bot]
cca70ffcec chore(deps): update dependency @biomejs/biome to v2.4.9 2026-03-28 12:57:11 +00:00
renovate[bot]
2a6a717ef2 fix(deps): update dependency react-querybuilder to ^8.14.2 (#2095)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-28 04:57:16 +00:00
renovate[bot]
11043554c2 fix(deps): update dependency @react-querybuilder/mantine to ^8.14.2 2026-03-27 21:36:47 +00:00
renovate[bot]
cdbef468d7 fix(deps): update dependency react-router-dom to ^7.13.2 2026-03-27 01:19:23 +00:00
renovate[bot]
4705b75580 chore(deps): update dependency vitest to ^4.1.1 2026-03-26 21:24:23 +00:00
renovate[bot]
245ccf889e chore(deps): update dependency vite to ^8.0.2 2026-03-26 18:20:14 +00:00
renovate[bot]
2ad0a3d622 chore(deps): update actions/deploy-pages action to v5 2026-03-25 20:26:46 +00:00
renovate[bot]
e775f774b5 chore(deps): update node.js to v24.14.1 2026-03-25 01:42:38 +00:00
renovate[bot]
ad2aec44e5 chore(deps): update dependency yaml to ^2.8.3 2026-03-24 12:58:01 +00:00
renovate[bot]
11d3effc28 chore(deps): update dependency jsdom to ^29.0.1 2026-03-23 04:57:54 +00:00
renovate[bot]
2ef12e2868 fix(deps): update mantine monorepo to ^8.3.18 (#2084)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-23 04:57:27 +00:00
renovate[bot]
ed8c5ce1ea chore(deps): lock file maintenance 2026-03-23 00:39:56 +00:00
renovate[bot]
33e507efe5 chore(deps): update dependency vite to ^8.0.1 2026-03-22 13:45:17 +00:00
renovate[bot]
c425f5cf6a chore(deps): update dependency @biomejs/biome to v2.4.8 2026-03-21 16:56:21 +00:00
renovate[bot]
fc76d7e609 fix(deps): update dependency @rolldown/plugin-babel to ^0.2.2 2026-03-21 08:51:10 +00:00
renovate[bot]
1b24bf33ed fix(deps): update dependency com.google.protobuf:protobuf-java to v4.34.1 2026-03-20 18:02:04 +00:00
Ingo Kegel
16036897cb Merge branch 'Athou:master' into perf/batch-guid-check-on-feed-refresh 2026-03-19 19:25:09 +01:00
renovate[bot]
58ff378735 fix(deps): update dependency io.github.hakky54:ayza-for-apache5 to v10.0.4 2026-03-19 13:44:43 +00:00
Jérémie Panzer
1cee04a233 Merge pull request #2088 from Athou/renovate/com.diffplug.spotless-spotless-maven-plugin-3.x
chore(deps): update dependency com.diffplug.spotless:spotless-maven-plugin to v3.4.0
2026-03-19 00:03:44 +01:00
renovate[bot]
ac11a0efb8 chore(deps): update dependency com.diffplug.spotless:spotless-maven-plugin to v3.4.0 2026-03-18 21:29:01 +00:00
renovate[bot]
f2ea1e3f7a fix(deps): update dependency io.quarkus.platform:quarkus-bom to v3.32.4 2026-03-18 18:07:29 +00:00
Ingo Kegel
76dbbdfbf9 batch guid existence check on feed refresh
Instead of querying the database once per entry to check if it already
exists, fetch all existing guids for a feed in a single query upfront
and filter new entries in memory before the per-entry loop.

The per-entry findExisting call inside addEntry is kept as a safety net
for concurrent inserts, but is now only reached for new entries.

Profiling in real usage showed a ~50% reduction in guidHash queries,
with the check falling from the most expensive query to sixth in the ranking.
2026-03-18 18:56:40 +01:00
Jérémie Panzer
153970c146 Merge pull request #2087 from Athou/renovate/jsdom-29.x
chore(deps): update dependency jsdom to v29
2026-03-18 13:46:24 +01:00
renovate[bot]
c21287e642 chore(deps): update dependency jsdom to v29 2026-03-18 12:13:28 +00:00
Athou
284942a82e add feature-request to the list of exempted labels 2026-03-18 13:00:44 +01:00
Jérémie Panzer
e796916e73 Merge pull request #2085 from Athou/renovate/com.ibm.icu-icu4j-78.x
fix(deps): update dependency com.ibm.icu:icu4j to v78.3
2026-03-18 12:42:41 +01:00
renovate[bot]
004db1762c fix(deps): update dependency com.ibm.icu:icu4j to v78.3 2026-03-17 22:35:16 +00:00
renovate[bot]
8e05ba8820 chore(deps): update dependency lint-staged to ^16.4.0 (#2083)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-17 20:33:50 +00:00
renovate[bot]
f4f386b5e5 chore(deps): update dependency lint-staged to ^16.3.4 2026-03-17 09:01:31 +00:00
Jérémie Panzer
ecbf8bec23 Merge pull request #2082 from Athou/renovate/debian-13.x
chore(deps): update debian docker tag to v13.4
2026-03-17 07:29:17 +01:00
renovate[bot]
5d8c09ccda chore(deps): update debian docker tag to v13.4 2026-03-17 00:35:37 +00:00
renovate[bot]
47c5c3d8a0 chore(deps): update dependency io.quarkiverse.playwright:quarkus-playwright to v2.3.3 2026-03-16 21:27:52 +00:00
renovate[bot]
3ddce16d5b chore(deps): update graalvm/setup-graalvm digest to 03e8abf 2026-03-16 18:35:24 +00:00
renovate[bot]
acefdc44d9 chore(deps): lock file maintenance 2026-03-16 01:07:15 +00:00
renovate[bot]
d05c5b9d7f chore(deps): update dependency npm to v11.11.1 2026-03-15 04:53:39 +00:00
renovate[bot]
5d1237d1f4 chore(deps): update ncipollo/release-action digest to 339a818 2026-03-15 01:34:06 +00:00
Athou
6bac8631ac output mantine as its own chunk because it is quite large 2026-03-14 20:20:51 +01:00
Athou
2c803327ad upgrade to vite 8 2026-03-13 22:35:20 +01:00
renovate[bot]
451ae5bc51 chore(deps): update dependency lint-staged to ^16.3.3 2026-03-13 05:46:24 +00:00
renovate[bot]
f41ce8c878 chore(deps): update graalvm/setup-graalvm digest to 6e327d2 2026-03-12 19:12:27 +00:00
renovate[bot]
177c54c813 chore(deps): update dependency maven to v3.9.14 2026-03-12 14:46:09 +00:00
Jérémie Panzer
3765e32fd4 Merge pull request #2079 from Athou/renovate/protobuf-monorepo
fix(deps): update dependency com.google.protobuf:protobuf-java to v4.34.0
2026-03-12 08:19:25 +01:00
renovate[bot]
aab7a16d18 fix(deps): update dependency com.google.protobuf:protobuf-java to v4.34.0 2026-03-12 06:26:40 +00:00
Athou
f2463af63c cel update 2026-03-12 07:25:36 +01:00
renovate[bot]
212c2c3b56 fix(deps): update quarkus.version to v3.32.3 2026-03-11 22:48:05 +00:00
renovate[bot]
3ab00b0cdd chore(deps): update actions/download-artifact digest to 3e5f45b 2026-03-11 17:53:34 +00:00
renovate[bot]
fad85e9299 fix(deps): update dependency org.projectlombok:lombok to v1.18.44 2026-03-11 02:48:12 +00:00
renovate[bot]
3cd5e203e2 fix(deps): update mantine monorepo to ^8.3.16 (#2076)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-09 08:40:30 +00:00
Jérémie Panzer
7b081fa870 Merge pull request #2077 from Athou/renovate/biomejs-biome-2.4.x
chore(deps): update dependency @biomejs/biome to v2.4.6
2026-03-09 09:08:37 +01:00
renovate[bot]
5ce22051d4 chore(deps): update dependency @biomejs/biome to v2.4.6 2026-03-09 07:19:20 +00:00
Jérémie Panzer
1e59489fa5 Merge pull request #2078 from Athou/renovate/lock-file-maintenance
chore(deps): lock file maintenance
2026-03-09 08:18:42 +01:00
renovate[bot]
1e691b1255 chore(deps): lock file maintenance 2026-03-09 01:10:36 +00:00
Jérémie Panzer
61e1bef63f Merge pull request #2074 from Athou/renovate/maven-3.9.x
chore(deps): update dependency maven to v3.9.13
2026-03-07 03:45:01 +01:00
renovate[bot]
46dbb78fbf chore(deps): update dependency maven to v3.9.13 2026-03-07 01:16:46 +00:00
renovate[bot]
99890707b3 chore(deps): update dependency lint-staged to ^16.3.2 2026-03-06 21:20:05 +00:00
Jérémie Panzer
f54c841fdc Merge pull request #2073 from Athou/renovate/react-icons-5.x
fix(deps): update dependency react-icons to ^5.6.0
2026-03-06 17:37:19 +01:00
renovate[bot]
e2a6009ee9 fix(deps): update dependency react-icons to ^5.6.0 2026-03-06 10:39:30 +00:00
Jérémie Panzer
a34dd15040 Merge pull request #2072 from Athou/renovate/docker-build-push-action-7.x
chore(deps): update docker/build-push-action action to v7
2026-03-06 07:20:22 +01:00
renovate[bot]
24c934003d chore(deps): update docker/build-push-action action to v7 2026-03-05 21:51:18 +00:00
renovate[bot]
5300e1a245 chore(deps): update dependency @biomejs/biome to v2.4.5 2026-03-05 18:43:33 +00:00
Jérémie Panzer
90381c670b Merge pull request #2071 from Athou/renovate/org.apache.maven.plugins-maven-resources-plugin-3.x
chore(deps): update dependency org.apache.maven.plugins:maven-resources-plugin to v3.5.0
2026-03-05 14:08:00 +01:00
renovate[bot]
23edea93db chore(deps): update dependency org.apache.maven.plugins:maven-resources-plugin to v3.5.0 2026-03-05 12:25:30 +00:00
Jérémie Panzer
a51712e363 Merge pull request #2070 from Athou/renovate/docker-setup-buildx-action-4.x
chore(deps): update docker/setup-buildx-action action to v4
2026-03-05 13:25:03 +01:00
renovate[bot]
4310e979e1 chore(deps): update docker/setup-buildx-action action to v4 2026-03-05 09:47:18 +00:00
renovate[bot]
f690b76d87 fix(deps): update quarkus.version to v3.32.2 2026-03-05 01:25:51 +00:00
Jérémie Panzer
ac29594b67 Merge pull request #2069 from Athou/renovate/docker-setup-qemu-action-4.x
chore(deps): update docker/setup-qemu-action action to v4
2026-03-04 15:29:50 +01:00
renovate[bot]
93f535bb87 chore(deps): update docker/setup-qemu-action action to v4 2026-03-04 13:38:20 +00:00
Jérémie Panzer
076eb3cf42 Merge pull request #2068 from Athou/renovate/docker-login-action-4.x
chore(deps): update docker/login-action action to v4
2026-03-04 14:35:47 +01:00
Athou
7b2e0fffbd reduce timeout for tests to speed up shutdown 2026-03-04 14:19:56 +01:00
renovate[bot]
8eaab0dbc3 chore(deps): update docker/login-action action to v4 2026-03-04 12:59:09 +00:00
Athou
eaa5bc896e stop the application between tests to make sure that there are no active transactions when we truncate the tables 2026-03-04 13:58:06 +01:00
renovate[bot]
42d1db5fc3 chore(deps): update dependency lint-staged to ^16.3.1 2026-03-04 12:09:08 +00:00
Athou
78c017ddaf wait for tasks to complete when shutting down 2026-03-04 12:49:06 +01:00
renovate[bot]
231551d743 chore(deps): update dependency lint-staged to ^16.3.0 (#2067)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-03 21:56:21 +00:00
Jérémie Panzer
d0984eaba7 Merge pull request #2066 from Athou/renovate/com.diffplug.spotless-spotless-maven-plugin-3.x
chore(deps): update dependency com.diffplug.spotless:spotless-maven-plugin to v3.3.0
2026-03-03 06:05:51 +01:00
renovate[bot]
15854a72d1 chore(deps): update dependency com.diffplug.spotless:spotless-maven-plugin to v3.3.0 2026-03-03 01:56:14 +00:00
renovate[bot]
7fd2bf0eda fix(deps): update dependency axios to ^1.13.6 2026-03-02 18:15:22 +00:00
renovate[bot]
6a10a2167e chore(deps): lock file maintenance 2026-03-02 01:25:14 +00:00
Jérémie Panzer
1ba99d255c Merge pull request #2063 from Athou/renovate/npm-11.x
chore(deps): update dependency npm to v11.11.0
2026-03-01 00:43:13 +01:00
renovate[bot]
ff1c2947b6 chore(deps): update dependency npm to v11.11.0 2026-02-28 23:17:20 +00:00
Jérémie Panzer
a690d2e0db Merge pull request #2062 from Athou/renovate/com.puppycrawl.tools-checkstyle-13.x
chore(deps): update dependency com.puppycrawl.tools:checkstyle to v13.3.0
2026-03-01 00:16:55 +01:00
renovate[bot]
a3df327396 chore(deps): update dependency com.puppycrawl.tools:checkstyle to v13.3.0 2026-02-28 20:52:06 +00:00
Jérémie Panzer
ede0016d8e Merge pull request #2060 from Athou/renovate/major-github-artifact-actions
chore(deps): update github artifact actions (major)
2026-02-26 22:57:55 +01:00
renovate[bot]
c19b091795 chore(deps): update github artifact actions 2026-02-26 20:39:27 +00:00
renovate[bot]
9e62c8b9f3 fix(deps): update linguijs monorepo to ^5.9.2 2026-02-26 20:39:23 +00:00
renovate[bot]
9f30dc181c fix(deps): update dependency react-router-dom to ^7.13.1 2026-02-26 18:02:38 +00:00
Jérémie Panzer
37fe44f860 Merge pull request #2059 from Athou/renovate/quarkus.version
fix(deps): update quarkus.version to v3.32.1 (minor)
2026-02-25 20:23:16 +01:00
renovate[bot]
68aaab8467 fix(deps): update quarkus.version to v3.32.1 2026-02-25 16:48:25 +00:00
renovate[bot]
b951ed1fcd chore(deps): update debian:13.3 docker digest to 3615a74 2026-02-24 21:53:17 +00:00
Jérémie Panzer
9bd9dc568a Merge pull request #2058 from Athou/renovate/node-24.x
chore(deps): update node.js to v24.14.0
2026-02-24 21:18:33 +01:00
renovate[bot]
29e4356fee chore(deps): update node.js to v24.14.0 2026-02-24 17:22:57 +00:00
renovate[bot]
0ed31eaa99 chore(deps): update dependency @biomejs/biome to v2.4.4 2026-02-23 21:56:45 +00:00
Jérémie Panzer
1e9869b217 Merge pull request #2057 from Athou/renovate/npm-11.10.x
chore(deps): update dependency npm to v11.10.1
2026-02-23 07:21:35 +01:00
renovate[bot]
78cfc2c827 chore(deps): update dependency npm to v11.10.1 2026-02-23 05:33:44 +00:00
renovate[bot]
a6e5a0d125 chore(deps): lock file maintenance 2026-02-23 00:55:55 +00:00
renovate[bot]
ea13aecd27 chore(deps): update dependency @biomejs/biome to v2.4.3 2026-02-22 21:47:30 +00:00
Athou
d838e8f28f fix occasional flicker 2026-02-22 14:36:25 +01:00
Athou
c9a7b9e17c ensure the indicator is not shown above the app header 2026-02-22 11:47:13 +01:00
Athou
8fe2d0bc0e fix typo 2026-02-21 23:58:49 +01:00
Athou
71e2f1e1e6 kill biome on build to prevent unlink errors on Windows 2026-02-21 23:55:08 +01:00
Athou
1ce9d1b9b2 prevent title line wrapping 2026-02-21 23:39:38 +01:00
Athou
b3d6ae467f reduce code duplication 2026-02-21 23:24:03 +01:00
Athou
da8d720dc4 don't show a pointer on hover 2026-02-21 22:58:49 +01:00
Athou
824c38f8ce show unread count on mobile only 2026-02-21 22:52:32 +01:00
Athou
b0579a70d8 Merge branch 'master' of https://github.com/lpoirothattermann/commafeed into lpoirothattermann-master 2026-02-21 22:28:03 +01:00
Louis POIROT--HATTERMANN
f9fe2d0976 feat: add unread count badge next to title 2026-02-21 18:54:23 +01:00
275 changed files with 18040 additions and 18387 deletions

1
.github/stale.yml vendored
View File

@@ -7,6 +7,7 @@ exemptLabels:
- pinned - pinned
- security - security
- enhancement - enhancement
- feature-request
- bug - bug
# Label to use when marking an issue as stale # Label to use when marking an issue as stale
staleLabel: wontfix staleLabel: wontfix

View File

@@ -23,18 +23,24 @@ jobs:
steps: steps:
# Checkout # Checkout
- name: Checkout - name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with: with:
fetch-depth: 0 fetch-depth: 0
# Setup # Setup
- name: Set up GraalVM - name: Set up GraalVM
uses: graalvm/setup-graalvm@54b4f5a65c1a84b2fdfdc2078fe43df32819e4b1 # v1 uses: graalvm/setup-graalvm@0def53c0fd8534bc13416c9469f5be45265824fd # v1.6.3
with: with:
java-version: ${{ env.JAVA_VERSION }} java-version: ${{ env.JAVA_VERSION }}
distribution: "graalvm" distribution: "graalvm"
cache: "maven" cache: "maven"
- name: Set up NodeJS cache
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
cache: "npm"
cache-dependency-path: 'commafeed-client/package-lock.json'
- name: Install Playwright dependencies - name: Install Playwright dependencies
run: sudo apt-get install -y libgbm1 run: sudo apt-get install -y libgbm1
if: matrix.os != 'windows-latest' if: matrix.os != 'windows-latest'
@@ -67,20 +73,20 @@ jobs:
# Upload artifacts # Upload artifacts
- name: Upload cross-platform app - name: Upload cross-platform app
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: matrix.os == 'ubuntu-latest' # we only need to upload the cross-platform artifact once per database if: matrix.os == 'ubuntu-latest' # we only need to upload the cross-platform artifact once per database
with: with:
name: commafeed-${{ matrix.database }}-jvm name: commafeed-${{ matrix.database }}-jvm
path: commafeed-server/target/commafeed-*.zip path: commafeed-server/target/commafeed-*.zip
- name: Upload native executable - name: Upload native executable
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with: with:
name: commafeed-${{ matrix.database }}-${{ runner.os }}-${{ runner.arch }} name: commafeed-${{ matrix.database }}-${{ runner.os }}-${{ runner.arch }}
path: commafeed-server/target/commafeed-*-runner* path: commafeed-server/target/commafeed-*-runner*
- name: Upload pages - name: Upload pages
uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4 uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
if: matrix.os == 'ubuntu-latest' && matrix.database == 'h2' # we only need to upload the pages once if: matrix.os == 'ubuntu-latest' && matrix.database == 'h2' # we only need to upload the pages once
with: with:
path: target/pages path: target/pages
@@ -98,23 +104,23 @@ jobs:
steps: steps:
# Checkout # Checkout
- name: Checkout - name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with: with:
fetch-depth: 0 fetch-depth: 0
# Setup # Setup
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3 uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
- name: Install required packages - name: Install required packages
run: sudo apt-get install -y rename unzip run: sudo apt-get install -y rename unzip
# Prepare artifacts # Prepare artifacts
- name: Download artifacts - name: Download artifacts
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7 uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with: with:
pattern: commafeed-${{ matrix.database }}-* pattern: commafeed-${{ matrix.database }}-*
path: ./artifacts path: ./artifacts
@@ -135,7 +141,7 @@ jobs:
# Docker # Docker
- name: Login to Container Registry - name: Login to Container Registry
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
if: ${{ env.DOCKERHUB_USERNAME != '' }} if: ${{ env.DOCKERHUB_USERNAME != '' }}
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
@@ -143,7 +149,7 @@ jobs:
## build but don't push for PRs and renovate ## build but don't push for PRs and renovate
- name: Docker build - native - name: Docker build - native
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with: with:
context: . context: .
file: commafeed-server/src/main/docker/Dockerfile.native file: commafeed-server/src/main/docker/Dockerfile.native
@@ -151,7 +157,7 @@ jobs:
platforms: linux/amd64,linux/arm64/v8 platforms: linux/amd64,linux/arm64/v8
- name: Docker build - jvm - name: Docker build - jvm
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with: with:
context: . context: .
file: commafeed-server/src/main/docker/Dockerfile.jvm file: commafeed-server/src/main/docker/Dockerfile.jvm
@@ -160,7 +166,7 @@ jobs:
## build and push tag ## build and push tag
- name: Docker build and push tag - native - name: Docker build and push tag - native
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
if: ${{ github.ref_type == 'tag' }} if: ${{ github.ref_type == 'tag' }}
with: with:
context: . context: .
@@ -172,7 +178,7 @@ jobs:
athou/commafeed:${{ github.ref_name }}-${{ matrix.database }} athou/commafeed:${{ github.ref_name }}-${{ matrix.database }}
- name: Docker build and push tag - jvm - name: Docker build and push tag - jvm
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
if: ${{ github.ref_type == 'tag' }} if: ${{ github.ref_type == 'tag' }}
with: with:
context: . context: .
@@ -185,7 +191,7 @@ jobs:
## build and push master ## build and push master
- name: Docker build and push master - native - name: Docker build and push master - native
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
if: ${{ github.ref_name == 'master' }} if: ${{ github.ref_name == 'master' }}
with: with:
context: . context: .
@@ -195,7 +201,7 @@ jobs:
tags: athou/commafeed:master-${{ matrix.database }} tags: athou/commafeed:master-${{ matrix.database }}
- name: Docker build and push master - jvm - name: Docker build and push master - jvm
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
if: ${{ github.ref_name == 'master' }} if: ${{ github.ref_name == 'master' }}
with: with:
context: . context: .
@@ -215,12 +221,12 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Download artifacts - name: Download artifacts
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7 uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with: with:
pattern: commafeed-* pattern: commafeed-*
path: ./artifacts path: ./artifacts
@@ -230,13 +236,13 @@ jobs:
run: chmod +x artifacts/*-runner run: chmod +x artifacts/*-runner
- name: Extract Changelog Entry - name: Extract Changelog Entry
uses: mindsers/changelog-reader-action@32aa5b4c155d76c94e4ec883a223c947b2f02656 # v2 uses: mindsers/changelog-reader-action@1faaf50aa09d5793d9a100819973df801febfb31 # v2.4.0
id: changelog_reader id: changelog_reader
with: with:
version: ${{ github.ref_name }} version: ${{ github.ref_name }}
- name: Create GitHub release - name: Create GitHub release
uses: ncipollo/release-action@b7eabc95ff50cbeeedec83973935c8f306dfcd0b # v1 uses: ncipollo/release-action@339a81892b84b4eeb0f6e744e4574d79d0d9b8dd # v1.21.0
with: with:
name: CommaFeed ${{ github.ref_name }} name: CommaFeed ${{ github.ref_name }}
body: ${{ steps.changelog_reader.outputs.changes }} body: ${{ steps.changelog_reader.outputs.changes }}
@@ -249,12 +255,12 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Update Docker Hub Description - name: Update Docker Hub Description
uses: peter-evans/dockerhub-description@1b9a80c056b620d92cedb9d9b5a223409c68ddfa # v5 uses: peter-evans/dockerhub-description@1b9a80c056b620d92cedb9d9b5a223409c68ddfa # v5.0.0
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
@@ -274,5 +280,5 @@ jobs:
url: ${{ steps.deployment.outputs.page_url }} url: ${{ steps.deployment.outputs.page_url }}
steps: steps:
- uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4 - uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0
id: deployment id: deployment

View File

@@ -1,3 +1,3 @@
wrapperVersion=3.3.4 wrapperVersion=3.3.4
distributionType=only-script distributionType=only-script
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.12/apache-maven-3.9.12-bin.zip distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.16/apache-maven-3.9.16-bin.zip

View File

@@ -1,5 +1,27 @@
# Changelog # Changelog
## [7.2.1]
- correctly handle favicons hosted at the root of the domain for feeds with non-default ports
- prevent XXS injections in third party apps. The CommaFeed React client was already stripping malicious "javascript:" URLs, they are now filtered during feed parsing and no longer stored in the database/served through the REST API.
## [7.2.0]
- Add support for icons declared in feeds. This is useful for feeds exposed by RSS bridges (#2048)
- Search now also works for starred entries (#2217)
- The error message when subscribing to a feed is now properly displayed again
- Small performance improvements to the feed refresh engine
- Removed the Pocket sharing feature because the Pocket service has been discontinued
- Prevent the image proxy feature to access any URL to avoid SSRF attacks
- Strengthened the SSRF protection by also blocking ULA and CGNAT ranges
- Prevent DDOS attacks by filtering OPML files during imports
## [7.1.0]
- Display the unread count in the header on mobile, since the tree is hidden by default and the unread count is not visible otherwise (#2055)
- The feed refresh engine is now a little bit more performant (#2089)
- On shutdown, give the feed refresh engine some time to finish refreshing feeds before killing it. This is controlled by the new `commafeed.shutdown-timeout` setting, which defaults to 2 seconds
## [7.0.0] ## [7.0.0]
- Replaced the JEXL filter expression for marking feed entries as read automatically with a user-friendly visual query builder. Expressions are now evaluated with Common Expression Language, which is safer than JEXL and sanboxed by default. - Replaced the JEXL filter expression for marking feed entries as read automatically with a user-friendly visual query builder. Expressions are now evaluated with Common Expression Language, which is safer than JEXL and sanboxed by default.

View File

@@ -70,8 +70,8 @@ memory usage.
./mvnw clean package [-P<database> [-Pnative]] [-DskipTests] ./mvnw clean package [-P<database> [-Pnative]] [-DskipTests]
- `<database>` can be one of `h2`, `postgresql`, `mysql` or `mariadb`. The default is `h2`. - `<database>` can be one of `h2`, `postgresql`, `mysql` or `mariadb`. The default is `h2`.
- `-Pnative` compiles the application to native code. This requires GraalVM to be installed (`GRAALVM_HOME` environment - `-Pnative` compiles the application to native code. This requires either GraalVM to be installed (`GRAALVM_HOME` environment
variable pointing to a GraalVM installation). variable pointing to a GraalVM installation) or a container environment to be available (docker/podman/...).
- `-DskipTests` to speed up the build process by skipping tests. - `-DskipTests` to speed up the build process by skipping tests.
When the build is complete: When the build is complete:

View File

@@ -1 +0,0 @@
cd commafeed-client && npx lint-staged

View File

@@ -1,5 +1,5 @@
{ {
"$schema": "https://biomejs.dev/schemas/2.4.2/schema.json", "$schema": "https://biomejs.dev/schemas/2.5.6/schema.json",
"formatter": { "formatter": {
"indentStyle": "space", "indentStyle": "space",
"indentWidth": 4, "indentWidth": 4,

View File

@@ -1,4 +1,5 @@
import type { LinguiConfig } from "@lingui/conf" import type { LinguiConfig } from "@lingui/conf"
import { formatter } from "@lingui/format-po"
const config: LinguiConfig = { const config: LinguiConfig = {
locales: [ locales: [
@@ -38,11 +39,9 @@ const config: LinguiConfig = {
exclude: ["src/locales/**"], exclude: ["src/locales/**"],
}, },
], ],
format: "po", format: formatter({
formatOptions: {
origins: true,
lineNumbers: false, lineNumbers: false,
}, }),
sourceLocale: "en", sourceLocale: "en",
fallbackLocales: { fallbackLocales: {
default: "en", default: "en",

View File

@@ -1,3 +0,0 @@
export default {
"src/**/*.{js,jsx,ts,tsx}": () => ["npm run i18n:extract", "git diff --exit-code commafeed-client/src/locales/en/messages.po"],
}

File diff suppressed because it is too large Load Diff

View File

@@ -12,75 +12,73 @@
"test:ci": "vitest run", "test:ci": "vitest run",
"lint": "biome check", "lint": "biome check",
"lint:fix": "biome check --write", "lint:fix": "biome check --write",
"i18n:extract": "lingui extract --clean", "i18n:extract": "lingui extract --clean"
"prepare": "cd .. && husky ./commafeed-client/.husky"
}, },
"dependencies": { "dependencies": {
"@emotion/react": "^11.14.0", "@emotion/react": "11.14.0",
"@fontsource/open-sans": "^5.2.7", "@fontsource/open-sans": "5.3.0",
"@lingui/core": "^5.9.1", "@lingui/core": "6.6.0",
"@lingui/react": "^5.9.1", "@lingui/react": "6.6.0",
"@mantine/core": "^8.3.15", "@mantine/core": "9.5.0",
"@mantine/form": "^8.3.15", "@mantine/dates": "9.5.0",
"@mantine/hooks": "^8.3.15", "@mantine/form": "9.5.0",
"@mantine/modals": "^8.3.15", "@mantine/hooks": "9.5.0",
"@mantine/notifications": "^8.3.15", "@mantine/modals": "9.5.0",
"@mantine/spotlight": "^8.3.15", "@mantine/notifications": "9.5.0",
"@monaco-editor/react": "^4.7.0", "@mantine/spotlight": "9.5.0",
"@react-querybuilder/mantine": "^8.14.0", "@monaco-editor/react": "4.7.0",
"@reduxjs/toolkit": "^2.11.2", "@react-querybuilder/mantine": "8.21.2",
"axios": "^1.13.5", "@reduxjs/toolkit": "2.12.0",
"dayjs": "^1.11.19", "@rolldown/plugin-babel": "0.2.3",
"escape-string-regexp": "^5.0.0", "axios": "1.19.0",
"interweave": "^13.1.1", "dayjs": "1.11.21",
"monaco-editor": "^0.55.1", "escape-string-regexp": "5.0.0",
"mousetrap": "^1.6.5", "interweave": "13.1.1",
"react": "^19.2.4", "monaco-editor": "0.56.0",
"react-async-hook": "^4.0.0", "mousetrap": "1.6.5",
"react-contexify": "^6.0.0", "react": "19.2.8",
"react-dom": "^19.2.4", "react-async-hook": "4.0.0",
"react-draggable": "^4.5.0", "react-contexify": "6.0.0",
"react-icons": "^5.5.0", "react-dom": "19.2.8",
"react-infinite-scroller": "^1.2.6", "react-draggable": "4.7.1",
"react-querybuilder": "^8.14.0", "react-icons": "5.7.0",
"react-redux": "^9.2.0", "react-infinite-scroller": "1.2.6",
"react-router-dom": "^7.13.0", "react-querybuilder": "8.21.2",
"react-swipeable": "^7.0.2", "react-redux": "9.3.0",
"style-to-object": "^1.0.14", "react-router-dom": "7.18.2",
"throttle-debounce": "^5.0.2", "react-swipeable": "7.0.2",
"tinycon": "^0.6.8", "style-to-object": "2.0.2",
"tss-react": "^4.9.20", "throttle-debounce": "5.0.2",
"websocket-heartbeat-js": "^1.1.3" "tinycon": "0.6.8",
"tss-react": "4.9.21",
"websocket-heartbeat-js": "1.1.3"
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "^2.4.2", "@biomejs/biome": "2.5.6",
"@lingui/babel-plugin-lingui-macro": "^5.9.1", "@lingui/babel-plugin-lingui-macro": "6.6.0",
"@lingui/cli": "^5.9.1", "@lingui/cli": "6.6.0",
"@lingui/vite-plugin": "^5.9.1", "@lingui/vite-plugin": "6.6.0",
"@testing-library/jest-dom": "^6.9.1", "@testing-library/jest-dom": "7.0.0",
"@testing-library/react": "^16.3.2", "@testing-library/react": "16.3.2",
"@testing-library/user-event": "^14.6.1", "@testing-library/user-event": "14.6.1",
"@types/mousetrap": "^1.6.15", "@types/mousetrap": "1.6.15",
"@types/react": "^19.2.14", "@types/react": "19.2.18",
"@types/react-dom": "^19.2.3", "@types/react-dom": "19.2.4",
"@types/react-infinite-scroller": "^1.2.5", "@types/react-infinite-scroller": "1.2.5",
"@types/throttle-debounce": "^5.0.2", "@types/throttle-debounce": "5.0.2",
"@types/tinycon": "^0.6.7", "@types/tinycon": "0.6.7",
"@vitejs/plugin-react": "^5.1.4", "@vitejs/plugin-react": "6.0.5",
"babel-plugin-react-compiler": "1.0.0", "babel-plugin-react-compiler": "1.0.0",
"husky": "^9.1.7", "jsdom": "30.0.1",
"jsdom": "^28.1.0", "typescript": "7.0.2",
"lint-staged": "^16.2.7", "vite": "8.2.0",
"typescript": "^5.9.3", "vite-plugin-checker": "0.14.5",
"vite": "^7.3.1", "vitest": "4.1.10",
"vite-plugin-checker": "^0.12.0", "yaml": "2.9.0"
"vite-tsconfig-paths": "^6.1.1",
"vitest": "^4.0.18",
"yaml": "^2.8.2"
}, },
"overrides": { "overrides": {
"react-infinite-scroller": { "react-infinite-scroller": {
"react": "^19.2.4" "react": "19.2.8"
} }
} }
} }

View File

@@ -6,16 +6,16 @@
<parent> <parent>
<groupId>com.commafeed</groupId> <groupId>com.commafeed</groupId>
<artifactId>commafeed</artifactId> <artifactId>commafeed</artifactId>
<version>7.0.0</version> <version>7.2.1</version>
</parent> </parent>
<artifactId>commafeed-client</artifactId> <artifactId>commafeed-client</artifactId>
<name>CommaFeed Client</name> <name>CommaFeed Client</name>
<properties> <properties>
<!-- renovate: datasource=node-version depName=node --> <!-- renovate: datasource=node-version depName=node -->
<node.version>v24.13.1</node.version> <node.version>v24.18.1</node.version>
<!-- renovate: datasource=npm depName=npm --> <!-- renovate: datasource=npm depName=npm -->
<npm.version>11.10.0</npm.version> <npm.version>12.0.2</npm.version>
</properties> </properties>
<build> <build>
@@ -23,7 +23,7 @@
<plugin> <plugin>
<groupId>com.github.eirslett</groupId> <groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId> <artifactId>frontend-maven-plugin</artifactId>
<version>2.0.0</version> <version>2.0.2</version>
<?m2e ignore?> <?m2e ignore?>
<executions> <executions>
<execution> <execution>
@@ -72,7 +72,7 @@
</plugin> </plugin>
<plugin> <plugin>
<artifactId>maven-resources-plugin</artifactId> <artifactId>maven-resources-plugin</artifactId>
<version>3.4.0</version> <version>3.5.0</version>
<executions> <executions>
<execution> <execution>
<id>copy web interface to resources</id> <id>copy web interface to resources</id>
@@ -94,4 +94,49 @@
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
<profiles>
<!-- This profile is used to kill the Biome process on Windows -->
<!-- npm ci can fail if Biome is running (e.g., in the IDE) because it locks some files -->
<profile>
<id>kill-biome</id>
<activation>
<os>
<family>Windows</family>
</os>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.6.3</version>
<executions>
<execution>
<id>kill-biome</id>
<phase>initialize</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>taskkill</executable>
<arguments>
<argument>/F</argument>
<argument>/IM</argument>
<argument>biome.exe</argument>
</arguments>
<successCodes>
<successCode>0</successCode>
<!-- taskkill returns 128 if the process is not found, which is fine in this case -->
<successCode>128</successCode>
</successCodes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project> </project>

View File

@@ -1,62 +1,40 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg <svg
height="393.84613" height="393.84613"
width="393.84613" width="393.84613"
viewBox="0 0 5.0480766 5.0480766" viewBox="0 0 5.0480766 5.0480766"
version="1.1" version="1.1"
id="svg3" id="svg3"
sodipodi:docname="favicon.svg" xmlns="http://www.w3.org/2000/svg">
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)" <title>CommaFeed favicon</title>
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" <defs
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" id="defs3" />
xmlns="http://www.w3.org/2000/svg" <rect
xmlns:svg="http://www.w3.org/2000/svg"> fill="#f88a14"
<defs rx="0.53846151"
id="defs3" /> ry="0.53846151"
<sodipodi:namedview height="5.0480766"
id="namedview3" width="5.0480766"
pagecolor="#ffffff" id="rect1"
bordercolor="#000000" x="0"
borderopacity="0.25" y="0"
inkscape:showpageshadow="2" style="stroke-width:0.769231" />
inkscape:pageopacity="0.0" <path
inkscape:pagecheckerboard="0" d="m 1.3450904,0.64548657 c 2.9002,0 2.9002,2.91010003 2.9002,2.91010003"
inkscape:deskcolor="#d1d1d1" fill="none"
inkscape:zoom="1.21875" stroke="#ffffff"
inkscape:cx="207.17949" stroke-linecap="round"
inkscape:cy="187.07692" stroke-width="0.78125"
inkscape:window-width="1440" id="path1" />
inkscape:window-height="855" <path
inkscape:window-x="0" d="m 1.3377904,1.9915866 c 1.5705,-0.00908 1.5705,1.5639 1.5705,1.5639"
inkscape:window-y="0" fill="none"
inkscape:window-maximized="1" stroke="#ffffff"
inkscape:current-layer="svg3" /> stroke-linecap="round"
<rect stroke-width="0.78125"
fill="#f88a14" id="path2" />
rx="0.53846151" <path
ry="0.53846151" d="m 2.0192904,3.5227866 c 0,0.23366 -0.10712,0.47418 -0.24663,0.6537 -0.1814,0.2333 -0.5705,0.5618 -0.6913,0.5653 0.0402,-0.0662 0.263,-0.5654 0.2563,-0.5654 -0.36423004,0 -0.65950004,-0.29265 -0.65950004,-0.65365 0,-0.361 0.29527,-0.65365 0.65950004,-0.65365 0.36423,0 0.68159,0.29265 0.68159,0.65365 z"
height="5.0480766" fill="#ffffff"
width="5.0480766" id="path3" />
id="rect1"
x="0"
y="0"
style="stroke-width:0.769231" />
<path
d="m 1.3450904,0.64548657 c 2.9002,0 2.9002,2.91010003 2.9002,2.91010003"
fill="none"
stroke="#ffffff"
stroke-linecap="round"
stroke-width="0.78125"
id="path1" />
<path
d="m 1.3377904,1.9915866 c 1.5705,-0.00908 1.5705,1.5639 1.5705,1.5639"
fill="none"
stroke="#ffffff"
stroke-linecap="round"
stroke-width="0.78125"
id="path2" />
<path
d="m 2.0192904,3.5227866 c 0,0.23366 -0.10712,0.47418 -0.24663,0.6537 -0.1814,0.2333 -0.5705,0.5618 -0.6913,0.5653 0.0402,-0.0662 0.263,-0.5654 0.2563,-0.5654 -0.36423004,0 -0.65950004,-0.29265 -0.65950004,-0.65365 0,-0.361 0.29527,-0.65365 0.65950004,-0.65365 0.36423,0 0.68159,0.29265 0.68159,0.65365 z"
fill="#ffffff"
id="path3" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,24 +1,19 @@
import { i18n } from "@lingui/core" import { i18n } from "@lingui/core"
import { I18nProvider } from "@lingui/react" import { I18nProvider } from "@lingui/react"
import { MantineProvider } from "@mantine/core" import { MantineProvider, v8CssVariablesResolver } from "@mantine/core"
import { ModalsProvider } from "@mantine/modals" import { ModalsProvider } from "@mantine/modals"
import { Notifications } from "@mantine/notifications" import { Notifications } from "@mantine/notifications"
import type React from "react" import type React from "react"
import { useEffect, useState } from "react" import { useEffect } from "react"
import { HashRouter, Navigate, Route, Routes, useNavigate } from "react-router-dom" import { HashRouter, Navigate, Route, Routes, useNavigate } from "react-router-dom"
import Tinycon from "tinycon"
import { Constants } from "@/app/constants" import { Constants } from "@/app/constants"
import { redirectTo } from "@/app/redirect/slice" import { redirectTo } from "@/app/redirect/slice"
import { redirectToInitialSetup } from "@/app/redirect/thunks" import { redirectToInitialSetup } from "@/app/redirect/thunks"
import { reloadServerInfos } from "@/app/server/thunks" import { reloadServerInfos } from "@/app/server/thunks"
import { useAppDispatch, useAppSelector } from "@/app/store" import { useAppDispatch, useAppSelector } from "@/app/store"
import { categoryUnreadCount } from "@/app/utils"
import { DisablePullToRefresh } from "@/components/DisablePullToRefresh"
import { ErrorBoundary } from "@/components/ErrorBoundary" import { ErrorBoundary } from "@/components/ErrorBoundary"
import { Header } from "@/components/header/Header" import { Header } from "@/components/header/Header"
import { Tree } from "@/components/sidebar/Tree" import { Tree } from "@/components/sidebar/Tree"
import { useAppLoading } from "@/hooks/useAppLoading"
import { useBrowserExtension } from "@/hooks/useBrowserExtension"
import { useI18n } from "@/i18n" import { useI18n } from "@/i18n"
import { AdminUsersPage } from "@/pages/admin/AdminUsersPage" import { AdminUsersPage } from "@/pages/admin/AdminUsersPage"
import { MetricsPage } from "@/pages/admin/MetricsPage" import { MetricsPage } from "@/pages/admin/MetricsPage"
@@ -48,6 +43,8 @@ function Providers(
<I18nProvider i18n={i18n}> <I18nProvider i18n={i18n}>
<MantineProvider <MantineProvider
defaultColorScheme="auto" defaultColorScheme="auto"
// keep using css variables from mantine v8
cssVariablesResolver={v8CssVariablesResolver}
theme={{ theme={{
primaryColor: primaryColor, primaryColor: primaryColor,
fontFamily: "Open Sans", fontFamily: "Open Sans",
@@ -144,83 +141,8 @@ function RedirectHandler() {
return null return null
} }
function UnreadCountTitleHandler({
enabled,
}: Readonly<{
enabled?: boolean
}>) {
const root = useAppSelector(state => state.tree.rootCategory)
const unreadCount = categoryUnreadCount(root)
return <title>{enabled && unreadCount > 0 ? `(${unreadCount}) CommaFeed` : "CommaFeed"}</title>
}
function UnreadCountFaviconHandler({ enabled }: { enabled?: boolean }) {
const root = useAppSelector(state => state.tree.rootCategory)
const unreadCount = categoryUnreadCount(root)
useEffect(() => {
if (enabled && unreadCount > 0) {
Tinycon.setBubble(unreadCount)
} else {
Tinycon.reset()
}
}, [unreadCount, enabled])
return null
}
function BrowserExtensionBadgeUnreadCountHandler() {
const root = useAppSelector(state => state.tree.rootCategory)
const { setBadgeUnreadCount } = useBrowserExtension()
useEffect(() => {
if (!root) return
const unreadCount = categoryUnreadCount(root)
setBadgeUnreadCount(unreadCount)
}, [root, setBadgeUnreadCount])
return null
}
function CustomJsHandler() {
const [scriptLoaded, setScriptLoaded] = useState(false)
const { loading } = useAppLoading()
useEffect(() => {
if (scriptLoaded || loading) {
return
}
const script = document.createElement("script")
script.src = "custom_js.js"
script.async = true
document.body.appendChild(script)
setScriptLoaded(true)
return () => script.remove()
}, [scriptLoaded, loading])
return null
}
function CustomCssHandler() {
useEffect(() => {
const link = document.createElement("link")
link.rel = "stylesheet"
link.type = "text/css"
link.href = "custom_css.css"
document.head.appendChild(link)
return () => link.remove()
}, [])
return null
}
export function App() { export function App() {
useI18n() useI18n()
const unreadCountTitle = useAppSelector(state => state.user.settings?.unreadCountTitle)
const unreadCountFavicon = useAppSelector(state => state.user.settings?.unreadCountFavicon)
const disablePullToRefresh = useAppSelector(state => state.user.settings?.disablePullToRefresh)
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
useEffect(() => { useEffect(() => {
@@ -229,13 +151,6 @@ export function App() {
return ( return (
<Providers> <Providers>
<UnreadCountTitleHandler enabled={unreadCountTitle} />
<UnreadCountFaviconHandler enabled={unreadCountFavicon} />
<BrowserExtensionBadgeUnreadCountHandler />
<CustomJsHandler />
<CustomCssHandler />
<DisablePullToRefresh enabled={disablePullToRefresh} />
<HashRouter> <HashRouter>
<InitialSetupHandler /> <InitialSetupHandler />
<RedirectHandler /> <RedirectHandler />

View File

@@ -1,6 +1,6 @@
import type { IconType } from "react-icons" import type { IconType } from "react-icons"
import { FaAt } from "react-icons/fa" import { FaAt } from "react-icons/fa"
import { SiBuffer, SiFacebook, SiGmail, SiInstapaper, SiPocket, SiTumblr, SiX } from "react-icons/si" import { SiBuffer, SiFacebook, SiGmail, SiInstapaper, SiTumblr, SiX } from "react-icons/si"
import type { Category, Entry, SharingSettings } from "./types" import type { Category, Entry, SharingSettings } from "./types"
const categories: Record<string, Omit<Category, "name">> = { const categories: Record<string, Omit<Category, "name">> = {
@@ -58,12 +58,6 @@ const sharing: {
color: "#375672", color: "#375672",
url: (url, desc) => `https://www.tumblr.com/share/link?url=${url}&name=${desc}`, url: (url, desc) => `https://www.tumblr.com/share/link?url=${url}&name=${desc}`,
}, },
pocket: {
label: "Pocket",
icon: SiPocket,
color: "#EF4154",
url: (url, desc) => `https://getpocket.com/save?url=${url}&title=${desc}`,
},
instapaper: { instapaper: {
label: "Instapaper", label: "Instapaper",
icon: SiInstapaper, icon: SiInstapaper,

View File

@@ -1,5 +1,5 @@
import { configureStore } from "@reduxjs/toolkit" import { configureStore } from "@reduxjs/toolkit"
import { type TypedUseSelectorHook, useDispatch, useSelector } from "react-redux" import { shallowEqual, type TypedUseSelectorHook, useDispatch, useSelector } from "react-redux"
import { entriesSlice } from "@/app/entries/slice" import { entriesSlice } from "@/app/entries/slice"
import { redirectSlice } from "@/app/redirect/slice" import { redirectSlice } from "@/app/redirect/slice"
import { serverSlice } from "@/app/server/slice" import { serverSlice } from "@/app/server/slice"
@@ -41,3 +41,4 @@ export type AppDispatch = typeof store.dispatch
export const useAppDispatch: () => AppDispatch = useDispatch export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
export const useShallowEqualAppSelector: TypedUseSelectorHook<RootState> = selector => useSelector(selector, shallowEqual)

View File

@@ -249,7 +249,6 @@ export interface SharingSettings {
facebook: boolean facebook: boolean
twitter: boolean twitter: boolean
tumblr: boolean tumblr: boolean
pocket: boolean
instapaper: boolean instapaper: boolean
buffer: boolean buffer: boolean
} }

View File

@@ -1,32 +1,8 @@
import { t } from "@lingui/core/macro" import { t } from "@lingui/core/macro"
import { showNotification } from "@mantine/notifications" import { showNotification } from "@mantine/notifications"
import { createSlice, isAnyOf, type PayloadAction } from "@reduxjs/toolkit" import { createSlice, type PayloadAction } from "@reduxjs/toolkit"
import type { LocalSettings, Settings, UserModel, ViewMode } from "@/app/types" import type { LocalSettings, Settings, UserModel, ViewMode } from "@/app/types"
import { import { changeSettings, reloadProfile, reloadSettings, reloadTags } from "./thunks"
changeCustomContextMenu,
changeDisablePullToRefresh,
changeEntriesToKeepOnTopWhenScrolling,
changeExternalLinkIconDisplayMode,
changeLanguage,
changeMarkAllAsReadConfirmation,
changeMarkAllAsReadNavigateToUnread,
changeMobileFooter,
changePrimaryColor,
changePushNotificationSettings,
changeReadingMode,
changeReadingOrder,
changeScrollMarks,
changeScrollMode,
changeScrollSpeed,
changeSharingSetting,
changeShowRead,
changeStarIconDisplayMode,
changeUnreadCountFavicon,
changeUnreadCountTitle,
reloadProfile,
reloadSettings,
reloadTags,
} from "./thunks"
interface UserState { interface UserState {
settings?: Settings settings?: Settings
@@ -73,115 +49,16 @@ export const userSlice = createSlice({
builder.addCase(reloadTags.fulfilled, (state, action) => { builder.addCase(reloadTags.fulfilled, (state, action) => {
state.tags = action.payload state.tags = action.payload
}) })
builder.addCase(changeReadingMode.pending, (state, action) => { builder.addCase(changeSettings.pending, (state, action) => {
if (!state.settings) return if (!state.settings) return
state.settings.readingMode = action.meta.arg state.settings = { ...state.settings, ...action.meta.arg }
}) })
builder.addCase(changeReadingOrder.pending, (state, action) => { builder.addCase(changeSettings.fulfilled, () => {
if (!state.settings) return showNotification({
state.settings.readingOrder = action.meta.arg message: t`Settings saved.`,
color: "green",
})
}) })
builder.addCase(changeLanguage.pending, (state, action) => {
if (!state.settings) return
state.settings.language = action.meta.arg
})
builder.addCase(changeScrollSpeed.pending, (state, action) => {
if (!state.settings) return
state.settings.scrollSpeed = action.meta.arg ? 400 : 0
})
builder.addCase(changeShowRead.pending, (state, action) => {
if (!state.settings) return
state.settings.showRead = action.meta.arg
})
builder.addCase(changeScrollMarks.pending, (state, action) => {
if (!state.settings) return
state.settings.scrollMarks = action.meta.arg
})
builder.addCase(changeScrollMode.pending, (state, action) => {
if (!state.settings) return
state.settings.scrollMode = action.meta.arg
})
builder.addCase(changeEntriesToKeepOnTopWhenScrolling.pending, (state, action) => {
if (!state.settings) return
state.settings.entriesToKeepOnTopWhenScrolling = action.meta.arg
})
builder.addCase(changeStarIconDisplayMode.pending, (state, action) => {
if (!state.settings) return
state.settings.starIconDisplayMode = action.meta.arg
})
builder.addCase(changeExternalLinkIconDisplayMode.pending, (state, action) => {
if (!state.settings) return
state.settings.externalLinkIconDisplayMode = action.meta.arg
})
builder.addCase(changeMarkAllAsReadConfirmation.pending, (state, action) => {
if (!state.settings) return
state.settings.markAllAsReadConfirmation = action.meta.arg
})
builder.addCase(changeMarkAllAsReadNavigateToUnread.pending, (state, action) => {
if (!state.settings) return
state.settings.markAllAsReadNavigateToNextUnread = action.meta.arg
})
builder.addCase(changeCustomContextMenu.pending, (state, action) => {
if (!state.settings) return
state.settings.customContextMenu = action.meta.arg
})
builder.addCase(changeMobileFooter.pending, (state, action) => {
if (!state.settings) return
state.settings.mobileFooter = action.meta.arg
})
builder.addCase(changeUnreadCountTitle.pending, (state, action) => {
if (!state.settings) return
state.settings.unreadCountTitle = action.meta.arg
})
builder.addCase(changeUnreadCountFavicon.pending, (state, action) => {
if (!state.settings) return
state.settings.unreadCountFavicon = action.meta.arg
})
builder.addCase(changeDisablePullToRefresh.pending, (state, action) => {
if (!state.settings) return
state.settings.disablePullToRefresh = action.meta.arg
})
builder.addCase(changePrimaryColor.pending, (state, action) => {
if (!state.settings) return
state.settings.primaryColor = action.meta.arg
})
builder.addCase(changeSharingSetting.pending, (state, action) => {
if (!state.settings) return
state.settings.sharingSettings[action.meta.arg.site] = action.meta.arg.value
})
builder.addCase(changePushNotificationSettings.pending, (state, action) => {
if (!state.settings) return
state.settings.pushNotificationSettings = action.meta.arg
})
builder.addMatcher(
isAnyOf(
changeLanguage.fulfilled,
changeScrollSpeed.fulfilled,
changeShowRead.fulfilled,
changeScrollMarks.fulfilled,
changeScrollMode.fulfilled,
changeEntriesToKeepOnTopWhenScrolling.fulfilled,
changeStarIconDisplayMode.fulfilled,
changeExternalLinkIconDisplayMode.fulfilled,
changeMarkAllAsReadConfirmation.fulfilled,
changeMarkAllAsReadNavigateToUnread.fulfilled,
changeCustomContextMenu.fulfilled,
changeMobileFooter.fulfilled,
changeUnreadCountTitle.fulfilled,
changeUnreadCountFavicon.fulfilled,
changeDisablePullToRefresh.fulfilled,
changePrimaryColor.fulfilled,
changeSharingSetting.fulfilled,
changePushNotificationSettings.fulfilled
),
() => {
showNotification({
message: t`Settings saved.`,
color: "green",
})
}
)
}, },
}) })

View File

@@ -1,7 +1,6 @@
import { createAppAsyncThunk } from "@/app/async-thunk" import { createAppAsyncThunk } from "@/app/async-thunk"
import { client } from "@/app/client" import { client } from "@/app/client"
import { reloadEntries } from "@/app/entries/thunks" import type { Settings } from "@/app/types"
import type { IconDisplayMode, PushNotificationSettings, ReadingMode, ReadingOrder, ScrollMode, SharingSettings } from "@/app/types"
export const reloadSettings = createAppAsyncThunk("settings/reload", async () => await client.user.getSettings().then(r => r.data)) export const reloadSettings = createAppAsyncThunk("settings/reload", async () => await client.user.getSettings().then(r => r.data))
@@ -9,163 +8,8 @@ export const reloadProfile = createAppAsyncThunk("profile/reload", async () => a
export const reloadTags = createAppAsyncThunk("entries/tags", async () => await client.entry.getTags().then(r => r.data)) export const reloadTags = createAppAsyncThunk("entries/tags", async () => await client.entry.getTags().then(r => r.data))
export const changeReadingMode = createAppAsyncThunk("settings/readingMode", (readingMode: ReadingMode, thunkApi) => { export const changeSettings = createAppAsyncThunk("settings/change", async (newSettings: Partial<Settings>, thunkApi) => {
const { settings } = thunkApi.getState().user const { settings } = thunkApi.getState().user
if (!settings) return if (!settings) return
client.user.saveSettings({ ...settings, readingMode }) await client.user.saveSettings({ ...settings, ...newSettings })
thunkApi.dispatch(reloadEntries())
}) })
export const changeReadingOrder = createAppAsyncThunk("settings/readingOrder", (readingOrder: ReadingOrder, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, readingOrder })
thunkApi.dispatch(reloadEntries())
})
export const changeLanguage = createAppAsyncThunk("settings/language", (language: string, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, language })
})
export const changeScrollSpeed = createAppAsyncThunk("settings/scrollSpeed", (speed: boolean, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, scrollSpeed: speed ? 400 : 0 })
})
export const changeShowRead = createAppAsyncThunk("settings/showRead", (showRead: boolean, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, showRead })
})
export const changeScrollMarks = createAppAsyncThunk("settings/scrollMarks", (scrollMarks: boolean, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, scrollMarks })
})
export const changeScrollMode = createAppAsyncThunk("settings/scrollMode", (scrollMode: ScrollMode, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, scrollMode })
})
export const changeEntriesToKeepOnTopWhenScrolling = createAppAsyncThunk(
"settings/entriesToKeepOnTopWhenScrolling",
(entriesToKeepOnTopWhenScrolling: number, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, entriesToKeepOnTopWhenScrolling })
}
)
export const changeStarIconDisplayMode = createAppAsyncThunk(
"settings/starIconDisplayMode",
(starIconDisplayMode: IconDisplayMode, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, starIconDisplayMode })
}
)
export const changeExternalLinkIconDisplayMode = createAppAsyncThunk(
"settings/externalLinkIconDisplayMode",
(externalLinkIconDisplayMode: IconDisplayMode, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, externalLinkIconDisplayMode })
}
)
export const changeMarkAllAsReadConfirmation = createAppAsyncThunk(
"settings/markAllAsReadConfirmation",
(markAllAsReadConfirmation: boolean, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, markAllAsReadConfirmation })
}
)
export const changeMarkAllAsReadNavigateToUnread = createAppAsyncThunk(
"settings/markAllAsReadNavigateToUnread",
(markAllAsReadNavigateToNextUnread: boolean, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, markAllAsReadNavigateToNextUnread })
}
)
export const changeCustomContextMenu = createAppAsyncThunk("settings/customContextMenu", (customContextMenu: boolean, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, customContextMenu })
})
export const changeMobileFooter = createAppAsyncThunk("settings/mobileFooter", (mobileFooter: boolean, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, mobileFooter })
})
export const changeUnreadCountTitle = createAppAsyncThunk("settings/unreadCountTitle", (unreadCountTitle: boolean, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, unreadCountTitle })
})
export const changeUnreadCountFavicon = createAppAsyncThunk("settings/unreadCountFavicon", (unreadCountFavicon: boolean, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, unreadCountFavicon })
})
export const changeDisablePullToRefresh = createAppAsyncThunk(
"settings/disablePullToRefresh",
(disablePullToRefresh: boolean, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, disablePullToRefresh })
}
)
export const changePrimaryColor = createAppAsyncThunk("settings/primaryColor", (primaryColor: string, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, primaryColor })
})
export const changeSharingSetting = createAppAsyncThunk(
"settings/sharingSetting",
(
sharingSetting: {
site: keyof SharingSettings
value: boolean
},
thunkApi
) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({
...settings,
sharingSettings: {
...settings.sharingSettings,
[sharingSetting.site]: sharingSetting.value,
},
})
}
)
export const changePushNotificationSettings = createAppAsyncThunk(
"settings/pushNotificationSettings",
(pushNotificationSettings: PushNotificationSettings, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({
...settings,
pushNotificationSettings,
})
}
)

View File

@@ -1,10 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg height="512" width="512" viewBox="0 0 6.5625 6.5625" xmlns="http://www.w3.org/2000/svg"> <svg height="512" width="512" viewBox="0 0 6.5625 6.5625" xmlns="http://www.w3.org/2000/svg">
<title>CommaFeed logo</title>
<rect fill="#f88a14" rx="0.7" ry="0.7" height="6.5625" width="6.5625" /> <rect fill="#f88a14" rx="0.7" ry="0.7" height="6.5625" width="6.5625" />
<path d="m1.9761,1.5289c2.9002,0,2.9002,2.9101,2.9002,2.9101" fill="none" stroke="#FFF" stroke-linecap="round" <path d="m1.9761,1.5289c2.9002,0,2.9002,2.9101,2.9002,2.9101" fill="none" stroke="#FFF" stroke-linecap="round"
stroke-width="0.78125" /> stroke-width="0.78125" />
<path d="m1.9688,2.875c1.5705-0.00908,1.5705,1.5639,1.5705,1.5639" fill="none" stroke="#FFF" stroke-linecap="round" <path d="m1.9688,2.875c1.5705-0.00908,1.5705,1.5639,1.5705,1.5639" fill="none" stroke="#FFF" stroke-linecap="round"
stroke-width="0.78125" /> stroke-width="0.78125" />
<path d="m2.6503,4.4062c0,0.23366-0.10712,0.47418-0.24663,0.6537-0.1814,0.2333-0.5705,0.5618-0.6913,0.5653,0.0402-0.0662,0.263-0.5654,0.2563-0.5654-0.36423,0-0.6595-0.29265-0.6595-0.65365s0.29527-0.65365,0.6595-0.65365,0.68159,0.29265,0.68159,0.65365z" <path d="m2.6503,4.4062c0,0.23366-0.10712,0.47418-0.24663,0.6537-0.1814,0.2333-0.5705,0.5618-0.6913,0.5653,0.0402-0.0662,0.263-0.5654,0.2563-0.5654-0.36423,0-0.6595-0.29265-0.6595-0.65365s0.29527-0.65365,0.6595-0.65365,0.68159,0.29265,0.68159,0.65365z"
fill="#FFF" /> fill="#FFF" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 791 B

After

Width:  |  Height:  |  Size: 831 B

View File

@@ -1,7 +1,6 @@
import type { MessageDescriptor } from "@lingui/core" import type { MessageDescriptor } from "@lingui/core"
import { useLingui } from "@lingui/react" import { useLingui } from "@lingui/react"
import { ActionIcon, Box, Button, type ButtonVariant, Tooltip, useMantineTheme } from "@mantine/core" import { ActionIcon, type ActionIconVariant, Box, Button, type ButtonVariant, Tooltip, useMantineTheme } from "@mantine/core"
import type { ActionIconVariant } from "@mantine/core/lib/components/ActionIcon/ActionIcon"
import { forwardRef, type MouseEventHandler, type ReactNode } from "react" import { forwardRef, type MouseEventHandler, type ReactNode } from "react"
import { Constants } from "@/app/constants" import { Constants } from "@/app/constants"
import { useActionButton } from "@/hooks/useActionButton" import { useActionButton } from "@/hooks/useActionButton"

View File

@@ -14,6 +14,7 @@ interface ImageWithPlaceholderWhileLoadingProps {
placeholderHeight?: number placeholderHeight?: number
placeholderBackgroundColor?: string placeholderBackgroundColor?: string
placeholderIconSize?: number placeholderIconSize?: number
onError?: (e: React.SyntheticEvent<HTMLImageElement, Event>) => void
} }
const useStyles = tss const useStyles = tss
@@ -44,6 +45,7 @@ export function ImageWithPlaceholderWhileLoading({
title, title,
width, width,
style, style,
onError,
}: Readonly<ImageWithPlaceholderWhileLoadingProps>) { }: Readonly<ImageWithPlaceholderWhileLoadingProps>) {
const { classes } = useStyles({ const { classes } = useStyles({
placeholderWidth, placeholderWidth,
@@ -70,6 +72,7 @@ export function ImageWithPlaceholderWhileLoading({
width={width} width={width}
height={height} height={height}
onLoad={() => setLoading(false)} onLoad={() => setLoading(false)}
onError={onError}
style={{ style={{
...style, ...style,
display: loading ? "none" : (style?.display ?? "initial"), display: loading ? "none" : (style?.display ?? "initial"),

View File

@@ -7,11 +7,11 @@ const init = async () => {
async getWorker(_, label) { async getWorker(_, label) {
let worker: typeof import("*?worker") let worker: typeof import("*?worker")
if (label === "css") { if (label === "css") {
worker = await import("monaco-editor/esm/vs/language/css/css.worker?worker") worker = await import("monaco-editor/language/css/css.worker?worker")
} else if (label === "javascript") { } else if (label === "javascript") {
worker = await import("monaco-editor/esm/vs/language/typescript/ts.worker?worker") worker = await import("monaco-editor/language/typescript/ts.worker?worker")
} else { } else {
worker = await import("monaco-editor/esm/vs/editor/editor.worker?worker") worker = await import("monaco-editor/editor/editor.worker?worker")
} }
return new worker.default() return new worker.default()
}, },

View File

@@ -1,3 +1,5 @@
import { useTimeout } from "@mantine/hooks"
import { useState } from "react"
import { ImageWithPlaceholderWhileLoading } from "@/components/ImageWithPlaceholderWhileLoading" import { ImageWithPlaceholderWhileLoading } from "@/components/ImageWithPlaceholderWhileLoading"
export interface FeedFaviconProps { export interface FeedFaviconProps {
@@ -6,9 +8,23 @@ export interface FeedFaviconProps {
} }
export function FeedFavicon({ url, size = 18 }: Readonly<FeedFaviconProps>) { export function FeedFavicon({ url, size = 18 }: Readonly<FeedFaviconProps>) {
// the backend always returns a favicon except when the feed has never been fetched
// this can happen when the user subscribes to a feed, the feed is added to the tree but the feed has not been fetched yet
// in this case we retry every second up to 3 times until the feed is fetched and the favicon is available
const [timestamp, setTimestamp] = useState(0)
const [retryCount, setRetryCount] = useState(0)
const { start: retry } = useTimeout(() => setTimestamp(Date.now()), 1000)
const urlWithTimestamp = url + (timestamp === 0 ? "" : `?t=${timestamp}`)
const handleError = () => {
if (retryCount < 3) {
setRetryCount(c => c + 1)
retry()
}
}
return ( return (
<ImageWithPlaceholderWhileLoading <ImageWithPlaceholderWhileLoading
src={url} src={urlWithTimestamp}
alt="feed favicon" alt="feed favicon"
width={size} width={size}
height={size} height={size}
@@ -16,6 +32,7 @@ export function FeedFavicon({ url, size = 18 }: Readonly<FeedFaviconProps>) {
placeholderHeight={size} placeholderHeight={size}
placeholderBackgroundColor="inherit" placeholderBackgroundColor="inherit"
placeholderIconSize={size} placeholderIconSize={size}
onError={handleError}
/> />
) )
} }

View File

@@ -1,7 +1,6 @@
import { msg } from "@lingui/core/macro" import { msg } from "@lingui/core/macro"
import { useLingui } from "@lingui/react" import { useLingui } from "@lingui/react"
import { Select, type SelectProps } from "@mantine/core" import { type ComboboxItem, Select, type SelectProps } from "@mantine/core"
import type { ComboboxItem } from "@mantine/core/lib/components/Combobox/Combobox.types"
import { Constants } from "@/app/constants" import { Constants } from "@/app/constants"
import { useAppSelector } from "@/app/store" import { useAppSelector } from "@/app/store"
import type { Category } from "@/app/types" import type { Category } from "@/app/types"

View File

@@ -1,20 +1,30 @@
import { Highlight } from "@mantine/core" import { Highlight } from "@mantine/core"
import { useAppSelector } from "@/app/store" import { useAppSelector } from "@/app/store"
import type { Entry } from "@/app/types" import type { Entry } from "@/app/types"
import { tss } from "@/tss"
export interface FeedEntryTitleProps { export interface FeedEntryTitleProps {
entry: Entry entry: Entry
} }
const useStyles = tss.create(() => ({
content: {
textWrap: "inherit",
},
}))
export function FeedEntryTitle(props: Readonly<FeedEntryTitleProps>) { export function FeedEntryTitle(props: Readonly<FeedEntryTitleProps>) {
const search = useAppSelector(state => state.entries.search) const search = useAppSelector(state => state.entries.search)
const keywords = search?.split(" ") const keywords = search?.split(" ")
const { classes } = useStyles()
return ( return (
<Highlight <Highlight
inherit inherit
highlight={keywords ?? ""} highlight={keywords ?? ""}
// make sure ellipsis is shown when title is too long // make sure ellipsis is shown when title is too long
span span
className={classes.content}
> >
{props.entry.title} {props.entry.title}
</Highlight> </Highlight>

View File

@@ -19,7 +19,7 @@ import {
} from "react-icons/tb" } from "react-icons/tb"
import { markAllAsReadWithConfirmationIfRequired, reloadEntries, search, selectNextEntry, selectPreviousEntry } from "@/app/entries/thunks" import { markAllAsReadWithConfirmationIfRequired, reloadEntries, search, selectNextEntry, selectPreviousEntry } from "@/app/entries/thunks"
import { useAppDispatch, useAppSelector } from "@/app/store" import { useAppDispatch, useAppSelector } from "@/app/store"
import { changeReadingMode, changeReadingOrder } from "@/app/user/thunks" import { changeSettings } from "@/app/user/thunks"
import { ActionButton } from "@/components/ActionButton" import { ActionButton } from "@/components/ActionButton"
import { Loader } from "@/components/Loader" import { Loader } from "@/components/Loader"
import { useActionButton } from "@/hooks/useActionButton" import { useActionButton } from "@/hooks/useActionButton"
@@ -73,6 +73,25 @@ export function Header() {
}, [setValues, searchFromStore]) }, [setValues, searchFromStore])
if (!settings) return <Loader /> if (!settings) return <Loader />
const toggleReadingMode = async () => {
await dispatch(
changeSettings({
readingMode: settings.readingMode === "all" ? "unread" : "all",
})
)
dispatch(reloadEntries())
}
const toggleReadingOrder = async () => {
await dispatch(
changeSettings({
readingOrder: settings.readingOrder === "asc" ? "desc" : "asc",
})
)
dispatch(reloadEntries())
}
return ( return (
<Center className="cf-toolbar-wrapper"> <Center className="cf-toolbar-wrapper">
<HeaderToolbar> <HeaderToolbar>
@@ -121,12 +140,12 @@ export function Header() {
<ActionButton <ActionButton
icon={settings.readingMode === "all" ? <TbEye size={iconSize} /> : <TbEyeOff size={iconSize} />} icon={settings.readingMode === "all" ? <TbEye size={iconSize} /> : <TbEyeOff size={iconSize} />}
label={settings.readingMode === "all" ? msg`All` : msg`Unread`} label={settings.readingMode === "all" ? msg`All` : msg`Unread`}
onClick={async () => await dispatch(changeReadingMode(settings.readingMode === "all" ? "unread" : "all"))} onClick={toggleReadingMode}
/> />
<ActionButton <ActionButton
icon={settings.readingOrder === "asc" ? <TbSortAscending size={iconSize} /> : <TbSortDescending size={iconSize} />} icon={settings.readingOrder === "asc" ? <TbSortAscending size={iconSize} /> : <TbSortDescending size={iconSize} />}
label={settings.readingOrder === "asc" ? msg`Asc` : msg`Desc`} label={settings.readingOrder === "asc" ? msg`Asc` : msg`Desc`}
onClick={async () => await dispatch(changeReadingOrder(settings.readingOrder === "asc" ? "desc" : "asc"))} onClick={toggleReadingOrder}
/> />
<Popover> <Popover>

View File

@@ -1,51 +1,29 @@
import { msg } from "@lingui/core/macro" import { msg } from "@lingui/core/macro"
import { useLingui } from "@lingui/react" import { useLingui } from "@lingui/react"
import { Trans } from "@lingui/react/macro" import { Trans } from "@lingui/react/macro"
import { Box, Divider, Group, NumberInput, Radio, Select, type SelectProps, SimpleGrid, Stack, Switch } from "@mantine/core" import {
import type { ComboboxData } from "@mantine/core/lib/components/Combobox/Combobox.types" Box,
type ComboboxData,
Divider,
Group,
Loader,
NumberInput,
Radio,
Select,
type SelectProps,
SimpleGrid,
Stack,
Switch,
} from "@mantine/core"
import type { ReactNode } from "react" import type { ReactNode } from "react"
import { Constants } from "@/app/constants" import { Constants } from "@/app/constants"
import { useAppDispatch, useAppSelector } from "@/app/store" import { useAppDispatch, useAppSelector } from "@/app/store"
import type { IconDisplayMode, ScrollMode, SharingSettings } from "@/app/types" import type { IconDisplayMode, ScrollMode, SharingSettings } from "@/app/types"
import { import { changeSettings } from "@/app/user/thunks"
changeCustomContextMenu,
changeDisablePullToRefresh,
changeEntriesToKeepOnTopWhenScrolling,
changeExternalLinkIconDisplayMode,
changeLanguage,
changeMarkAllAsReadConfirmation,
changeMarkAllAsReadNavigateToUnread,
changeMobileFooter,
changePrimaryColor,
changeScrollMarks,
changeScrollMode,
changeScrollSpeed,
changeSharingSetting,
changeShowRead,
changeStarIconDisplayMode,
changeUnreadCountFavicon,
changeUnreadCountTitle,
} from "@/app/user/thunks"
import { locales } from "@/i18n" import { locales } from "@/i18n"
export function DisplaySettings() { export function DisplaySettings() {
const language = useAppSelector(state => state.user.settings?.language) const settings = useAppSelector(state => state.user.settings)
const scrollSpeed = useAppSelector(state => state.user.settings?.scrollSpeed)
const showRead = useAppSelector(state => state.user.settings?.showRead)
const scrollMarks = useAppSelector(state => state.user.settings?.scrollMarks)
const scrollMode = useAppSelector(state => state.user.settings?.scrollMode)
const entriesToKeepOnTop = useAppSelector(state => state.user.settings?.entriesToKeepOnTopWhenScrolling)
const starIconDisplayMode = useAppSelector(state => state.user.settings?.starIconDisplayMode)
const externalLinkIconDisplayMode = useAppSelector(state => state.user.settings?.externalLinkIconDisplayMode)
const markAllAsReadConfirmation = useAppSelector(state => state.user.settings?.markAllAsReadConfirmation)
const markAllAsReadNavigateToNextUnread = useAppSelector(state => state.user.settings?.markAllAsReadNavigateToNextUnread)
const customContextMenu = useAppSelector(state => state.user.settings?.customContextMenu)
const mobileFooter = useAppSelector(state => state.user.settings?.mobileFooter)
const unreadCountTitle = useAppSelector(state => state.user.settings?.unreadCountTitle)
const unreadCountFavicon = useAppSelector(state => state.user.settings?.unreadCountFavicon)
const disablePullToRefresh = useAppSelector(state => state.user.settings?.disablePullToRefresh)
const sharingSettings = useAppSelector(state => state.user.settings?.sharingSettings)
const primaryColor = useAppSelector(state => state.user.settings?.primaryColor) || Constants.theme.defaultPrimaryColor
const { _ } = useLingui() const { _ } = useLingui()
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
@@ -97,50 +75,51 @@ export function DisplaySettings() {
</Group> </Group>
) )
if (!settings) return <Loader />
return ( return (
<Stack> <Stack>
<Divider label={<Trans>Display</Trans>} labelPosition="center" /> <Divider label={<Trans>Display</Trans>} labelPosition="center" />
<Select <Select
label={<Trans>Language</Trans>} label={<Trans>Language</Trans>}
value={language} value={settings.language}
data={locales.map(l => ({ data={locales.map(l => ({
value: l.key, value: l.key,
label: l.label, label: l.label,
}))} }))}
onChange={async s => await (s && dispatch(changeLanguage(s)))} onChange={language => language && dispatch(changeSettings({ language }))}
/> />
<Select <Select
label={<Trans>Primary color</Trans>} label={<Trans>Primary color</Trans>}
data={colorData} data={colorData}
value={primaryColor} value={settings.primaryColor}
onChange={async value => value && (await dispatch(changePrimaryColor(value)))} onChange={primaryColor => primaryColor && dispatch(changeSettings({ primaryColor }))}
renderOption={colorRenderer} renderOption={colorRenderer}
/> />
<Switch <Switch
label={<Trans>Show feeds and categories with no unread entries</Trans>} label={<Trans>Show feeds and categories with no unread entries</Trans>}
checked={showRead} checked={settings.showRead}
onChange={async e => await dispatch(changeShowRead(e.currentTarget.checked))} onChange={e => dispatch(changeSettings({ showRead: e.currentTarget.checked }))}
/> />
<Switch <Switch
label={<Trans>Show confirmation when marking all entries as read</Trans>} label={<Trans>Show confirmation when marking all entries as read</Trans>}
checked={markAllAsReadConfirmation} checked={settings.markAllAsReadConfirmation}
onChange={async e => await dispatch(changeMarkAllAsReadConfirmation(e.currentTarget.checked))} onChange={e => dispatch(changeSettings({ markAllAsReadConfirmation: e.currentTarget.checked }))}
/> />
<Switch <Switch
label={<Trans>Navigate to the next category/feed with unread entries when marking all entries as read</Trans>} label={<Trans>Navigate to the next category/feed with unread entries when marking all entries as read</Trans>}
checked={markAllAsReadNavigateToNextUnread} checked={settings.markAllAsReadNavigateToNextUnread}
onChange={async e => await dispatch(changeMarkAllAsReadNavigateToUnread(e.currentTarget.checked))} onChange={e => dispatch(changeSettings({ markAllAsReadNavigateToNextUnread: e.currentTarget.checked }))}
/> />
<Switch <Switch
label={<Trans>On mobile, show action buttons at the bottom of the screen</Trans>} label={<Trans>On mobile, show action buttons at the bottom of the screen</Trans>}
checked={mobileFooter} checked={settings.mobileFooter}
onChange={async e => await dispatch(changeMobileFooter(e.currentTarget.checked))} onChange={e => dispatch(changeSettings({ mobileFooter: e.currentTarget.checked }))}
/> />
<Divider label={<Trans>Scrolling</Trans>} labelPosition="center" /> <Divider label={<Trans>Scrolling</Trans>} labelPosition="center" />
@@ -148,14 +127,14 @@ export function DisplaySettings() {
<Switch <Switch
label={<Trans>Disable "Pull to refresh" browser behavior</Trans>} label={<Trans>Disable "Pull to refresh" browser behavior</Trans>}
description={<Trans>This setting can cause scrolling issues on some browsers (e.g. Safari)</Trans>} description={<Trans>This setting can cause scrolling issues on some browsers (e.g. Safari)</Trans>}
checked={disablePullToRefresh} checked={settings.disablePullToRefresh}
onChange={async e => await dispatch(changeDisablePullToRefresh(e.currentTarget.checked))} onChange={e => dispatch(changeSettings({ disablePullToRefresh: e.currentTarget.checked }))}
/> />
<Radio.Group <Radio.Group
label={<Trans>Scroll selected entry to the top of the page</Trans>} label={<Trans>Scroll selected entry to the top of the page</Trans>}
value={scrollMode} value={settings.scrollMode}
onChange={async value => await dispatch(changeScrollMode(value as ScrollMode))} onChange={value => dispatch(changeSettings({ scrollMode: value }))}
> >
<Group mt="xs"> <Group mt="xs">
{Object.entries(scrollModeOptions).map(e => ( {Object.entries(scrollModeOptions).map(e => (
@@ -168,56 +147,56 @@ export function DisplaySettings() {
label={<Trans>Entries to keep above the selected entry when scrolling</Trans>} label={<Trans>Entries to keep above the selected entry when scrolling</Trans>}
description={<Trans>Only applies to compact, cozy and detailed modes</Trans>} description={<Trans>Only applies to compact, cozy and detailed modes</Trans>}
min={0} min={0}
value={entriesToKeepOnTop} value={settings.entriesToKeepOnTopWhenScrolling}
onChange={async value => await dispatch(changeEntriesToKeepOnTopWhenScrolling(+value))} onChange={value => dispatch(changeSettings({ entriesToKeepOnTopWhenScrolling: +value }))}
/> />
<Switch <Switch
label={<Trans>Scroll smoothly when navigating between entries</Trans>} label={<Trans>Scroll smoothly when navigating between entries</Trans>}
checked={scrollSpeed ? scrollSpeed > 0 : false} checked={settings.scrollSpeed ? settings.scrollSpeed > 0 : false}
onChange={async e => await dispatch(changeScrollSpeed(e.currentTarget.checked))} onChange={e => dispatch(changeSettings({ scrollSpeed: e.currentTarget.checked ? 400 : 0 }))}
/> />
<Switch <Switch
label={<Trans>In expanded view, scrolling through entries mark them as read</Trans>} label={<Trans>In expanded view, scrolling through entries mark them as read</Trans>}
checked={scrollMarks} checked={settings.scrollMarks}
onChange={async e => await dispatch(changeScrollMarks(e.currentTarget.checked))} onChange={e => dispatch(changeSettings({ scrollMarks: e.currentTarget.checked }))}
/> />
<Divider label={<Trans>Browser tab</Trans>} labelPosition="center" /> <Divider label={<Trans>Browser tab</Trans>} labelPosition="center" />
<Switch <Switch
label={<Trans>Show unread count in tab title</Trans>} label={<Trans>Show unread count in tab title</Trans>}
checked={unreadCountTitle} checked={settings.unreadCountTitle}
onChange={async e => await dispatch(changeUnreadCountTitle(e.currentTarget.checked))} onChange={e => dispatch(changeSettings({ unreadCountTitle: e.currentTarget.checked }))}
/> />
<Switch <Switch
label={<Trans>Show unread count in tab favicon</Trans>} label={<Trans>Show unread count in tab favicon</Trans>}
checked={unreadCountFavicon} checked={settings.unreadCountFavicon}
onChange={async e => await dispatch(changeUnreadCountFavicon(e.currentTarget.checked))} onChange={e => dispatch(changeSettings({ unreadCountFavicon: e.currentTarget.checked }))}
/> />
<Divider label={<Trans>Entry headers</Trans>} labelPosition="center" /> <Divider label={<Trans>Entry headers</Trans>} labelPosition="center" />
<Select <Select
label={<Trans>Show star icon</Trans>} label={<Trans>Show star icon</Trans>}
value={starIconDisplayMode} value={settings.starIconDisplayMode}
data={displayModeData} data={displayModeData}
onChange={async s => await dispatch(changeStarIconDisplayMode(s as IconDisplayMode))} onChange={value => dispatch(changeSettings({ starIconDisplayMode: value as IconDisplayMode }))}
/> />
<Select <Select
label={<Trans>Show external link icon</Trans>} label={<Trans>Show external link icon</Trans>}
value={externalLinkIconDisplayMode} value={settings.externalLinkIconDisplayMode}
data={displayModeData} data={displayModeData}
onChange={async s => await dispatch(changeExternalLinkIconDisplayMode(s as IconDisplayMode))} onChange={value => dispatch(changeSettings({ externalLinkIconDisplayMode: value as IconDisplayMode }))}
/> />
<Switch <Switch
label={<Trans>Show CommaFeed's own context menu on right click</Trans>} label={<Trans>Show CommaFeed's own context menu on right click</Trans>}
checked={customContextMenu} checked={settings.customContextMenu}
onChange={async e => await dispatch(changeCustomContextMenu(e.currentTarget.checked))} onChange={e => dispatch(changeSettings({ customContextMenu: e.currentTarget.checked }))}
/> />
<Divider label={<Trans>Sharing sites</Trans>} labelPosition="center" /> <Divider label={<Trans>Sharing sites</Trans>} labelPosition="center" />
@@ -227,12 +206,14 @@ export function DisplaySettings() {
<Switch <Switch
key={site} key={site}
label={Constants.sharing[site].label} label={Constants.sharing[site].label}
checked={sharingSettings?.[site]} checked={settings.sharingSettings[site]}
onChange={async e => onChange={e =>
await dispatch( dispatch(
changeSharingSetting({ changeSettings({
site, sharingSettings: {
value: e.currentTarget.checked, ...settings.sharingSettings,
[site]: e.currentTarget.checked,
},
}) })
) )
} }

View File

@@ -10,7 +10,7 @@ import { client, errorToStrings } from "@/app/client"
import { redirectToSelectedSource } from "@/app/redirect/thunks" import { redirectToSelectedSource } from "@/app/redirect/thunks"
import { useAppDispatch, useAppSelector } from "@/app/store" import { useAppDispatch, useAppSelector } from "@/app/store"
import type { PushNotificationSettings as PushNotificationSettingsModel } from "@/app/types" import type { PushNotificationSettings as PushNotificationSettingsModel } from "@/app/types"
import { changePushNotificationSettings } from "@/app/user/thunks" import { changeSettings } from "@/app/user/thunks"
import { Alert } from "@/components/Alert" import { Alert } from "@/components/Alert"
export function PushNotificationSettings() { export function PushNotificationSettings() {
@@ -25,7 +25,7 @@ export function PushNotificationSettings() {
}, [form.initialize, notificationSettings]) }, [form.initialize, notificationSettings])
const handleSubmit = (values: PushNotificationSettingsModel) => { const handleSubmit = (values: PushNotificationSettingsModel) => {
dispatch(changePushNotificationSettings(values)) dispatch(changeSettings({ pushNotificationSettings: values }))
} }
const sendTestPushNotification = useAsyncCallback(client.user.sendTestPushNotification) const sendTestPushNotification = useAsyncCallback(client.user.sendTestPushNotification)

View File

@@ -6,7 +6,11 @@ const useStyles = tss.create(() => ({
badge: { badge: {
width: "3.2rem", width: "3.2rem",
// for some reason, mantine Badge has "cursor: 'default'" // for some reason, mantine Badge has "cursor: 'default'"
cursor: "pointer", cursor: "inherit",
},
indicator: {
// ensure the indicator is not shown above the app header
zIndex: 0,
}, },
})) }))
@@ -23,7 +27,15 @@ export function UnreadCount(
const count = props.unreadCount >= 10000 ? "10k+" : props.unreadCount const count = props.unreadCount >= 10000 ? "10k+" : props.unreadCount
return ( return (
<Tooltip label={props.unreadCount} disabled={props.unreadCount === count} openDelay={Constants.tooltip.delay}> <Tooltip label={props.unreadCount} disabled={props.unreadCount === count} openDelay={Constants.tooltip.delay}>
<Indicator disabled={!props.showIndicator} size={4} offset={10} position="middle-start"> <Indicator
disabled={!props.showIndicator}
size={4}
offset={10}
position="middle-start"
classNames={{
indicator: classes.indicator,
}}
>
<Badge className={`${classes.badge} cf-badge`} variant="light" fullWidth> <Badge className={`${classes.badge} cf-badge`} variant="light" fullWidth>
{count} {count}
</Badge> </Badge>

3
commafeed-client/src/globals.d.ts vendored Normal file
View File

@@ -0,0 +1,3 @@
// required because of noUncheckedSideEffectImports
// https://www.typescriptlang.org/tsconfig/#noUncheckedSideEffectImports
declare module "@fontsource/open-sans"

View File

@@ -60,7 +60,6 @@ msgstr "إضافة مستخدم"
msgid "Admin" msgid "Admin"
msgstr "إداري" msgstr "إداري"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "اسم مستخدم المسؤول" msgstr "اسم مستخدم المسؤول"
@@ -73,7 +72,6 @@ msgstr "اسم مستخدم المسؤول"
msgid "All" msgid "All"
msgstr "الكل" msgstr "الكل"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "دائمًا" msgstr "دائمًا"
@@ -173,18 +171,14 @@ msgstr "قم ببناء تعبير تصفية لتحديد ما تريد قرا
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "إلغاء" msgstr "إلغاء"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "تأكيد"
msgid "Confirm password" msgid "Confirm password"
msgstr "تأكيد كلمة المرور" msgstr "تأكيد كلمة المرور"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "تأكيد كلمة المرور" msgstr "تأكيد كلمة المرور"
@@ -294,7 +287,6 @@ msgstr "أيام"
msgid "Delete" msgid "Delete"
msgstr "حذف" msgstr "حذف"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "حذف الحساب" msgstr "حذف الحساب"
@@ -342,13 +334,10 @@ msgstr "اسحب الرابط إلى شريط الإشارات"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "البريد الإلكتروني" msgstr "البريد الإلكتروني"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "عنوان البريد الإلكتروني" msgstr "عنوان البريد الإلكتروني"
@@ -399,7 +388,6 @@ msgstr "خيارات الإضافة"
msgid "Feed name" msgid "Feed name"
msgstr "اسم الخلاصة" msgstr "اسم الخلاصة"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "تحميل الاشتراكات ..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "تحميل العلامات ..." msgstr "تحميل العلامات ..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "انتقل إلى اشتراك بإدخال اسمه"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "انتقل إلى الفئة/الخلاصة التالية التي تحتوي على إدخالات غير مقروءة عند تمييز الكل كمقروء" msgstr "انتقل إلى الفئة/الخلاصة التالية التي تحتوي على إدخالات غير مقروءة عند تمييز الكل كمقروء"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "أبدا" msgstr "أبدا"
@@ -657,7 +643,6 @@ msgstr "أبدا"
msgid "New password" msgid "New password"
msgstr "كلمة مرور جديدة" msgstr "كلمة مرور جديدة"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "كلمة مرور جديدة" msgstr "كلمة مرور جديدة"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "تصدير OPML" msgstr "تصدير OPML"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "ملف OPML" msgstr "ملف OPML"
@@ -791,10 +775,7 @@ msgstr "الفئة الأصل"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "كلمة المرور" msgstr "كلمة المرور"
@@ -874,7 +855,6 @@ msgstr "تحديث"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "تم إغلاق التسجيلات في مثيل CommaFeed هذا" msgstr "تم إغلاق التسجيلات في مثيل CommaFeed هذا"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "إعادة تعيين كلمة المرور" msgstr "إعادة تعيين كلمة المرور"
@@ -883,7 +863,6 @@ msgstr "إعادة تعيين كلمة المرور"
msgid "REST API" msgid "REST API"
msgstr "REST API" msgstr "REST API"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "نقرة بالزر الأيمن" msgstr "نقرة بالزر الأيمن"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "التمرير" msgstr "التمرير"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "بحث" msgstr "بحث"
@@ -924,7 +901,6 @@ msgstr "تحديد الخلاصة/الفئة التالية غير المقرو
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "تحديد الخلاصة/الفئة السابقة غير المقروءة" msgstr "تحديد الخلاصة/الفئة السابقة غير المقروءة"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "رابط الخادم" msgstr "رابط الخادم"
@@ -953,8 +929,6 @@ msgstr "مشاركة"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "مشاركة المواقع" msgstr "مشاركة المواقع"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "الحلقة" msgstr "الحلقة"
@@ -1003,7 +977,6 @@ msgstr "إظهار عدد غير المقروء في أيقونة التبويب
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "إظهار عدد غير المقروء في عنوان التبويب" msgstr "إظهار عدد غير المقروء في عنوان التبويب"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "قم بالتسجيل"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "شيء سيء حدث للتو ..." msgstr "شيء سيء حدث للتو ..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "فضاء" msgstr "فضاء"
@@ -1030,7 +1002,6 @@ msgstr "النجم"
msgid "Starred" msgid "Starred"
msgstr "مميز بنجمة" msgstr "مميز بنجمة"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "قم بالتبديل إلى النسق الفاتح"
msgid "System" msgid "System"
msgstr "النظام" msgstr "النظام"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "الكلمات" msgstr "الكلمات"
@@ -1136,7 +1106,6 @@ msgstr "غير مقروءة"
msgid "Unstar" msgid "Unstar"
msgstr "إلغاء النجم" msgstr "إلغاء النجم"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "إلغاء الاشتراك" msgstr "إلغاء الاشتراك"
@@ -1149,7 +1118,6 @@ msgstr "مفتاح المستخدم"
msgid "User name" msgid "User name"
msgstr "اسم المستخدم" msgstr "اسم المستخدم"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "اسم المستخدم أو البريد الإلكتروني" msgstr "اسم المستخدم أو البريد الإلكتروني"

View File

@@ -60,7 +60,6 @@ msgstr "Afegeix usuari"
msgid "Admin" msgid "Admin"
msgstr "Administrador" msgstr "Administrador"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "Nom d'usuari de l'administrador" msgstr "Nom d'usuari de l'administrador"
@@ -73,7 +72,6 @@ msgstr "Nom d'usuari de l'administrador"
msgid "All" msgid "All"
msgstr "Tot" msgstr "Tot"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "Sempre" msgstr "Sempre"
@@ -173,18 +171,14 @@ msgstr "Creeu una expressió de filtratge per indicar què voleu llegir. Les ent
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "Cancel·la" msgstr "Cancel·la"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "Confirma"
msgid "Confirm password" msgid "Confirm password"
msgstr "Confirmeu la contrasenya" msgstr "Confirmeu la contrasenya"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "Confirma la contrasenya" msgstr "Confirma la contrasenya"
@@ -294,7 +287,6 @@ msgstr "dies"
msgid "Delete" msgid "Delete"
msgstr "Eliminar" msgstr "Eliminar"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "Suprimeix el compte" msgstr "Suprimeix el compte"
@@ -342,13 +334,10 @@ msgstr "Arrossegueu l'enllaç a la barra d'adreces d'interès"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "Correu electrònic" msgstr "Correu electrònic"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "Adreça de correu electrònic" msgstr "Adreça de correu electrònic"
@@ -399,7 +388,6 @@ msgstr "Opcions de l'extensió"
msgid "Feed name" msgid "Feed name"
msgstr "Nom del canal" msgstr "Nom del canal"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "S'estan carregant les subscripcions..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "Carregant les etiquetes..." msgstr "Carregant les etiquetes..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "Navegueu a una subscripció introduint-ne el nom"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "Navega a la següent categoria/canal amb entrades no llegides quan es marquen totes les entrades com a llegides" msgstr "Navega a la següent categoria/canal amb entrades no llegides quan es marquen totes les entrades com a llegides"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "Mai" msgstr "Mai"
@@ -657,7 +643,6 @@ msgstr "Mai"
msgid "New password" msgid "New password"
msgstr "Contrasenya nova" msgstr "Contrasenya nova"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "Contrasenya nova" msgstr "Contrasenya nova"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "Exportació OPML" msgstr "Exportació OPML"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "Fitxer OPML" msgstr "Fitxer OPML"
@@ -791,10 +775,7 @@ msgstr "Categoria pare"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "Contrasenya" msgstr "Contrasenya"
@@ -874,7 +855,6 @@ msgstr "Actualitzar"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "Els registres estan tancats en aquesta instància de CommaFeed" msgstr "Els registres estan tancats en aquesta instància de CommaFeed"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "Restableix la contrasenya" msgstr "Restableix la contrasenya"
@@ -883,7 +863,6 @@ msgstr "Restableix la contrasenya"
msgid "REST API" msgid "REST API"
msgstr "API REST" msgstr "API REST"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "Clic dret" msgstr "Clic dret"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "Desplaçament" msgstr "Desplaçament"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "Cerca" msgstr "Cerca"
@@ -924,7 +901,6 @@ msgstr "Selecciona el següent canal/categoria no llegit"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "Selecciona el canal/categoria anterior sense llegir" msgstr "Selecciona el canal/categoria anterior sense llegir"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "URL del servidor" msgstr "URL del servidor"
@@ -953,8 +929,6 @@ msgstr "Comparteix"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "Compartir a altres llocs web" msgstr "Compartir a altres llocs web"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "canvi" msgstr "canvi"
@@ -1003,7 +977,6 @@ msgstr "Mostra el recompte de no llegits a la icona de favorits de la pestanya"
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "Mostra el recompte de no llegits al títol de la pestanya" msgstr "Mostra el recompte de no llegits al títol de la pestanya"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "Registra't"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "Acaba de passar una cosa dolenta..." msgstr "Acaba de passar una cosa dolenta..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "Espai" msgstr "Espai"
@@ -1030,7 +1002,6 @@ msgstr "Estrella"
msgid "Starred" msgid "Starred"
msgstr "Estrellat" msgstr "Estrellat"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "Canvia al tema clar"
msgid "System" msgid "System"
msgstr "Sistema" msgstr "Sistema"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "Etiquetes" msgstr "Etiquetes"
@@ -1136,7 +1106,6 @@ msgstr "Sense llegir"
msgid "Unstar" msgid "Unstar"
msgstr "Desestrellar" msgstr "Desestrellar"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "Donar-se de baixa" msgstr "Donar-se de baixa"
@@ -1149,7 +1118,6 @@ msgstr "Clau d'usuari"
msgid "User name" msgid "User name"
msgstr "Nom d'usuari" msgstr "Nom d'usuari"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "Nom d'usuari o correu electrònic" msgstr "Nom d'usuari o correu electrònic"

View File

@@ -60,7 +60,6 @@ msgstr "Přidat uživatele"
msgid "Admin" msgid "Admin"
msgstr "Správce" msgstr "Správce"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "Uživatelské jméno správce" msgstr "Uživatelské jméno správce"
@@ -73,7 +72,6 @@ msgstr "Uživatelské jméno správce"
msgid "All" msgid "All"
msgstr "Všechny" msgstr "Všechny"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "Vždy" msgstr "Vždy"
@@ -173,18 +171,14 @@ msgstr "Vytvořte výraz filtru pro určení toho, co chcete číst. Položky, k
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "Zrušit" msgstr "Zrušit"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "Potvrdit"
msgid "Confirm password" msgid "Confirm password"
msgstr "Potvrďte heslo" msgstr "Potvrďte heslo"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "Potvrdit heslo" msgstr "Potvrdit heslo"
@@ -294,7 +287,6 @@ msgstr "dní"
msgid "Delete" msgid "Delete"
msgstr "Smazat" msgstr "Smazat"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "Smazat účet" msgstr "Smazat účet"
@@ -342,13 +334,10 @@ msgstr "Přetáhněte odkaz na lištu záložek"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "E-mail" msgstr "E-mail"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "E-mailová adresa" msgstr "E-mailová adresa"
@@ -399,7 +388,6 @@ msgstr "Možnosti rozšíření"
msgid "Feed name" msgid "Feed name"
msgstr "Název zdroje" msgstr "Název zdroje"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "Načítání odběrů..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "Načítání značek..." msgstr "Načítání značek..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "Přejděte na předplatné zadáním jeho názvu"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "Po označení všech položek jako přečtených přejít na další kategorii/zdroj s nepřečtenými položkami" msgstr "Po označení všech položek jako přečtených přejít na další kategorii/zdroj s nepřečtenými položkami"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "Nikdy" msgstr "Nikdy"
@@ -657,7 +643,6 @@ msgstr "Nikdy"
msgid "New password" msgid "New password"
msgstr "Nové heslo" msgstr "Nové heslo"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "Nové heslo" msgstr "Nové heslo"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "Export OPML" msgstr "Export OPML"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "soubor OPML" msgstr "soubor OPML"
@@ -791,10 +775,7 @@ msgstr "Rodičovská kategorie"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "Heslo" msgstr "Heslo"
@@ -874,7 +855,6 @@ msgstr "Obnovit"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "V této instanci CommaFeed jsou registrace uzavřeny" msgstr "V této instanci CommaFeed jsou registrace uzavřeny"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "Obnovit heslo" msgstr "Obnovit heslo"
@@ -883,7 +863,6 @@ msgstr "Obnovit heslo"
msgid "REST API" msgid "REST API"
msgstr "REST API" msgstr "REST API"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "Kliknutí pravým tlačítkem" msgstr "Kliknutí pravým tlačítkem"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "Posouvání" msgstr "Posouvání"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "Hledej" msgstr "Hledej"
@@ -924,7 +901,6 @@ msgstr "Vybrat další nepřečtený zdroj/kategorii"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "Vybrat předchozí nepřečtený zdroj/kategorii" msgstr "Vybrat předchozí nepřečtený zdroj/kategorii"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "URL serveru" msgstr "URL serveru"
@@ -953,8 +929,6 @@ msgstr "Sdílejte"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "Stránky pro sdílení" msgstr "Stránky pro sdílení"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "Směna" msgstr "Směna"
@@ -1003,7 +977,6 @@ msgstr "Zobrazovat počet nepřečtených v ikoně karty"
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "Zobrazovat počet nepřečtených v názvu karty" msgstr "Zobrazovat počet nepřečtených v názvu karty"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "Zaregistrovat se"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "Právě se stalo něco špatného..." msgstr "Právě se stalo něco špatného..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "Vesmír" msgstr "Vesmír"
@@ -1030,7 +1002,6 @@ msgstr "Hvězda"
msgid "Starred" msgid "Starred"
msgstr "S hvězdičkou" msgstr "S hvězdičkou"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "Přepnout na světlý motiv"
msgid "System" msgid "System"
msgstr "Systémový" msgstr "Systémový"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "Štítky" msgstr "Štítky"
@@ -1136,7 +1106,6 @@ msgstr "Nepřečteno"
msgid "Unstar" msgid "Unstar"
msgstr "Odstranit hvězdu" msgstr "Odstranit hvězdu"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "Odhlásit odběr" msgstr "Odhlásit odběr"
@@ -1149,7 +1118,6 @@ msgstr "Uživatelský klíč"
msgid "User name" msgid "User name"
msgstr "Uživatelské jméno" msgstr "Uživatelské jméno"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "Uživatelské jméno nebo e-mail" msgstr "Uživatelské jméno nebo e-mail"

View File

@@ -60,7 +60,6 @@ msgstr "Ychwanegu defnyddiwr"
msgid "Admin" msgid "Admin"
msgstr "Gweinyddol" msgstr "Gweinyddol"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "Enw defnyddiwr gweinyddwr" msgstr "Enw defnyddiwr gweinyddwr"
@@ -73,7 +72,6 @@ msgstr "Enw defnyddiwr gweinyddwr"
msgid "All" msgid "All"
msgstr "Pawb" msgstr "Pawb"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "Bob amser" msgstr "Bob amser"
@@ -173,18 +171,14 @@ msgstr "Adeiladwch fynegiant hidlo i nodi'r hyn rydych chi am ei ddarllen. Bydd
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "Diddymu" msgstr "Diddymu"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "Cadarnhau"
msgid "Confirm password" msgid "Confirm password"
msgstr "Cadarnhau'r cyfrinair" msgstr "Cadarnhau'r cyfrinair"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "Cadarnhau Cyfrinair" msgstr "Cadarnhau Cyfrinair"
@@ -294,7 +287,6 @@ msgstr "diwrnodau"
msgid "Delete" msgid "Delete"
msgstr "Dileu" msgstr "Dileu"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "Dileu cyfrif" msgstr "Dileu cyfrif"
@@ -342,13 +334,10 @@ msgstr "Llusgwch y ddolen i'r bar nod tudalen"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "E-bost" msgstr "E-bost"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "cyfeiriad e-bost" msgstr "cyfeiriad e-bost"
@@ -399,7 +388,6 @@ msgstr "Opsiynau estyniad"
msgid "Feed name" msgid "Feed name"
msgstr "Enw porthiant" msgstr "Enw porthiant"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "Yn llwytho tanysgrifiadau..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "Wrthi'n llwytho tagiau..." msgstr "Wrthi'n llwytho tagiau..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "Llywiwch i danysgrifiad trwy nodi ei enw"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "Llywiwch i'r categori/porthiant nesaf gyda chofnodion heb eu darllen wrth farcio pob cofnod fel un wedi'i ddarllen" msgstr "Llywiwch i'r categori/porthiant nesaf gyda chofnodion heb eu darllen wrth farcio pob cofnod fel un wedi'i ddarllen"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "Byth" msgstr "Byth"
@@ -657,7 +643,6 @@ msgstr "Byth"
msgid "New password" msgid "New password"
msgstr "Cyfrinair newydd" msgstr "Cyfrinair newydd"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "Cyfrinair Newydd" msgstr "Cyfrinair Newydd"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "Allforio OPML" msgstr "Allforio OPML"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "Ffeil OPML" msgstr "Ffeil OPML"
@@ -791,10 +775,7 @@ msgstr "Categori Rhiant"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "cyfrinair" msgstr "cyfrinair"
@@ -874,7 +855,6 @@ msgstr "Adnewyddu"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "Mae cofrestriadau ar gau ar yr achos CommaFeed hwn" msgstr "Mae cofrestriadau ar gau ar yr achos CommaFeed hwn"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "Ailosod Cyfrinair" msgstr "Ailosod Cyfrinair"
@@ -883,7 +863,6 @@ msgstr "Ailosod Cyfrinair"
msgid "REST API" msgid "REST API"
msgstr "REST API" msgstr "REST API"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "Clic dde" msgstr "Clic dde"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "Sgrolio" msgstr "Sgrolio"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "Chwilio" msgstr "Chwilio"
@@ -924,7 +901,6 @@ msgstr "Dewiswch y porthiant/categori nesaf heb ei ddarllen"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "Dewiswch y porthiant/categori blaenorol heb ei ddarllen" msgstr "Dewiswch y porthiant/categori blaenorol heb ei ddarllen"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "URL y gweinydd" msgstr "URL y gweinydd"
@@ -953,8 +929,6 @@ msgstr "Rhannu"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "Rhannu gwefannau" msgstr "Rhannu gwefannau"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "shifft" msgstr "shifft"
@@ -1003,7 +977,6 @@ msgstr "Dangos nifer heb ei ddarllen yn ffaficon y tab"
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "Dangos nifer heb ei ddarllen yn nheitl y tab" msgstr "Dangos nifer heb ei ddarllen yn nheitl y tab"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "Cofrestrwch"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "Mae rhywbeth drwg newydd ddigwydd ..." msgstr "Mae rhywbeth drwg newydd ddigwydd ..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "Gofod" msgstr "Gofod"
@@ -1030,7 +1002,6 @@ msgstr "seren"
msgid "Starred" msgid "Starred"
msgstr "serennog" msgstr "serennog"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "Newid i thema golau"
msgid "System" msgid "System"
msgstr "System" msgstr "System"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "Tagiau" msgstr "Tagiau"
@@ -1136,7 +1106,6 @@ msgstr "Heb ei ddarllen"
msgid "Unstar" msgid "Unstar"
msgstr "dad-seren" msgstr "dad-seren"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "Dad-danysgrifio" msgstr "Dad-danysgrifio"
@@ -1149,7 +1118,6 @@ msgstr "Allwedd defnyddiwr"
msgid "User name" msgid "User name"
msgstr "Enw defnyddiwr" msgstr "Enw defnyddiwr"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "Enw Defnyddiwr neu E-bost" msgstr "Enw Defnyddiwr neu E-bost"

View File

@@ -60,7 +60,6 @@ msgstr "Tilføj bruger"
msgid "Admin" msgid "Admin"
msgstr "Administrator" msgstr "Administrator"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "Administrator brugernavn" msgstr "Administrator brugernavn"
@@ -73,7 +72,6 @@ msgstr "Administrator brugernavn"
msgid "All" msgid "All"
msgstr "Alle" msgstr "Alle"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "Altid" msgstr "Altid"
@@ -173,18 +171,14 @@ msgstr "Byg et filterudtryk for at angive, hvad du vil læse. Indlæg, der ikke
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "Annuller" msgstr "Annuller"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "Bekræft"
msgid "Confirm password" msgid "Confirm password"
msgstr "Bekræft adgangskode" msgstr "Bekræft adgangskode"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "Bekræft adgangskode" msgstr "Bekræft adgangskode"
@@ -294,7 +287,6 @@ msgstr "dage"
msgid "Delete" msgid "Delete"
msgstr "Slet" msgstr "Slet"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "Slet konto" msgstr "Slet konto"
@@ -342,13 +334,10 @@ msgstr "Træk linket til bogmærkelinjen"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "E-mail" msgstr "E-mail"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "E-mailadresse" msgstr "E-mailadresse"
@@ -399,7 +388,6 @@ msgstr "Indstillinger for udvidelse"
msgid "Feed name" msgid "Feed name"
msgstr "Feednavn" msgstr "Feednavn"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "Indlæser abonnementer..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "Indlæser tags..." msgstr "Indlæser tags..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "Naviger til et abonnement ved at indtaste dets navn"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "Naviger til næste kategori/feed med ulæste indlæg, når alle indlæg markeres som læst" msgstr "Naviger til næste kategori/feed med ulæste indlæg, når alle indlæg markeres som læst"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "Aldrig" msgstr "Aldrig"
@@ -657,7 +643,6 @@ msgstr "Aldrig"
msgid "New password" msgid "New password"
msgstr "Ny adgangskode" msgstr "Ny adgangskode"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "Ny adgangskode" msgstr "Ny adgangskode"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "OPML eksport" msgstr "OPML eksport"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "OPML fil" msgstr "OPML fil"
@@ -791,10 +775,7 @@ msgstr "Forældrekategori"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "Adgangskode" msgstr "Adgangskode"
@@ -874,7 +855,6 @@ msgstr "Opdater"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "Registreringer er lukket på denne CommaFeed-instans" msgstr "Registreringer er lukket på denne CommaFeed-instans"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "Nulstil adgangskode" msgstr "Nulstil adgangskode"
@@ -883,7 +863,6 @@ msgstr "Nulstil adgangskode"
msgid "REST API" msgid "REST API"
msgstr "REST API" msgstr "REST API"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "Højreklik" msgstr "Højreklik"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "Rulning" msgstr "Rulning"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "Søg" msgstr "Søg"
@@ -924,7 +901,6 @@ msgstr "Vælg næste ulæste feed/kategori"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "Vælg forrige ulæste feed/kategori" msgstr "Vælg forrige ulæste feed/kategori"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "Server-URL" msgstr "Server-URL"
@@ -953,8 +929,6 @@ msgstr "Del"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "Delingssider" msgstr "Delingssider"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "Skift" msgstr "Skift"
@@ -1003,7 +977,6 @@ msgstr "Vis ulæst antal i fanens favicon"
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "Vis ulæst antal i fanens titel" msgstr "Vis ulæst antal i fanens titel"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "Tilmeld dig"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "Der er lige sket noget slemt..." msgstr "Der er lige sket noget slemt..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "Rum" msgstr "Rum"
@@ -1030,7 +1002,6 @@ msgstr "Stjerne"
msgid "Starred" msgid "Starred"
msgstr "Medvirkende" msgstr "Medvirkende"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "Skift til lystema"
msgid "System" msgid "System"
msgstr "System" msgstr "System"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "Tags" msgstr "Tags"
@@ -1136,7 +1106,6 @@ msgstr "Ulæst"
msgid "Unstar" msgid "Unstar"
msgstr "Fjern stjerne" msgstr "Fjern stjerne"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "Afmeld" msgstr "Afmeld"
@@ -1149,7 +1118,6 @@ msgstr "Brugernøgle"
msgid "User name" msgid "User name"
msgstr "Brugernavn" msgstr "Brugernavn"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "Brugernavn eller e-mail" msgstr "Brugernavn eller e-mail"

View File

@@ -60,7 +60,6 @@ msgstr "Benutzer hinzufügen"
msgid "Admin" msgid "Admin"
msgstr "Verwaltung" msgstr "Verwaltung"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "Administrator-Benutzername" msgstr "Administrator-Benutzername"
@@ -73,7 +72,6 @@ msgstr "Administrator-Benutzername"
msgid "All" msgid "All"
msgstr "Alle" msgstr "Alle"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "Immer" msgstr "Immer"
@@ -173,18 +171,14 @@ msgstr "Erstellen Sie einen Filterausdruck, um anzugeben, was Sie lesen möchten
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "Abbrechen" msgstr "Abbrechen"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "Bestätigen"
msgid "Confirm password" msgid "Confirm password"
msgstr "Passwort bestätigen" msgstr "Passwort bestätigen"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "Passwort bestätigen" msgstr "Passwort bestätigen"
@@ -294,7 +287,6 @@ msgstr "Tage"
msgid "Delete" msgid "Delete"
msgstr "Löschen" msgstr "Löschen"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "Konto löschen" msgstr "Konto löschen"
@@ -342,13 +334,10 @@ msgstr "Link in Lesezeichenleiste ziehen"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "E-Mail" msgstr "E-Mail"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "E-Mail-Adresse" msgstr "E-Mail-Adresse"
@@ -399,7 +388,6 @@ msgstr "Erweiterungsoptionen"
msgid "Feed name" msgid "Feed name"
msgstr "Feedname" msgstr "Feedname"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "Abonnements werden geladen..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "Tags werden geladen..." msgstr "Tags werden geladen..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "Navigieren Sie zu einem Abonnement, indem Sie seinen Namen eingeben"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "Navigieren Sie zum nächsten Feed/Kategorie mit ungelesenen Einträgen, wenn Sie alle Einträge als gelesen markieren" msgstr "Navigieren Sie zum nächsten Feed/Kategorie mit ungelesenen Einträgen, wenn Sie alle Einträge als gelesen markieren"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "Niemals" msgstr "Niemals"
@@ -657,7 +643,6 @@ msgstr "Niemals"
msgid "New password" msgid "New password"
msgstr "Neues Passwort" msgstr "Neues Passwort"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "Neues Passwort" msgstr "Neues Passwort"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "OPML-Export" msgstr "OPML-Export"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "OPML-Datei" msgstr "OPML-Datei"
@@ -791,10 +775,7 @@ msgstr "Übergeordnete Kategorie"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "Passwort" msgstr "Passwort"
@@ -874,7 +855,6 @@ msgstr "Aktualisieren"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "Registrierungen sind für diese CommaFeed-Instanz geschlossen" msgstr "Registrierungen sind für diese CommaFeed-Instanz geschlossen"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "Passwort zurücksetzen" msgstr "Passwort zurücksetzen"
@@ -883,7 +863,6 @@ msgstr "Passwort zurücksetzen"
msgid "REST API" msgid "REST API"
msgstr "REST-API" msgstr "REST-API"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "Rechtsklick" msgstr "Rechtsklick"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "Scrollen" msgstr "Scrollen"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "Suche" msgstr "Suche"
@@ -924,7 +901,6 @@ msgstr "Nächsten ungelesenen Feed/Kategorie auswählen"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "Vorherigen ungelesenen Feed/Kategorie auswählen" msgstr "Vorherigen ungelesenen Feed/Kategorie auswählen"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "Server-URL" msgstr "Server-URL"
@@ -953,8 +929,6 @@ msgstr "Teilen"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "Seiten teilen" msgstr "Seiten teilen"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "Verschiebung" msgstr "Verschiebung"
@@ -1003,7 +977,6 @@ msgstr "Anzahl ungelesener Nachrichten im Tab-Favicon anzeigen"
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "Anzahl ungelesener Nachrichten im Tab-Titel anzeigen" msgstr "Anzahl ungelesener Nachrichten im Tab-Titel anzeigen"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "Melden Sie sich an"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "Etwas Schlimmes ist gerade passiert..." msgstr "Etwas Schlimmes ist gerade passiert..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "Raum" msgstr "Raum"
@@ -1030,7 +1002,6 @@ msgstr "Stern"
msgid "Starred" msgid "Starred"
msgstr "Markiert" msgstr "Markiert"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "Zum Lightmode wechseln"
msgid "System" msgid "System"
msgstr "System" msgstr "System"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "Tags" msgstr "Tags"
@@ -1136,7 +1106,6 @@ msgstr "Ungelesen"
msgid "Unstar" msgid "Unstar"
msgstr "Stern entfernen" msgstr "Stern entfernen"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "Abbestellen" msgstr "Abbestellen"
@@ -1149,7 +1118,6 @@ msgstr "Benutzerschlüssel"
msgid "User name" msgid "User name"
msgstr "Benutzername" msgstr "Benutzername"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "Benutzername oder E-Mail" msgstr "Benutzername oder E-Mail"

View File

@@ -60,7 +60,6 @@ msgstr "Add user"
msgid "Admin" msgid "Admin"
msgstr "Admin" msgstr "Admin"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "Admin user name" msgstr "Admin user name"
@@ -73,7 +72,6 @@ msgstr "Admin user name"
msgid "All" msgid "All"
msgstr "All" msgstr "All"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "Always" msgstr "Always"
@@ -173,18 +171,14 @@ msgstr "Build a filter expression to indicate what you want to read. Entries tha
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "Cancel" msgstr "Cancel"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "Confirm"
msgid "Confirm password" msgid "Confirm password"
msgstr "Confirm password" msgstr "Confirm password"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "Confirm Password" msgstr "Confirm Password"
@@ -294,7 +287,6 @@ msgstr "days"
msgid "Delete" msgid "Delete"
msgstr "Delete" msgstr "Delete"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "Delete account" msgstr "Delete account"
@@ -342,13 +334,10 @@ msgstr "Drag link to bookmark bar"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "E-mail" msgstr "E-mail"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "E-mail address" msgstr "E-mail address"
@@ -399,7 +388,6 @@ msgstr "Extension options"
msgid "Feed name" msgid "Feed name"
msgstr "Feed name" msgstr "Feed name"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "Loading subscriptions..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "Loading tags..." msgstr "Loading tags..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "Navigate to a subscription by entering its name"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "Navigate to the next category/feed with unread entries when marking all entries as read" msgstr "Navigate to the next category/feed with unread entries when marking all entries as read"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "Never" msgstr "Never"
@@ -657,7 +643,6 @@ msgstr "Never"
msgid "New password" msgid "New password"
msgstr "New password" msgstr "New password"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "New Password" msgstr "New Password"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "OPML export" msgstr "OPML export"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "OPML file" msgstr "OPML file"
@@ -791,10 +775,7 @@ msgstr "Parent Category"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "Password" msgstr "Password"
@@ -874,7 +855,6 @@ msgstr "Refresh"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "Registrations are closed on this CommaFeed instance" msgstr "Registrations are closed on this CommaFeed instance"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "Reset Password" msgstr "Reset Password"
@@ -883,7 +863,6 @@ msgstr "Reset Password"
msgid "REST API" msgid "REST API"
msgstr "REST API" msgstr "REST API"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "Right click" msgstr "Right click"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "Scrolling" msgstr "Scrolling"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "Search" msgstr "Search"
@@ -924,7 +901,6 @@ msgstr "Select next unread feed/category"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "Select previous unread feed/category" msgstr "Select previous unread feed/category"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "Server URL" msgstr "Server URL"
@@ -953,8 +929,6 @@ msgstr "Share"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "Sharing sites" msgstr "Sharing sites"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "Shift" msgstr "Shift"
@@ -1003,7 +977,6 @@ msgstr "Show unread count in tab favicon"
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "Show unread count in tab title" msgstr "Show unread count in tab title"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "Sign up"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "Something bad just happened..." msgstr "Something bad just happened..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "Space" msgstr "Space"
@@ -1030,7 +1002,6 @@ msgstr "Star"
msgid "Starred" msgid "Starred"
msgstr "Starred" msgstr "Starred"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "Switch to light theme"
msgid "System" msgid "System"
msgstr "System" msgstr "System"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "Tags" msgstr "Tags"
@@ -1136,7 +1106,6 @@ msgstr "Unread"
msgid "Unstar" msgid "Unstar"
msgstr "Unstar" msgstr "Unstar"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "Unsubscribe" msgstr "Unsubscribe"
@@ -1149,7 +1118,6 @@ msgstr "User key"
msgid "User name" msgid "User name"
msgstr "User name" msgstr "User name"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "User Name or E-mail" msgstr "User Name or E-mail"

View File

@@ -61,7 +61,6 @@ msgstr "Añadir usuario"
msgid "Admin" msgid "Admin"
msgstr "Administrador" msgstr "Administrador"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "Nombre de usuario administrador" msgstr "Nombre de usuario administrador"
@@ -74,7 +73,6 @@ msgstr "Nombre de usuario administrador"
msgid "All" msgid "All"
msgstr "Todo" msgstr "Todo"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "Siempre" msgstr "Siempre"
@@ -174,18 +172,14 @@ msgstr "Crea una expresión de filtrado para indicar lo que quieres leer. Las en
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "Cancelar" msgstr "Cancelar"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -241,7 +235,6 @@ msgstr "Confirmar"
msgid "Confirm password" msgid "Confirm password"
msgstr "Confirmar contraseña" msgstr "Confirmar contraseña"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "Confirmar contraseña" msgstr "Confirmar contraseña"
@@ -295,7 +288,6 @@ msgstr "días"
msgid "Delete" msgid "Delete"
msgstr "Borrar" msgstr "Borrar"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "Borrar cuenta" msgstr "Borrar cuenta"
@@ -343,13 +335,10 @@ msgstr "Arrastra el enlace a la barra de marcadores"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "Correo electrónico" msgstr "Correo electrónico"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "Dirección de correo electrónico" msgstr "Dirección de correo electrónico"
@@ -400,7 +389,6 @@ msgstr "Opciones de la extensión"
msgid "Feed name" msgid "Feed name"
msgstr "Nombre del feed" msgstr "Nombre del feed"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -571,7 +559,6 @@ msgstr "Cargando suscripciones..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "Cargando etiquetas..." msgstr "Cargando etiquetas..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -649,7 +636,6 @@ msgstr "Navegar a una suscripción introduciendo su nombre"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "Navegar a la siguiente categoría/feed con entradas no leídas al marcar todas como leídas" msgstr "Navegar a la siguiente categoría/feed con entradas no leídas al marcar todas como leídas"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "Nunca" msgstr "Nunca"
@@ -658,7 +644,6 @@ msgstr "Nunca"
msgid "New password" msgid "New password"
msgstr "Nueva contraseña" msgstr "Nueva contraseña"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "Nueva contraseña" msgstr "Nueva contraseña"
@@ -765,7 +750,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "Exportar OPML" msgstr "Exportar OPML"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "Archivo OPML" msgstr "Archivo OPML"
@@ -792,10 +776,7 @@ msgstr "Categoría principal"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "Contraseña" msgstr "Contraseña"
@@ -875,7 +856,6 @@ msgstr "Actualizar"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "Los registros están cerrados en esta instancia de CommaFeed" msgstr "Los registros están cerrados en esta instancia de CommaFeed"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "Restablecer contraseña" msgstr "Restablecer contraseña"
@@ -884,7 +864,6 @@ msgstr "Restablecer contraseña"
msgid "REST API" msgid "REST API"
msgstr "API REST" msgstr "API REST"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "Clic derecho" msgstr "Clic derecho"
@@ -911,8 +890,6 @@ msgid "Scrolling"
msgstr "Desplazarse" msgstr "Desplazarse"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "Buscar" msgstr "Buscar"
@@ -925,7 +902,6 @@ msgstr "Seleccionar el siguiente feed/categoría no leído"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "Seleccionar el anterior feed/categoría no leído" msgstr "Seleccionar el anterior feed/categoría no leído"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "URL del servidor" msgstr "URL del servidor"
@@ -954,8 +930,6 @@ msgstr "Compartir"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "Compartir sitios" msgstr "Compartir sitios"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "Shift" msgstr "Shift"
@@ -1004,7 +978,6 @@ msgstr "Mostrar recuento de no leídos en la pestaña favicon"
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "Mostrar recuento de no leídos en el título de la pestaña" msgstr "Mostrar recuento de no leídos en el título de la pestaña"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1014,7 +987,6 @@ msgstr "Registrarse"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "Algo malo acaba de pasar..." msgstr "Algo malo acaba de pasar..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "Espacio" msgstr "Espacio"
@@ -1031,7 +1003,6 @@ msgstr "Estrella"
msgid "Starred" msgid "Starred"
msgstr "Destacado" msgstr "Destacado"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1065,7 +1036,6 @@ msgstr "Cambiar a tema claro"
msgid "System" msgid "System"
msgstr "Sistema" msgstr "Sistema"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "Etiquetas" msgstr "Etiquetas"
@@ -1137,7 +1107,6 @@ msgstr "No leído"
msgid "Unstar" msgid "Unstar"
msgstr "Desmarcar" msgstr "Desmarcar"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "Cancelar suscripción" msgstr "Cancelar suscripción"
@@ -1150,7 +1119,6 @@ msgstr "Clave de usuario"
msgid "User name" msgid "User name"
msgstr "Nombre de usuario" msgstr "Nombre de usuario"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "Nombre de usuario o correo electrónico" msgstr "Nombre de usuario o correo electrónico"

View File

@@ -60,7 +60,6 @@ msgstr "افزودن کاربر"
msgid "Admin" msgid "Admin"
msgstr "مدیر" msgstr "مدیر"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "نام کاربری مدیر" msgstr "نام کاربری مدیر"
@@ -73,7 +72,6 @@ msgstr "نام کاربری مدیر"
msgid "All" msgid "All"
msgstr "همه" msgstr "همه"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "همیشه" msgstr "همیشه"
@@ -173,18 +171,14 @@ msgstr "یک عبارت فیلتر بسازید تا نشان دهید چه چی
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "لغو" msgstr "لغو"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "تأیید کنید"
msgid "Confirm password" msgid "Confirm password"
msgstr "رمز عبور را تأیید کنید" msgstr "رمز عبور را تأیید کنید"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "تأیید رمز عبور" msgstr "تأیید رمز عبور"
@@ -294,7 +287,6 @@ msgstr "روز"
msgid "Delete" msgid "Delete"
msgstr "حذف کنید" msgstr "حذف کنید"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "حذف حساب" msgstr "حذف حساب"
@@ -342,13 +334,10 @@ msgstr "پیوند را به نوار نشانک بکشید"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "ایمیل" msgstr "ایمیل"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "آدرس ایمیل" msgstr "آدرس ایمیل"
@@ -399,7 +388,6 @@ msgstr "گزینه های افزونه"
msgid "Feed name" msgid "Feed name"
msgstr "نام فید" msgstr "نام فید"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "بارگیری اشتراک ها..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "بارگیری برچسب ها..." msgstr "بارگیری برچسب ها..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "با وارد کردن نام اشتراک، به آن بروید"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "هنگام علامت‌گذاری همه ورودی‌ها به‌عنوان خوانده‌شده، به دسته‌بندی/فید بعدی با ورودی‌های خوانده‌نشده بروید" msgstr "هنگام علامت‌گذاری همه ورودی‌ها به‌عنوان خوانده‌شده، به دسته‌بندی/فید بعدی با ورودی‌های خوانده‌نشده بروید"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "هرگز" msgstr "هرگز"
@@ -657,7 +643,6 @@ msgstr "هرگز"
msgid "New password" msgid "New password"
msgstr "رمز عبور جدید" msgstr "رمز عبور جدید"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "رمز عبور جدید" msgstr "رمز عبور جدید"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "خروجی OPML" msgstr "خروجی OPML"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "فایل OPML" msgstr "فایل OPML"
@@ -791,10 +775,7 @@ msgstr "دسته والد"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "رمز عبور" msgstr "رمز عبور"
@@ -874,7 +855,6 @@ msgstr "تازه کردن"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "ثبت نام در این نمونه CommaFeed بسته شده است" msgstr "ثبت نام در این نمونه CommaFeed بسته شده است"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "بازنشانی رمز عبور" msgstr "بازنشانی رمز عبور"
@@ -883,7 +863,6 @@ msgstr "بازنشانی رمز عبور"
msgid "REST API" msgid "REST API"
msgstr "REST API" msgstr "REST API"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "راست کلیک" msgstr "راست کلیک"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "پیمایش" msgstr "پیمایش"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "جستجو" msgstr "جستجو"
@@ -924,7 +901,6 @@ msgstr "انتخاب فید/دسته بعدی خوانده نشده"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "انتخاب فید/دسته قبلی خوانده نشده" msgstr "انتخاب فید/دسته قبلی خوانده نشده"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "آدرس سرور" msgstr "آدرس سرور"
@@ -953,8 +929,6 @@ msgstr "به اشتراک بگذارید"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "اشتراک گذاری سایت ها" msgstr "اشتراک گذاری سایت ها"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "شیفت" msgstr "شیفت"
@@ -1003,7 +977,6 @@ msgstr "نمایش تعداد خوانده نشده در فاویکون زبان
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "نمایش تعداد خوانده نشده در عنوان زبانه" msgstr "نمایش تعداد خوانده نشده در عنوان زبانه"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "ثبت نام کنید"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "اتفاق بدی افتاد..." msgstr "اتفاق بدی افتاد..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "فضا" msgstr "فضا"
@@ -1030,7 +1002,6 @@ msgstr "ستاره"
msgid "Starred" msgid "Starred"
msgstr "ستاره دار" msgstr "ستاره دار"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "تغییر به تم روشن"
msgid "System" msgid "System"
msgstr "سیستم" msgstr "سیستم"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "برچسب‌ها" msgstr "برچسب‌ها"
@@ -1136,7 +1106,6 @@ msgstr "خوانده نشده"
msgid "Unstar" msgid "Unstar"
msgstr "برداشتن ستاره" msgstr "برداشتن ستاره"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "لغو اشتراک" msgstr "لغو اشتراک"
@@ -1149,7 +1118,6 @@ msgstr "کلید کاربر"
msgid "User name" msgid "User name"
msgstr "نام کاربری" msgstr "نام کاربری"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "نام کاربری یا ایمیل" msgstr "نام کاربری یا ایمیل"

View File

@@ -60,7 +60,6 @@ msgstr "Lisää käyttäjä"
msgid "Admin" msgid "Admin"
msgstr "Järjestelmänvalvoja" msgstr "Järjestelmänvalvoja"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "Järjestelmänvalvojan käyttäjänimi" msgstr "Järjestelmänvalvojan käyttäjänimi"
@@ -73,7 +72,6 @@ msgstr "Järjestelmänvalvojan käyttäjänimi"
msgid "All" msgid "All"
msgstr "Kaikki" msgstr "Kaikki"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "Aina" msgstr "Aina"
@@ -173,18 +171,14 @@ msgstr "Rakenna suodatinlauseke määrittääksesi, mitä haluat lukea. Merkinn
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "Peruuta" msgstr "Peruuta"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "Vahvista"
msgid "Confirm password" msgid "Confirm password"
msgstr "Vahvista salasana" msgstr "Vahvista salasana"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "Vahvista salasana" msgstr "Vahvista salasana"
@@ -294,7 +287,6 @@ msgstr "päivää"
msgid "Delete" msgid "Delete"
msgstr "Poista" msgstr "Poista"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "Poista tili" msgstr "Poista tili"
@@ -342,13 +334,10 @@ msgstr "Vedä linkki kirjanmerkkipalkkiin"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "Sähköposti" msgstr "Sähköposti"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "Sähköpostiosoite" msgstr "Sähköpostiosoite"
@@ -399,7 +388,6 @@ msgstr "Laajennuksen asetukset"
msgid "Feed name" msgid "Feed name"
msgstr "Syötteen nimi" msgstr "Syötteen nimi"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "Ladataan tilauksia..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "Ladataan tunnisteita..." msgstr "Ladataan tunnisteita..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "Siirry tilaukseen kirjoittamalla sen nimi"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "Siirry seuraavaan luokkaan/syötteeseen, jossa on lukemattomia merkintöjä, kun kaikki merkinnät merkitään luetuiksi" msgstr "Siirry seuraavaan luokkaan/syötteeseen, jossa on lukemattomia merkintöjä, kun kaikki merkinnät merkitään luetuiksi"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "Ei koskaan" msgstr "Ei koskaan"
@@ -657,7 +643,6 @@ msgstr "Ei koskaan"
msgid "New password" msgid "New password"
msgstr "Uusi salasana" msgstr "Uusi salasana"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "Uusi salasana" msgstr "Uusi salasana"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "OPML-vienti" msgstr "OPML-vienti"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "OPML-tiedosto" msgstr "OPML-tiedosto"
@@ -791,10 +775,7 @@ msgstr "Pääluokka"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "Salasana" msgstr "Salasana"
@@ -874,7 +855,6 @@ msgstr "Päivitä"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "Tämän CommaFeed-esiintymän rekisteröinnit on suljettu" msgstr "Tämän CommaFeed-esiintymän rekisteröinnit on suljettu"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "Nollaa salasana" msgstr "Nollaa salasana"
@@ -883,7 +863,6 @@ msgstr "Nollaa salasana"
msgid "REST API" msgid "REST API"
msgstr "REST-API" msgstr "REST-API"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "Oikea napsautus" msgstr "Oikea napsautus"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "Vieritys" msgstr "Vieritys"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "Etsi" msgstr "Etsi"
@@ -924,7 +901,6 @@ msgstr "Valitse seuraava lukematon syöte/luokka"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "Valitse edellinen lukematon syöte/luokka" msgstr "Valitse edellinen lukematon syöte/luokka"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "Palvelimen URL-osoite" msgstr "Palvelimen URL-osoite"
@@ -953,8 +929,6 @@ msgstr "Jaa"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "Sivustojen jakaminen" msgstr "Sivustojen jakaminen"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "Vaihto" msgstr "Vaihto"
@@ -1003,7 +977,6 @@ msgstr "Näytä lukemattomien määrä välilehden kuvakkeessa"
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "Näytä lukemattomien määrä välilehden otsikossa" msgstr "Näytä lukemattomien määrä välilehden otsikossa"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "Rekisteröidy"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "Jotain pahaa tapahtui juuri..." msgstr "Jotain pahaa tapahtui juuri..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "Avaruus" msgstr "Avaruus"
@@ -1030,7 +1002,6 @@ msgstr "Tähti"
msgid "Starred" msgid "Starred"
msgstr "Tähdellä merkitty" msgstr "Tähdellä merkitty"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "Vaihda vaaleaan teemaan"
msgid "System" msgid "System"
msgstr "Järjestelmä" msgstr "Järjestelmä"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "Tunnisteet" msgstr "Tunnisteet"
@@ -1136,7 +1106,6 @@ msgstr "Lukematon"
msgid "Unstar" msgid "Unstar"
msgstr "Poista tähti" msgstr "Poista tähti"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "Peruuta tilaus" msgstr "Peruuta tilaus"
@@ -1149,7 +1118,6 @@ msgstr "Käyttäjäavain"
msgid "User name" msgid "User name"
msgstr "Käyttäjänimi" msgstr "Käyttäjänimi"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "Käyttäjänimi tai sähköpostiosoite" msgstr "Käyttäjänimi tai sähköpostiosoite"

View File

@@ -60,7 +60,6 @@ msgstr "Ajouter un utilisateur"
msgid "Admin" msgid "Admin"
msgstr "Administrateur" msgstr "Administrateur"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "Nom de l'administrateur" msgstr "Nom de l'administrateur"
@@ -73,7 +72,6 @@ msgstr "Nom de l'administrateur"
msgid "All" msgid "All"
msgstr "Tout" msgstr "Tout"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "Toujours" msgstr "Toujours"
@@ -173,18 +171,14 @@ msgstr "Créez une expression régulière pour filtrer ce que vous voulez lire.
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "Annuler" msgstr "Annuler"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "Confirmer"
msgid "Confirm password" msgid "Confirm password"
msgstr "Confirmer le mot de passe" msgstr "Confirmer le mot de passe"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "Confirmer le mot de passe" msgstr "Confirmer le mot de passe"
@@ -294,7 +287,6 @@ msgstr "jours"
msgid "Delete" msgid "Delete"
msgstr "Effacer" msgstr "Effacer"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "Effacer le compte" msgstr "Effacer le compte"
@@ -342,13 +334,10 @@ msgstr "Déplacez le lien vers la barre de favoris"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "E-mail" msgstr "E-mail"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "Adresse e-mail" msgstr "Adresse e-mail"
@@ -399,7 +388,6 @@ msgstr "Options de l'extension"
msgid "Feed name" msgid "Feed name"
msgstr "Nom du flux" msgstr "Nom du flux"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "Chargement des abonnements..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "Chargement des marqueurs..." msgstr "Chargement des marqueurs..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "Naviguer vers un abonnement en entrant son nom"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "Aller vers la catégorie/le flux comportant des entrées non lues suivant après avoir marqué toutes les entrées lues" msgstr "Aller vers la catégorie/le flux comportant des entrées non lues suivant après avoir marqué toutes les entrées lues"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "Jamais" msgstr "Jamais"
@@ -657,7 +643,6 @@ msgstr "Jamais"
msgid "New password" msgid "New password"
msgstr "Nouveau mot de passe" msgstr "Nouveau mot de passe"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "Nouveau mot de passe" msgstr "Nouveau mot de passe"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "Export du fichier OPML" msgstr "Export du fichier OPML"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "Fichier OPML" msgstr "Fichier OPML"
@@ -791,10 +775,7 @@ msgstr "Catégorie parente"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "Mot de passe" msgstr "Mot de passe"
@@ -874,7 +855,6 @@ msgstr "Rafraîchir"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "Les inscriptions sont fermées sur cette instance de CommaFeed" msgstr "Les inscriptions sont fermées sur cette instance de CommaFeed"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "Réinitialiser le mot de passe" msgstr "Réinitialiser le mot de passe"
@@ -883,7 +863,6 @@ msgstr "Réinitialiser le mot de passe"
msgid "REST API" msgid "REST API"
msgstr "API REST" msgstr "API REST"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "Clic droit" msgstr "Clic droit"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "Défilement" msgstr "Défilement"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "Rechercher" msgstr "Rechercher"
@@ -924,7 +901,6 @@ msgstr "Sélectionner l'article non lu suivant/la catégorie non lue suivante"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "Sélectionner l'article non lu précédent/la catégorie non lue précédente" msgstr "Sélectionner l'article non lu précédent/la catégorie non lue précédente"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "URL du serveur" msgstr "URL du serveur"
@@ -953,8 +929,6 @@ msgstr "Partager"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "Sites de partage" msgstr "Sites de partage"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "Maj" msgstr "Maj"
@@ -1003,7 +977,6 @@ msgstr "Afficher le nombre d'entrées non lues dans la favicône de l'onglet"
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "Afficher le nombre d'entrées non lues dans le titre de l'onglet" msgstr "Afficher le nombre d'entrées non lues dans le titre de l'onglet"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "Créer un compte"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "Quelque chose s'est mal passé..." msgstr "Quelque chose s'est mal passé..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "Espace" msgstr "Espace"
@@ -1030,7 +1002,6 @@ msgstr "Ajouter aux favoris"
msgid "Starred" msgid "Starred"
msgstr "Favoris" msgstr "Favoris"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "Activer le mode clair"
msgid "System" msgid "System"
msgstr "Système" msgstr "Système"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "Marqueurs" msgstr "Marqueurs"
@@ -1136,7 +1106,6 @@ msgstr "Non lu"
msgid "Unstar" msgid "Unstar"
msgstr "Retirer des favoris" msgstr "Retirer des favoris"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "Se désabonner" msgstr "Se désabonner"
@@ -1149,7 +1118,6 @@ msgstr "Clé utilisateur"
msgid "User name" msgid "User name"
msgstr "Nom" msgstr "Nom"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "Nom d'utilisateur ou e-mail" msgstr "Nom d'utilisateur ou e-mail"

View File

@@ -61,7 +61,6 @@ msgstr "Engadir persoa usuaria"
msgid "Admin" msgid "Admin"
msgstr "Administración" msgstr "Administración"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "Identificador de admin" msgstr "Identificador de admin"
@@ -74,7 +73,6 @@ msgstr "Identificador de admin"
msgid "All" msgid "All"
msgstr "Todos" msgstr "Todos"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "Sempre" msgstr "Sempre"
@@ -174,18 +172,14 @@ msgstr "Crea unha expresión de filtrado para indicar o que queres ler. Os artig
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "Cancelar" msgstr "Cancelar"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -241,7 +235,6 @@ msgstr "Confirmar"
msgid "Confirm password" msgid "Confirm password"
msgstr "Confirmar contrasinal" msgstr "Confirmar contrasinal"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "Confirmar contrasinal" msgstr "Confirmar contrasinal"
@@ -295,7 +288,6 @@ msgstr "días"
msgid "Delete" msgid "Delete"
msgstr "Eliminar" msgstr "Eliminar"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "Eliminar conta" msgstr "Eliminar conta"
@@ -343,13 +335,10 @@ msgstr "Arrastra a ligazón á barra de marcadores"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "Correo electrónico" msgstr "Correo electrónico"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "Enderezo de correo electrónico" msgstr "Enderezo de correo electrónico"
@@ -400,7 +389,6 @@ msgstr "Opcións do complemento"
msgid "Feed name" msgid "Feed name"
msgstr "Nome da canle" msgstr "Nome da canle"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -571,7 +559,6 @@ msgstr "Cargando subscricións..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "Cargando etiquetas..." msgstr "Cargando etiquetas..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -649,7 +636,6 @@ msgstr "Vai a unha subscrición ao escribir o seu nome"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "Vai á seguinte categoría/canle con artigos sen ler cando marques todos artigos como lidos" msgstr "Vai á seguinte categoría/canle con artigos sen ler cando marques todos artigos como lidos"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "Nunca" msgstr "Nunca"
@@ -658,7 +644,6 @@ msgstr "Nunca"
msgid "New password" msgid "New password"
msgstr "Novo contrasinal" msgstr "Novo contrasinal"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "Novo contrasinal" msgstr "Novo contrasinal"
@@ -765,7 +750,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "Exportación OPML" msgstr "Exportación OPML"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "Ficheiro OPML" msgstr "Ficheiro OPML"
@@ -792,10 +776,7 @@ msgstr "Categoría superior"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "Contrasinal" msgstr "Contrasinal"
@@ -875,7 +856,6 @@ msgstr "Actualizar"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "Non se admiten novas contas nesta instancia de CommaFeed" msgstr "Non se admiten novas contas nesta instancia de CommaFeed"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "Restablecer contrasinal" msgstr "Restablecer contrasinal"
@@ -884,7 +864,6 @@ msgstr "Restablecer contrasinal"
msgid "REST API" msgid "REST API"
msgstr "API REST" msgstr "API REST"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "Botón dereito" msgstr "Botón dereito"
@@ -911,8 +890,6 @@ msgid "Scrolling"
msgstr "Desprazamento" msgstr "Desprazamento"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "Busca" msgstr "Busca"
@@ -925,7 +902,6 @@ msgstr "Seleccionar a seguinte canle/categoría sen ler"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "Seleccionar a canle/categoría anterior sen ler" msgstr "Seleccionar a canle/categoría anterior sen ler"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "URL do servidor" msgstr "URL do servidor"
@@ -954,8 +930,6 @@ msgstr "Compartir"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "Servizos para compartir" msgstr "Servizos para compartir"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "Maiúsculas" msgstr "Maiúsculas"
@@ -1004,7 +978,6 @@ msgstr "Mostrar a conta de artigos sen ler na icona da pestana"
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "Mostar a conta de artigos sen ler no título da pestana" msgstr "Mostar a conta de artigos sen ler no título da pestana"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1014,7 +987,6 @@ msgstr "Crear conta"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "Algo malo pasou..." msgstr "Algo malo pasou..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "Espazo" msgstr "Espazo"
@@ -1031,7 +1003,6 @@ msgstr "Pór estrela"
msgid "Starred" msgid "Starred"
msgstr "Con estrela" msgstr "Con estrela"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1065,7 +1036,6 @@ msgstr "Cambiar ao decorado claro"
msgid "System" msgid "System"
msgstr "Sistema" msgstr "Sistema"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "Etiquetas" msgstr "Etiquetas"
@@ -1137,7 +1107,6 @@ msgstr "Sen ler"
msgid "Unstar" msgid "Unstar"
msgstr "Retirar estrela" msgstr "Retirar estrela"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "Cancelar a subscrición" msgstr "Cancelar a subscrición"
@@ -1150,7 +1119,6 @@ msgstr "Clave de usuario"
msgid "User name" msgid "User name"
msgstr "Identificador" msgstr "Identificador"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "Identificador ou correo electrónico" msgstr "Identificador ou correo electrónico"

View File

@@ -60,7 +60,6 @@ msgstr "Felhasználó hozzáadása"
msgid "Admin" msgid "Admin"
msgstr "Adminisztráció" msgstr "Adminisztráció"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "Adminisztrátor felhasználóneve" msgstr "Adminisztrátor felhasználóneve"
@@ -73,7 +72,6 @@ msgstr "Adminisztrátor felhasználóneve"
msgid "All" msgid "All"
msgstr "Mind" msgstr "Mind"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "Mindig" msgstr "Mindig"
@@ -173,18 +171,14 @@ msgstr "Hozzon létre egy szűrőkifejezést annak megjelölésére, hogy mit sz
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "Mégse" msgstr "Mégse"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "Erősítse meg"
msgid "Confirm password" msgid "Confirm password"
msgstr "Erősítse meg a jelszót" msgstr "Erősítse meg a jelszót"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "Jelszó megerősítése" msgstr "Jelszó megerősítése"
@@ -294,7 +287,6 @@ msgstr "nap"
msgid "Delete" msgid "Delete"
msgstr "Törlés" msgstr "Törlés"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "Fiók törlése" msgstr "Fiók törlése"
@@ -342,13 +334,10 @@ msgstr "Húzza a hivatkozást a könyvjelzősávra"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "E-mail" msgstr "E-mail"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "E-mail cím" msgstr "E-mail cím"
@@ -399,7 +388,6 @@ msgstr "Bővítmény beállításai"
msgid "Feed name" msgid "Feed name"
msgstr "Hírcsatorna neve" msgstr "Hírcsatorna neve"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "Előfizetések betöltése..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "Címkék betöltése..." msgstr "Címkék betöltése..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "Navigáljon egy előfizetéshez a nevének megadásával"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "Navigálás a következő olvasatlan bejegyzéseket tartalmazó kategóriára/hírcsatornára, ha minden bejegyzést olvasottnak jelöl" msgstr "Navigálás a következő olvasatlan bejegyzéseket tartalmazó kategóriára/hírcsatornára, ha minden bejegyzést olvasottnak jelöl"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "Soha" msgstr "Soha"
@@ -657,7 +643,6 @@ msgstr "Soha"
msgid "New password" msgid "New password"
msgstr "Új jelszó" msgstr "Új jelszó"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "Új jelszó" msgstr "Új jelszó"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "OPML exportálás" msgstr "OPML exportálás"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "OPML fájl" msgstr "OPML fájl"
@@ -791,10 +775,7 @@ msgstr "Szülő kategória"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "Jelszó" msgstr "Jelszó"
@@ -874,7 +855,6 @@ msgstr "Frissítés"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "A regisztrációk le vannak zárva ezen a CommaFeed példányon" msgstr "A regisztrációk le vannak zárva ezen a CommaFeed példányon"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "Jelszó visszaállítása" msgstr "Jelszó visszaállítása"
@@ -883,7 +863,6 @@ msgstr "Jelszó visszaállítása"
msgid "REST API" msgid "REST API"
msgstr "REST API" msgstr "REST API"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "Jobb klikk" msgstr "Jobb klikk"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "Görgetés" msgstr "Görgetés"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "Keresés" msgstr "Keresés"
@@ -924,7 +901,6 @@ msgstr "Következő olvasatlan feed/kategória kiválasztása"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "Előző olvasatlan feed/kategória kiválasztása" msgstr "Előző olvasatlan feed/kategória kiválasztása"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "Szerver URL" msgstr "Szerver URL"
@@ -953,8 +929,6 @@ msgstr "Oszd meg"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "Webhelyek megosztása" msgstr "Webhelyek megosztása"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "Shift" msgstr "Shift"
@@ -1003,7 +977,6 @@ msgstr "Olvasatlan darabszám megjelenítése a tab faviconján"
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "Olvasatlan darabszám megjelenítése a tab címében" msgstr "Olvasatlan darabszám megjelenítése a tab címében"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "Regisztráció"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "Valami rossz történt..." msgstr "Valami rossz történt..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "Szóköz" msgstr "Szóköz"
@@ -1030,7 +1002,6 @@ msgstr "Csillag"
msgid "Starred" msgid "Starred"
msgstr "Csillaggal megjelölve" msgstr "Csillaggal megjelölve"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "Váltás világos témára"
msgid "System" msgid "System"
msgstr "Rendszer" msgstr "Rendszer"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "Címkék" msgstr "Címkék"
@@ -1136,7 +1106,6 @@ msgstr "Olvasatlan"
msgid "Unstar" msgid "Unstar"
msgstr "Csillag eltávolítása" msgstr "Csillag eltávolítása"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "Leiratkozás" msgstr "Leiratkozás"
@@ -1149,7 +1118,6 @@ msgstr "Felhasználói kulcs"
msgid "User name" msgid "User name"
msgstr "Felhasználónév" msgstr "Felhasználónév"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "Felhasználói név vagy e-mail cím" msgstr "Felhasználói név vagy e-mail cím"

View File

@@ -60,7 +60,6 @@ msgstr "Tambahkan pengguna"
msgid "Admin" msgid "Admin"
msgstr "Admin" msgstr "Admin"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "Nama pengguna admin" msgstr "Nama pengguna admin"
@@ -73,7 +72,6 @@ msgstr "Nama pengguna admin"
msgid "All" msgid "All"
msgstr "Semua" msgstr "Semua"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "Selalu" msgstr "Selalu"
@@ -173,18 +171,14 @@ msgstr "Bangun ekspresi filter untuk menunjukkan apa yang ingin Anda baca. Entri
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "Batal" msgstr "Batal"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "Konfirmasi"
msgid "Confirm password" msgid "Confirm password"
msgstr "Konfirmasi kata sandi" msgstr "Konfirmasi kata sandi"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "Konfirmasi Kata Sandi" msgstr "Konfirmasi Kata Sandi"
@@ -294,7 +287,6 @@ msgstr "hari"
msgid "Delete" msgid "Delete"
msgstr "Hapus" msgstr "Hapus"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "Hapus akun" msgstr "Hapus akun"
@@ -342,13 +334,10 @@ msgstr "Seret tautan ke bilah bookmark"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "Email" msgstr "Email"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "Alamat email" msgstr "Alamat email"
@@ -399,7 +388,6 @@ msgstr "Opsi ekstensi"
msgid "Feed name" msgid "Feed name"
msgstr "Nama umpan" msgstr "Nama umpan"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "Memuat langganan..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "Memuat tag..." msgstr "Memuat tag..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "Navigasikan ke langganan dengan memasukkan namanya"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "Navigasikan ke kategori/umpan berikutnya dengan entri yang belum dibaca saat menandai semua entri sebagai telah dibaca" msgstr "Navigasikan ke kategori/umpan berikutnya dengan entri yang belum dibaca saat menandai semua entri sebagai telah dibaca"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "Tidak pernah" msgstr "Tidak pernah"
@@ -657,7 +643,6 @@ msgstr "Tidak pernah"
msgid "New password" msgid "New password"
msgstr "Kata sandi baru" msgstr "Kata sandi baru"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "Kata Sandi Baru" msgstr "Kata Sandi Baru"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "ekspor OPML" msgstr "ekspor OPML"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "file OPML" msgstr "file OPML"
@@ -791,10 +775,7 @@ msgstr "Kategori Induk"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "Kata Sandi" msgstr "Kata Sandi"
@@ -874,7 +855,6 @@ msgstr "Segarkan"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "Pendaftaran ditutup pada instans CommaFeed ini" msgstr "Pendaftaran ditutup pada instans CommaFeed ini"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "Atur Ulang Kata Sandi" msgstr "Atur Ulang Kata Sandi"
@@ -883,7 +863,6 @@ msgstr "Atur Ulang Kata Sandi"
msgid "REST API" msgid "REST API"
msgstr "REST API" msgstr "REST API"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "Klik kanan" msgstr "Klik kanan"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "Menggulir" msgstr "Menggulir"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "Pencarian" msgstr "Pencarian"
@@ -924,7 +901,6 @@ msgstr "Pilih umpan/kategori belum dibaca berikutnya"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "Pilih umpan/kategori belum dibaca sebelumnya" msgstr "Pilih umpan/kategori belum dibaca sebelumnya"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "URL Server" msgstr "URL Server"
@@ -953,8 +929,6 @@ msgstr "Bagikan"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "Berbagi situs" msgstr "Berbagi situs"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "Pergeseran" msgstr "Pergeseran"
@@ -1003,7 +977,6 @@ msgstr "Tampilkan jumlah yang belum dibaca di favicon tab"
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "Tampilkan jumlah yang belum dibaca di judul tab" msgstr "Tampilkan jumlah yang belum dibaca di judul tab"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "Daftar"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "Sesuatu yang buruk baru saja terjadi..." msgstr "Sesuatu yang buruk baru saja terjadi..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "Spasi" msgstr "Spasi"
@@ -1030,7 +1002,6 @@ msgstr "Bintang"
msgid "Starred" msgid "Starred"
msgstr "Berbintang" msgstr "Berbintang"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "Beralih ke tema terang"
msgid "System" msgid "System"
msgstr "Sistem" msgstr "Sistem"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "Tag" msgstr "Tag"
@@ -1136,7 +1106,6 @@ msgstr "Belum Dibaca"
msgid "Unstar" msgid "Unstar"
msgstr "Hapus bintang" msgstr "Hapus bintang"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "Berhenti berlangganan" msgstr "Berhenti berlangganan"
@@ -1149,7 +1118,6 @@ msgstr "Kunci pengguna"
msgid "User name" msgid "User name"
msgstr "Nama pengguna" msgstr "Nama pengguna"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "Nama Pengguna atau Email" msgstr "Nama Pengguna atau Email"

View File

@@ -60,7 +60,6 @@ msgstr "Aggiungi utente"
msgid "Admin" msgid "Admin"
msgstr "Ammin" msgstr "Ammin"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "Nome utente amministratore" msgstr "Nome utente amministratore"
@@ -73,7 +72,6 @@ msgstr "Nome utente amministratore"
msgid "All" msgid "All"
msgstr "Tutto" msgstr "Tutto"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "Sempre" msgstr "Sempre"
@@ -173,18 +171,14 @@ msgstr "Crea un'espressione di filtro per indicare cosa vuoi leggere. Le voci ch
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "Annulla" msgstr "Annulla"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "Conferma"
msgid "Confirm password" msgid "Confirm password"
msgstr "Conferma password" msgstr "Conferma password"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "Conferma password" msgstr "Conferma password"
@@ -294,7 +287,6 @@ msgstr "giorni"
msgid "Delete" msgid "Delete"
msgstr "Elimina" msgstr "Elimina"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "Elimina account" msgstr "Elimina account"
@@ -342,13 +334,10 @@ msgstr "Trascina il collegamento sulla barra dei preferiti"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "E-mail" msgstr "E-mail"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "Indirizzo e-mail" msgstr "Indirizzo e-mail"
@@ -399,7 +388,6 @@ msgstr "Opzioni estensione"
msgid "Feed name" msgid "Feed name"
msgstr "Nome del feed" msgstr "Nome del feed"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "Caricamento abbonamenti..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "Caricamento tag..." msgstr "Caricamento tag..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "Navigare verso un abbonamento inserendo il suo nome"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "Passa alla categoria/feed successivo con voci non lette quando contrassegni tutte le voci come lette" msgstr "Passa alla categoria/feed successivo con voci non lette quando contrassegni tutte le voci come lette"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "Mai" msgstr "Mai"
@@ -657,7 +643,6 @@ msgstr "Mai"
msgid "New password" msgid "New password"
msgstr "Nuova password" msgstr "Nuova password"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "Nuova password" msgstr "Nuova password"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "Esportazione OPML" msgstr "Esportazione OPML"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "File OPML" msgstr "File OPML"
@@ -791,10 +775,7 @@ msgstr "Categoria padre"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "Password" msgstr "Password"
@@ -874,7 +855,6 @@ msgstr "Aggiorna"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "Le registrazioni sono chiuse su questa istanza CommaFeed" msgstr "Le registrazioni sono chiuse su questa istanza CommaFeed"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "Reimposta password" msgstr "Reimposta password"
@@ -883,7 +863,6 @@ msgstr "Reimposta password"
msgid "REST API" msgid "REST API"
msgstr "API REST" msgstr "API REST"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "Clic destro" msgstr "Clic destro"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "Scorrimento" msgstr "Scorrimento"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "Cerca" msgstr "Cerca"
@@ -924,7 +901,6 @@ msgstr "Seleziona il feed/categoria non letto successivo"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "Seleziona il feed/categoria non letto precedente" msgstr "Seleziona il feed/categoria non letto precedente"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "URL del server" msgstr "URL del server"
@@ -953,8 +929,6 @@ msgstr "Condividi"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "Condivisione di siti" msgstr "Condivisione di siti"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "Cambio" msgstr "Cambio"
@@ -1003,7 +977,6 @@ msgstr "Mostra il numero di non letti nella favicon della scheda"
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "Mostra il numero di non letti nel titolo della scheda" msgstr "Mostra il numero di non letti nel titolo della scheda"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "Iscriviti"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "È appena successo qualcosa di brutto..." msgstr "È appena successo qualcosa di brutto..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "Spazio" msgstr "Spazio"
@@ -1030,7 +1002,6 @@ msgstr "Stella"
msgid "Starred" msgid "Starred"
msgstr "Speciali" msgstr "Speciali"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "Passa al tema chiaro"
msgid "System" msgid "System"
msgstr "Sistema" msgstr "Sistema"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "Tag" msgstr "Tag"
@@ -1136,7 +1106,6 @@ msgstr "Non letto"
msgid "Unstar" msgid "Unstar"
msgstr "Elimina le stelle" msgstr "Elimina le stelle"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "Annulla iscrizione" msgstr "Annulla iscrizione"
@@ -1149,7 +1118,6 @@ msgstr "Chiave utente"
msgid "User name" msgid "User name"
msgstr "Nome utente" msgstr "Nome utente"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "Nome utente o e-mail" msgstr "Nome utente o e-mail"

View File

@@ -60,7 +60,6 @@ msgstr "ユーザー追加"
msgid "Admin" msgid "Admin"
msgstr "管理者" msgstr "管理者"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "管理者ユーザー名" msgstr "管理者ユーザー名"
@@ -73,7 +72,6 @@ msgstr "管理者ユーザー名"
msgid "All" msgid "All"
msgstr "すべて" msgstr "すべて"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "常に" msgstr "常に"
@@ -173,18 +171,14 @@ msgstr "読みたい内容を指定するためのフィルタ式を作成しま
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "キャンセル" msgstr "キャンセル"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "確認"
msgid "Confirm password" msgid "Confirm password"
msgstr "パスワード確認" msgstr "パスワード確認"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "パスワードの確認" msgstr "パスワードの確認"
@@ -294,7 +287,6 @@ msgstr "日"
msgid "Delete" msgid "Delete"
msgstr "削除" msgstr "削除"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "アカウント削除" msgstr "アカウント削除"
@@ -342,13 +334,10 @@ msgstr "リンクをブックマークバーにドラッグ"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "メール" msgstr "メール"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "メールアドレス" msgstr "メールアドレス"
@@ -399,7 +388,6 @@ msgstr "拡張機能オプション"
msgid "Feed name" msgid "Feed name"
msgstr "フィード名" msgstr "フィード名"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "サブスクリプションを読み込んでいます..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "タグを読み込んでいます..." msgstr "タグを読み込んでいます..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "名前を入力してサブスクリプションに移動します"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "すべてのエントリーを既読にするとき、未読エントリーのある次のカテゴリ/フィードに移動する" msgstr "すべてのエントリーを既読にするとき、未読エントリーのある次のカテゴリ/フィードに移動する"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "しない" msgstr "しない"
@@ -657,7 +643,6 @@ msgstr "しない"
msgid "New password" msgid "New password"
msgstr "新しいパスワード" msgstr "新しいパスワード"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "新しいパスワード" msgstr "新しいパスワード"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "OPML エクスポート" msgstr "OPML エクスポート"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "OPMLファイル" msgstr "OPMLファイル"
@@ -791,10 +775,7 @@ msgstr "親カテゴリ"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "パスワード" msgstr "パスワード"
@@ -874,7 +855,6 @@ msgstr "リフレッシュ"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "このCommaFeedインスタンスの登録は終了しています" msgstr "このCommaFeedインスタンスの登録は終了しています"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "パスワードをリセット" msgstr "パスワードをリセット"
@@ -883,7 +863,6 @@ msgstr "パスワードをリセット"
msgid "REST API" msgid "REST API"
msgstr "REST API" msgstr "REST API"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "右クリック" msgstr "右クリック"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "スクロール" msgstr "スクロール"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "検索" msgstr "検索"
@@ -924,7 +901,6 @@ msgstr "次の未読フィード/カテゴリを選択"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "前の未読フィード/カテゴリを選択" msgstr "前の未読フィード/カテゴリを選択"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "サーバーURL" msgstr "サーバーURL"
@@ -953,8 +929,6 @@ msgstr "シェア"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "共有サイト" msgstr "共有サイト"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "Shift" msgstr "Shift"
@@ -1003,7 +977,6 @@ msgstr "未読数をタブのアイコンに表示する"
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "未読数をタブのタイトルに表示する" msgstr "未読数をタブのタイトルに表示する"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "サインアップ"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "何か悪いことが起きました..." msgstr "何か悪いことが起きました..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "Space" msgstr "Space"
@@ -1030,7 +1002,6 @@ msgstr "スター"
msgid "Starred" msgid "Starred"
msgstr "スター付き" msgstr "スター付き"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "ライトテーマに切り替え"
msgid "System" msgid "System"
msgstr "システム" msgstr "システム"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "タグ" msgstr "タグ"
@@ -1136,7 +1106,6 @@ msgstr "未読"
msgid "Unstar" msgid "Unstar"
msgstr "スターを外す" msgstr "スターを外す"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "退会" msgstr "退会"
@@ -1149,7 +1118,6 @@ msgstr "ユーザーキー"
msgid "User name" msgid "User name"
msgstr "ユーザー名" msgstr "ユーザー名"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "ユーザー名またはメールアドレス" msgstr "ユーザー名またはメールアドレス"

View File

@@ -60,7 +60,6 @@ msgstr "사용자 추가"
msgid "Admin" msgid "Admin"
msgstr "관리자" msgstr "관리자"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "관리자 사용자 이름" msgstr "관리자 사용자 이름"
@@ -73,7 +72,6 @@ msgstr "관리자 사용자 이름"
msgid "All" msgid "All"
msgstr "전체" msgstr "전체"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "항상" msgstr "항상"
@@ -173,18 +171,14 @@ msgstr "읽고 싶은 항목을 지정하기 위한 필터 표현식을 작성
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "취소" msgstr "취소"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "확인"
msgid "Confirm password" msgid "Confirm password"
msgstr "비밀번호 확인" msgstr "비밀번호 확인"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "비밀번호 확인" msgstr "비밀번호 확인"
@@ -294,7 +287,6 @@ msgstr "일"
msgid "Delete" msgid "Delete"
msgstr "삭제" msgstr "삭제"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "계정 삭제" msgstr "계정 삭제"
@@ -342,13 +334,10 @@ msgstr "링크를 북마크바로 드래그"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "이메일" msgstr "이메일"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "이메일 주소" msgstr "이메일 주소"
@@ -399,7 +388,6 @@ msgstr "확장 프로그램 옵션"
msgid "Feed name" msgid "Feed name"
msgstr "피드 이름" msgstr "피드 이름"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "구독 로드 중..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "태그 로드 중..." msgstr "태그 로드 중..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "이름을 입력하여 구독으로 이동"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "모든 항목을 읽음으로 표시할 때 읽지 않은 항목이 있는 다음 카테고리/피드로 이동" msgstr "모든 항목을 읽음으로 표시할 때 읽지 않은 항목이 있는 다음 카테고리/피드로 이동"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "안 함" msgstr "안 함"
@@ -657,7 +643,6 @@ msgstr "안 함"
msgid "New password" msgid "New password"
msgstr "새 비밀번호" msgstr "새 비밀번호"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "새 비밀번호" msgstr "새 비밀번호"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "OPML 내보내기" msgstr "OPML 내보내기"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "OPML 파일" msgstr "OPML 파일"
@@ -791,10 +775,7 @@ msgstr "부모 카테고리"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "비밀번호" msgstr "비밀번호"
@@ -874,7 +855,6 @@ msgstr "새로 고침"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "이 CommaFeed 인스턴스에 대한 등록이 마감되었습니다." msgstr "이 CommaFeed 인스턴스에 대한 등록이 마감되었습니다."
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "비밀번호 재설정" msgstr "비밀번호 재설정"
@@ -883,7 +863,6 @@ msgstr "비밀번호 재설정"
msgid "REST API" msgid "REST API"
msgstr "REST API" msgstr "REST API"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "오른쪽 클릭" msgstr "오른쪽 클릭"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "스크롤" msgstr "스크롤"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "검색" msgstr "검색"
@@ -924,7 +901,6 @@ msgstr "다음 읽지 않은 피드/카테고리 선택"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "이전 읽지 않은 피드/카테고리 선택" msgstr "이전 읽지 않은 피드/카테고리 선택"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "서버 URL" msgstr "서버 URL"
@@ -953,8 +929,6 @@ msgstr "공유"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "사이트 공유" msgstr "사이트 공유"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "시프트" msgstr "시프트"
@@ -1003,7 +977,6 @@ msgstr "탭 파비콘에 읽지 않은 개수 표시"
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "탭 제목에 읽지 않은 개수 표시" msgstr "탭 제목에 읽지 않은 개수 표시"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "가입"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "뭔가 안 좋은 일이 일어났어..." msgstr "뭔가 안 좋은 일이 일어났어..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "우주" msgstr "우주"
@@ -1030,7 +1002,6 @@ msgstr "스타"
msgid "Starred" msgid "Starred"
msgstr "별표" msgstr "별표"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "밝은 테마로 전환"
msgid "System" msgid "System"
msgstr "시스템" msgstr "시스템"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "태그" msgstr "태그"
@@ -1136,7 +1106,6 @@ msgstr "읽지 않음"
msgid "Unstar" msgid "Unstar"
msgstr "별표 제거" msgstr "별표 제거"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "구독 취소" msgstr "구독 취소"
@@ -1149,7 +1118,6 @@ msgstr "사용자 키"
msgid "User name" msgid "User name"
msgstr "사용자 이름" msgstr "사용자 이름"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "사용자 이름 또는 이메일" msgstr "사용자 이름 또는 이메일"

View File

@@ -60,7 +60,6 @@ msgstr "Tambah pengguna"
msgid "Admin" msgid "Admin"
msgstr "Pentadbir" msgstr "Pentadbir"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "Nama pengguna pentadbir" msgstr "Nama pengguna pentadbir"
@@ -73,7 +72,6 @@ msgstr "Nama pengguna pentadbir"
msgid "All" msgid "All"
msgstr "Semua" msgstr "Semua"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "Sentiasa" msgstr "Sentiasa"
@@ -173,18 +171,14 @@ msgstr "Bina ungkapan penapis untuk menunjukkan perkara yang anda mahu baca. Ent
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "Batal" msgstr "Batal"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "Sahkan"
msgid "Confirm password" msgid "Confirm password"
msgstr "Sahkan kata laluan" msgstr "Sahkan kata laluan"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "Sahkan Kata Laluan" msgstr "Sahkan Kata Laluan"
@@ -294,7 +287,6 @@ msgstr "hari"
msgid "Delete" msgid "Delete"
msgstr "Padam" msgstr "Padam"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "Padam akaun" msgstr "Padam akaun"
@@ -342,13 +334,10 @@ msgstr "Seret pautan ke bar penanda halaman"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "E-mel" msgstr "E-mel"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "Alamat e-mel" msgstr "Alamat e-mel"
@@ -399,7 +388,6 @@ msgstr "Pilihan ekstensi"
msgid "Feed name" msgid "Feed name"
msgstr "Nama suapan" msgstr "Nama suapan"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "Memuatkan langganan..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "Memuatkan tag..." msgstr "Memuatkan tag..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "Navigasi ke langganan dengan memasukkan namanya"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "Navigasi ke kategori/suapan seterusnya dengan entri yang belum dibaca apabila menandakan semua entri sebagai dibaca" msgstr "Navigasi ke kategori/suapan seterusnya dengan entri yang belum dibaca apabila menandakan semua entri sebagai dibaca"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "Tidak pernah" msgstr "Tidak pernah"
@@ -657,7 +643,6 @@ msgstr "Tidak pernah"
msgid "New password" msgid "New password"
msgstr "Kata laluan baharu" msgstr "Kata laluan baharu"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "Kata Laluan Baharu" msgstr "Kata Laluan Baharu"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "OPML eksport" msgstr "OPML eksport"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "Fail OPML" msgstr "Fail OPML"
@@ -791,10 +775,7 @@ msgstr "Kategori Induk"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "Kata Laluan" msgstr "Kata Laluan"
@@ -874,7 +855,6 @@ msgstr "Muat semula"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "Pendaftaran ditutup pada contoh CommaFeed ini" msgstr "Pendaftaran ditutup pada contoh CommaFeed ini"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "Tetap Semula Kata Laluan" msgstr "Tetap Semula Kata Laluan"
@@ -883,7 +863,6 @@ msgstr "Tetap Semula Kata Laluan"
msgid "REST API" msgid "REST API"
msgstr "REHAT API" msgstr "REHAT API"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "Klik kanan" msgstr "Klik kanan"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "Menatal" msgstr "Menatal"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "Cari" msgstr "Cari"
@@ -924,7 +901,6 @@ msgstr "Pilih suapan/kategori belum dibaca seterusnya"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "Pilih suapan/kategori belum dibaca sebelumnya" msgstr "Pilih suapan/kategori belum dibaca sebelumnya"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "URL Pelayan" msgstr "URL Pelayan"
@@ -953,8 +929,6 @@ msgstr "Kongsi"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "Berkongsi tapak" msgstr "Berkongsi tapak"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "Anjakan" msgstr "Anjakan"
@@ -1003,7 +977,6 @@ msgstr "Tunjukkan kiraan belum dibaca dalam favicon tab"
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "Tunjukkan kiraan belum dibaca dalam tajuk tab" msgstr "Tunjukkan kiraan belum dibaca dalam tajuk tab"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "Daftar"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "Sesuatu yang buruk baru saja berlaku..." msgstr "Sesuatu yang buruk baru saja berlaku..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "Angkasa" msgstr "Angkasa"
@@ -1030,7 +1002,6 @@ msgstr "Bintang"
msgid "Starred" msgid "Starred"
msgstr "Dibintangi" msgstr "Dibintangi"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "Tukar kepada tema cahaya"
msgid "System" msgid "System"
msgstr "Sistem" msgstr "Sistem"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "Tag" msgstr "Tag"
@@ -1136,7 +1106,6 @@ msgstr "Belum dibaca"
msgid "Unstar" msgid "Unstar"
msgstr "Nyahbintang" msgstr "Nyahbintang"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "Nyahlanggan" msgstr "Nyahlanggan"
@@ -1149,7 +1118,6 @@ msgstr "Kunci pengguna"
msgid "User name" msgid "User name"
msgstr "Nama pengguna" msgstr "Nama pengguna"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "Nama Pengguna atau E-mel" msgstr "Nama Pengguna atau E-mel"

View File

@@ -60,7 +60,6 @@ msgstr "Legg til bruker"
msgid "Admin" msgid "Admin"
msgstr "Administrator" msgstr "Administrator"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "Administrator brukernavn" msgstr "Administrator brukernavn"
@@ -73,7 +72,6 @@ msgstr "Administrator brukernavn"
msgid "All" msgid "All"
msgstr "Alle" msgstr "Alle"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "Alltid" msgstr "Alltid"
@@ -173,18 +171,14 @@ msgstr "Bygg et filteruttrykk for å angi hva du vil lese. Oppføringer som ikke
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "Avbryt" msgstr "Avbryt"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "Bekreft"
msgid "Confirm password" msgid "Confirm password"
msgstr "Bekreft passord" msgstr "Bekreft passord"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "Bekreft passord" msgstr "Bekreft passord"
@@ -294,7 +287,6 @@ msgstr "dager"
msgid "Delete" msgid "Delete"
msgstr "Slett" msgstr "Slett"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "Slett konto" msgstr "Slett konto"
@@ -342,13 +334,10 @@ msgstr "Dra lenken til bokmerkelinjen"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "E-post" msgstr "E-post"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "E-postadresse" msgstr "E-postadresse"
@@ -399,7 +388,6 @@ msgstr "Utvidelsesvalg"
msgid "Feed name" msgid "Feed name"
msgstr "Feednavn" msgstr "Feednavn"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "Laster abonnementer..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "Laster tagger..." msgstr "Laster tagger..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "Naviger til et abonnement ved å skrive inn navnet"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "Naviger til neste kategori/feed med uleste oppføringer når du markerer alle oppføringer som lest" msgstr "Naviger til neste kategori/feed med uleste oppføringer når du markerer alle oppføringer som lest"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "Aldri" msgstr "Aldri"
@@ -657,7 +643,6 @@ msgstr "Aldri"
msgid "New password" msgid "New password"
msgstr "Nytt passord" msgstr "Nytt passord"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "Nytt passord" msgstr "Nytt passord"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "OPML-eksport" msgstr "OPML-eksport"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "OPML-fil" msgstr "OPML-fil"
@@ -791,10 +775,7 @@ msgstr "Overordnet kategori"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "Passord" msgstr "Passord"
@@ -874,7 +855,6 @@ msgstr "Oppdater"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "Registreringer er stengt på denne CommaFeed-forekomsten" msgstr "Registreringer er stengt på denne CommaFeed-forekomsten"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "Tilbakestill passord" msgstr "Tilbakestill passord"
@@ -883,7 +863,6 @@ msgstr "Tilbakestill passord"
msgid "REST API" msgid "REST API"
msgstr "REST API" msgstr "REST API"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "Høyreklikk" msgstr "Høyreklikk"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "Rulling" msgstr "Rulling"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "Søk" msgstr "Søk"
@@ -924,7 +901,6 @@ msgstr "Velg neste uleste feed/kategori"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "Velg forrige uleste feed/kategori" msgstr "Velg forrige uleste feed/kategori"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "Server-URL" msgstr "Server-URL"
@@ -953,8 +929,6 @@ msgstr "Del"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "Delingssider" msgstr "Delingssider"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "Skift" msgstr "Skift"
@@ -1003,7 +977,6 @@ msgstr "Vis antall uleste i fanens favicon"
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "Vis antall uleste i fanetittelen" msgstr "Vis antall uleste i fanetittelen"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "Meld deg på"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "Noe ille skjedde akkurat..." msgstr "Noe ille skjedde akkurat..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "Mellomrom" msgstr "Mellomrom"
@@ -1030,7 +1002,6 @@ msgstr "Stjerne"
msgid "Starred" msgid "Starred"
msgstr "Stjerne" msgstr "Stjerne"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "Bytt til lystema"
msgid "System" msgid "System"
msgstr "System" msgstr "System"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "Tagger" msgstr "Tagger"
@@ -1136,7 +1106,6 @@ msgstr "Ulest"
msgid "Unstar" msgid "Unstar"
msgstr "Fjern stjerne" msgstr "Fjern stjerne"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "Avslutt abonnement" msgstr "Avslutt abonnement"
@@ -1149,7 +1118,6 @@ msgstr "Brukernøkkel"
msgid "User name" msgid "User name"
msgstr "Brukernavn" msgstr "Brukernavn"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "Brukernavn eller e-post" msgstr "Brukernavn eller e-post"

View File

@@ -60,7 +60,6 @@ msgstr "Gebruiker toevoegen"
msgid "Admin" msgid "Admin"
msgstr "Beheerder" msgstr "Beheerder"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "Gebruikersnaam beheerder" msgstr "Gebruikersnaam beheerder"
@@ -73,7 +72,6 @@ msgstr "Gebruikersnaam beheerder"
msgid "All" msgid "All"
msgstr "Alles" msgstr "Alles"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "Altijd" msgstr "Altijd"
@@ -173,18 +171,14 @@ msgstr "Maak een filterexpressie om aan te geven wat u wilt lezen. Items die nie
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "Annuleren" msgstr "Annuleren"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "Bevestigen"
msgid "Confirm password" msgid "Confirm password"
msgstr "Bevestig wachtwoord" msgstr "Bevestig wachtwoord"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "Bevestig wachtwoord" msgstr "Bevestig wachtwoord"
@@ -294,7 +287,6 @@ msgstr "dagen"
msgid "Delete" msgid "Delete"
msgstr "Verwijderen" msgstr "Verwijderen"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "Account verwijderen" msgstr "Account verwijderen"
@@ -342,13 +334,10 @@ msgstr "Link naar bladwijzerbalk slepen"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "E-mail" msgstr "E-mail"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "E-mailadres" msgstr "E-mailadres"
@@ -399,7 +388,6 @@ msgstr "Extensie opties"
msgid "Feed name" msgid "Feed name"
msgstr "Feednaam" msgstr "Feednaam"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "Abonnementen laden..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "Tags laden..." msgstr "Tags laden..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "Navigeer naar een abonnement door de naam in te voeren"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "Navigeer naar de volgende categorie/feed met ongelezen items wanneer alle items als gelezen worden gemarkeerd" msgstr "Navigeer naar de volgende categorie/feed met ongelezen items wanneer alle items als gelezen worden gemarkeerd"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "Nooit" msgstr "Nooit"
@@ -657,7 +643,6 @@ msgstr "Nooit"
msgid "New password" msgid "New password"
msgstr "Nieuw wachtwoord" msgstr "Nieuw wachtwoord"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "Nieuw wachtwoord" msgstr "Nieuw wachtwoord"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "OPML-export" msgstr "OPML-export"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "OPML-bestand" msgstr "OPML-bestand"
@@ -791,10 +775,7 @@ msgstr "Oudercategorie"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "Wachtwoord" msgstr "Wachtwoord"
@@ -874,7 +855,6 @@ msgstr "Vernieuwen"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "Registraties zijn gesloten op deze CommaFeed-instantie" msgstr "Registraties zijn gesloten op deze CommaFeed-instantie"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "Wachtwoord herstellen" msgstr "Wachtwoord herstellen"
@@ -883,7 +863,6 @@ msgstr "Wachtwoord herstellen"
msgid "REST API" msgid "REST API"
msgstr "REST-API" msgstr "REST-API"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "Rechtermuisklik" msgstr "Rechtermuisklik"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "Scrollen" msgstr "Scrollen"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "Zoeken" msgstr "Zoeken"
@@ -924,7 +901,6 @@ msgstr "Selecteer volgende ongelezen feed/categorie"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "Selecteer vorige ongelezen feed/categorie" msgstr "Selecteer vorige ongelezen feed/categorie"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "Server-URL" msgstr "Server-URL"
@@ -953,8 +929,6 @@ msgstr "Delen"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "Sites delen" msgstr "Sites delen"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "Shift" msgstr "Shift"
@@ -1003,7 +977,6 @@ msgstr "Toon aantal ongelezen in tabblad-favicon"
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "Toon aantal ongelezen in tabbladtitel" msgstr "Toon aantal ongelezen in tabbladtitel"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "Aanmelden"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "Er is net iets ergs gebeurd..." msgstr "Er is net iets ergs gebeurd..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "Ruimte" msgstr "Ruimte"
@@ -1030,7 +1002,6 @@ msgstr "Ster"
msgid "Starred" msgid "Starred"
msgstr "Met ster" msgstr "Met ster"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "Schakel over naar licht thema"
msgid "System" msgid "System"
msgstr "Systeem" msgstr "Systeem"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "Tags" msgstr "Tags"
@@ -1136,7 +1106,6 @@ msgstr "Ongelezen"
msgid "Unstar" msgid "Unstar"
msgstr "Sterren uit" msgstr "Sterren uit"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "Afmelden" msgstr "Afmelden"
@@ -1149,7 +1118,6 @@ msgstr "Gebruikerssleutel"
msgid "User name" msgid "User name"
msgstr "Gebruikersnaam" msgstr "Gebruikersnaam"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "Gebruikersnaam of e-mail" msgstr "Gebruikersnaam of e-mail"

View File

@@ -60,7 +60,6 @@ msgstr "Legg til brukar"
msgid "Admin" msgid "Admin"
msgstr "Administrator" msgstr "Administrator"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "Brukarnamn for administrator" msgstr "Brukarnamn for administrator"
@@ -73,7 +72,6 @@ msgstr "Brukarnamn for administrator"
msgid "All" msgid "All"
msgstr "Alle" msgstr "Alle"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "Alltid" msgstr "Alltid"
@@ -173,18 +171,14 @@ msgstr "Bygg eit filteruttrykk for å angis kva du vil lesa. Innlegg som ikkje s
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "Avbryt" msgstr "Avbryt"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "Bekreft"
msgid "Confirm password" msgid "Confirm password"
msgstr "Bekreft passord" msgstr "Bekreft passord"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "Stadfest passord" msgstr "Stadfest passord"
@@ -294,7 +287,6 @@ msgstr "dagar"
msgid "Delete" msgid "Delete"
msgstr "Slett" msgstr "Slett"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "Slett konto" msgstr "Slett konto"
@@ -342,13 +334,10 @@ msgstr "Dra lenken til bokmerkelinjen"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "E-post" msgstr "E-post"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "E-postadresse" msgstr "E-postadresse"
@@ -399,7 +388,6 @@ msgstr "Val for utviding"
msgid "Feed name" msgid "Feed name"
msgstr "Feednavn" msgstr "Feednavn"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "Laster abonnementer..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "Laster tagger..." msgstr "Laster tagger..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "Naviger til et abonnement ved å skrive inn navnet"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "Naviger til neste kategori/suap med ulesne innlegg når du markerer alle innlegg som lesne" msgstr "Naviger til neste kategori/suap med ulesne innlegg når du markerer alle innlegg som lesne"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "Aldri" msgstr "Aldri"
@@ -657,7 +643,6 @@ msgstr "Aldri"
msgid "New password" msgid "New password"
msgstr "Nytt passord" msgstr "Nytt passord"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "Nytt passord" msgstr "Nytt passord"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "OPML-eksport" msgstr "OPML-eksport"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "OPML-fil" msgstr "OPML-fil"
@@ -791,10 +775,7 @@ msgstr "Overordnet kategori"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "Passord" msgstr "Passord"
@@ -874,7 +855,6 @@ msgstr "Oppdater"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "Registreringer er stengt på denne CommaFeed-forekomsten" msgstr "Registreringer er stengt på denne CommaFeed-forekomsten"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "Tilbakestill passord" msgstr "Tilbakestill passord"
@@ -883,7 +863,6 @@ msgstr "Tilbakestill passord"
msgid "REST API" msgid "REST API"
msgstr "REST API" msgstr "REST API"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "Høgreklikk" msgstr "Høgreklikk"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "Rulling" msgstr "Rulling"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "Søk" msgstr "Søk"
@@ -924,7 +901,6 @@ msgstr "Vel neste ulesne suap/kategori"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "Vel førre ulesne suap/kategori" msgstr "Vel førre ulesne suap/kategori"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "Server-URL" msgstr "Server-URL"
@@ -953,8 +929,6 @@ msgstr "Del"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "Delingssider" msgstr "Delingssider"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "Skift" msgstr "Skift"
@@ -1003,7 +977,6 @@ msgstr "Vis talet på ulesne i favicon for fana"
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "Vis talet på ulesne i tittelen på fana" msgstr "Vis talet på ulesne i tittelen på fana"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "Meld deg på"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "Noe ille skjedde akkurat..." msgstr "Noe ille skjedde akkurat..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "Mellomrom" msgstr "Mellomrom"
@@ -1030,7 +1002,6 @@ msgstr "Stjerne"
msgid "Starred" msgid "Starred"
msgstr "Stjernemerka" msgstr "Stjernemerka"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "Bytt til lyst tema"
msgid "System" msgid "System"
msgstr "System" msgstr "System"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "Tagger" msgstr "Tagger"
@@ -1136,7 +1106,6 @@ msgstr "Ulesen"
msgid "Unstar" msgid "Unstar"
msgstr "Fjern stjerne" msgstr "Fjern stjerne"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "Avslutt abonnement" msgstr "Avslutt abonnement"
@@ -1149,7 +1118,6 @@ msgstr "Brukarnøkkel"
msgid "User name" msgid "User name"
msgstr "Brukarnamn" msgstr "Brukarnamn"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "Brukarnamn eller e-post" msgstr "Brukarnamn eller e-post"

View File

@@ -60,7 +60,6 @@ msgstr "Dodaj użytkownika"
msgid "Admin" msgid "Admin"
msgstr "Administracja" msgstr "Administracja"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "Nazwa użytkownika administratora" msgstr "Nazwa użytkownika administratora"
@@ -73,7 +72,6 @@ msgstr "Nazwa użytkownika administratora"
msgid "All" msgid "All"
msgstr "Wszystkie" msgstr "Wszystkie"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "Zawsze" msgstr "Zawsze"
@@ -173,18 +171,14 @@ msgstr "Zbuduj wyrażenie filtrujące, aby wskazać, co chcesz czytać. Wpisy, k
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "Anuluj" msgstr "Anuluj"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "Potwierdź"
msgid "Confirm password" msgid "Confirm password"
msgstr "Potwierdź hasło" msgstr "Potwierdź hasło"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "Potwierdź hasło" msgstr "Potwierdź hasło"
@@ -294,7 +287,6 @@ msgstr "dni"
msgid "Delete" msgid "Delete"
msgstr "Usuń" msgstr "Usuń"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "Usuń konto" msgstr "Usuń konto"
@@ -342,13 +334,10 @@ msgstr "Przeciągnij link do paska zakładek"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "E-mail" msgstr "E-mail"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "Adres e-mail" msgstr "Adres e-mail"
@@ -399,7 +388,6 @@ msgstr "Opcje rozszerzenia"
msgid "Feed name" msgid "Feed name"
msgstr "nazwa kanału" msgstr "nazwa kanału"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "Ładowanie subskrypcji..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "Ładowanie tagów..." msgstr "Ładowanie tagów..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "Przejdź do subskrypcji, wpisując jej nazwę"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "Przejdź do następnej kategorii/kanału z nieprzeczytanymi wpisami po oznaczeniu wszystkich wpisów jako przeczytane" msgstr "Przejdź do następnej kategorii/kanału z nieprzeczytanymi wpisami po oznaczeniu wszystkich wpisów jako przeczytane"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "Nigdy" msgstr "Nigdy"
@@ -657,7 +643,6 @@ msgstr "Nigdy"
msgid "New password" msgid "New password"
msgstr "Nowe hasło" msgstr "Nowe hasło"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "Nowe hasło" msgstr "Nowe hasło"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "Eksport OPML" msgstr "Eksport OPML"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "Plik OPML" msgstr "Plik OPML"
@@ -791,10 +775,7 @@ msgstr "Kategoria nadrzędna"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "Hasło" msgstr "Hasło"
@@ -874,7 +855,6 @@ msgstr "Odśwież"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "Rejestracje są zamknięte w tej instancji CommaFeed" msgstr "Rejestracje są zamknięte w tej instancji CommaFeed"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "Zresetuj hasło" msgstr "Zresetuj hasło"
@@ -883,7 +863,6 @@ msgstr "Zresetuj hasło"
msgid "REST API" msgid "REST API"
msgstr "REST API" msgstr "REST API"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "Prawe kliknięcie" msgstr "Prawe kliknięcie"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "Przewijanie" msgstr "Przewijanie"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "Szukaj" msgstr "Szukaj"
@@ -924,7 +901,6 @@ msgstr "Wybierz następny nieprzeczytany kanał/kategorię"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "Wybierz poprzedni nieprzeczytany kanał/kategorię" msgstr "Wybierz poprzedni nieprzeczytany kanał/kategorię"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "URL serwera" msgstr "URL serwera"
@@ -953,8 +929,6 @@ msgstr "Udostępnij"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "Udostępnianie witryn" msgstr "Udostępnianie witryn"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "zmiana" msgstr "zmiana"
@@ -1003,7 +977,6 @@ msgstr "Pokazuj liczbę nieprzeczytanych na ikonie karty"
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "Pokazuj liczbę nieprzeczytanych w tytule karty" msgstr "Pokazuj liczbę nieprzeczytanych w tytule karty"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "Zarejestruj się"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "Coś złego właśnie się stało..." msgstr "Coś złego właśnie się stało..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "Przestrzeń" msgstr "Przestrzeń"
@@ -1030,7 +1002,6 @@ msgstr "Gwiazda"
msgid "Starred" msgid "Starred"
msgstr "Oznaczone gwiazdką" msgstr "Oznaczone gwiazdką"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "Przełącz na jasny motyw"
msgid "System" msgid "System"
msgstr "Systemowy" msgstr "Systemowy"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "Tagi" msgstr "Tagi"
@@ -1136,7 +1106,6 @@ msgstr "Nieprzeczytane"
msgid "Unstar" msgid "Unstar"
msgstr "Usuń gwiazdkę" msgstr "Usuń gwiazdkę"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "Anuluj subskrypcję" msgstr "Anuluj subskrypcję"
@@ -1149,7 +1118,6 @@ msgstr "Klucz użytkownika"
msgid "User name" msgid "User name"
msgstr "Nazwa użytkownika" msgstr "Nazwa użytkownika"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "Nazwa użytkownika lub e-mail" msgstr "Nazwa użytkownika lub e-mail"

View File

@@ -60,7 +60,6 @@ msgstr "Adicionar usuário"
msgid "Admin" msgid "Admin"
msgstr "Administrador" msgstr "Administrador"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "Nome de usuário do administrador" msgstr "Nome de usuário do administrador"
@@ -73,7 +72,6 @@ msgstr "Nome de usuário do administrador"
msgid "All" msgid "All"
msgstr "Todos" msgstr "Todos"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "Sempre" msgstr "Sempre"
@@ -173,18 +171,14 @@ msgstr "Crie uma expressão de filtro para indicar o que você deseja ler. As en
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "Cancelar" msgstr "Cancelar"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "Confirmar"
msgid "Confirm password" msgid "Confirm password"
msgstr "Confirmar senha" msgstr "Confirmar senha"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "Confirmar senha" msgstr "Confirmar senha"
@@ -294,7 +287,6 @@ msgstr "dias"
msgid "Delete" msgid "Delete"
msgstr "Excluir" msgstr "Excluir"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "Excluir conta" msgstr "Excluir conta"
@@ -342,13 +334,10 @@ msgstr "Arraste o link para a barra de favoritos"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "E-mail" msgstr "E-mail"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "Endereço de e-mail" msgstr "Endereço de e-mail"
@@ -399,7 +388,6 @@ msgstr "Opções da extensão"
msgid "Feed name" msgid "Feed name"
msgstr "Nome do feed" msgstr "Nome do feed"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "Carregando assinaturas..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "Carregando tags..." msgstr "Carregando tags..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "Navegue até uma assinatura digitando seu nome"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "Navegar para a próxima categoria/feed com entradas não lidas quando todas as entrafas forem lidas" msgstr "Navegar para a próxima categoria/feed com entradas não lidas quando todas as entrafas forem lidas"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "Nunca" msgstr "Nunca"
@@ -657,7 +643,6 @@ msgstr "Nunca"
msgid "New password" msgid "New password"
msgstr "Nova senha" msgstr "Nova senha"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "Nova senha" msgstr "Nova senha"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "Exportação OPML" msgstr "Exportação OPML"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "Arquivo OPML" msgstr "Arquivo OPML"
@@ -791,10 +775,7 @@ msgstr "Categoria Pai"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "Senha" msgstr "Senha"
@@ -874,7 +855,6 @@ msgstr "Atualizar"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "Os registros estão fechados nesta instância do CommaFeed" msgstr "Os registros estão fechados nesta instância do CommaFeed"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "Redefinir senha" msgstr "Redefinir senha"
@@ -883,7 +863,6 @@ msgstr "Redefinir senha"
msgid "REST API" msgid "REST API"
msgstr "API REST" msgstr "API REST"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "Clique com o botão direito" msgstr "Clique com o botão direito"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "Deslizar" msgstr "Deslizar"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "Pesquisar" msgstr "Pesquisar"
@@ -924,7 +901,6 @@ msgstr "Selecionar próximo feed/categoria não lido"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "Selecionar feed/categoria não lido anterior" msgstr "Selecionar feed/categoria não lido anterior"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "URL do servidor" msgstr "URL do servidor"
@@ -953,8 +929,6 @@ msgstr "Compartilhar"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "Compartilhando sites" msgstr "Compartilhando sites"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "Shift" msgstr "Shift"
@@ -1003,7 +977,6 @@ msgstr "Mostrar contagem de não lidos no favion da aba"
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "Mostrar contagem de não lidos no título da aba" msgstr "Mostrar contagem de não lidos no título da aba"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "Inscreva-se"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "Algo ruim acabou de acontecer..." msgstr "Algo ruim acabou de acontecer..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "Espaço" msgstr "Espaço"
@@ -1030,7 +1002,6 @@ msgstr "Estrela"
msgid "Starred" msgid "Starred"
msgstr "Com estrela" msgstr "Com estrela"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "Mudar para tema claro"
msgid "System" msgid "System"
msgstr "Sistema" msgstr "Sistema"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "Etiquetas" msgstr "Etiquetas"
@@ -1136,7 +1106,6 @@ msgstr "Não lido"
msgid "Unstar" msgid "Unstar"
msgstr "Desestrelar" msgstr "Desestrelar"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "Cancelar inscrição" msgstr "Cancelar inscrição"
@@ -1149,7 +1118,6 @@ msgstr "Chave do usuário"
msgid "User name" msgid "User name"
msgstr "Nome de usuário" msgstr "Nome de usuário"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "Nome de usuário ou e-mail" msgstr "Nome de usuário ou e-mail"

View File

@@ -60,7 +60,6 @@ msgstr "Добавить пользователя"
msgid "Admin" msgid "Admin"
msgstr "Админ" msgstr "Админ"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "Имя администратора" msgstr "Имя администратора"
@@ -73,7 +72,6 @@ msgstr "Имя администратора"
msgid "All" msgid "All"
msgstr "Все" msgstr "Все"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "Всегда" msgstr "Всегда"
@@ -173,18 +171,14 @@ msgstr "Создайте выражение фильтра, чтобы указ
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "Отмена" msgstr "Отмена"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "Подтвердить"
msgid "Confirm password" msgid "Confirm password"
msgstr "Подтвердить пароль" msgstr "Подтвердить пароль"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "Подтвердите пароль" msgstr "Подтвердите пароль"
@@ -294,7 +287,6 @@ msgstr "дней"
msgid "Delete" msgid "Delete"
msgstr "Удалить" msgstr "Удалить"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "Удалить учетную запись" msgstr "Удалить учетную запись"
@@ -342,13 +334,10 @@ msgstr "Перетащите ссылку на панель закладок"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "Электронная почта" msgstr "Электронная почта"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "Адрес электронной почты" msgstr "Адрес электронной почты"
@@ -399,7 +388,6 @@ msgstr "Параметры расширения"
msgid "Feed name" msgid "Feed name"
msgstr "Имя фида" msgstr "Имя фида"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "Загрузка подписок..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "Загрузка тегов..." msgstr "Загрузка тегов..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "Перейдите к подписке, введя ее имя."
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "Переходить к следующей категории/фиду с непрочитанными записями при пометке всех записей как прочитанных" msgstr "Переходить к следующей категории/фиду с непрочитанными записями при пометке всех записей как прочитанных"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "Никогда" msgstr "Никогда"
@@ -657,7 +643,6 @@ msgstr "Никогда"
msgid "New password" msgid "New password"
msgstr "Новый пароль" msgstr "Новый пароль"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "Новый пароль" msgstr "Новый пароль"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "Экспорт OPML" msgstr "Экспорт OPML"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "OPML файл" msgstr "OPML файл"
@@ -791,10 +775,7 @@ msgstr "Родительская категория"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "Пароль" msgstr "Пароль"
@@ -874,7 +855,6 @@ msgstr "Обновить"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "Регистрация закрыта для этого экземпляра CommaFeed." msgstr "Регистрация закрыта для этого экземпляра CommaFeed."
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "Сброс пароля" msgstr "Сброс пароля"
@@ -883,7 +863,6 @@ msgstr "Сброс пароля"
msgid "REST API" msgid "REST API"
msgstr "REST API" msgstr "REST API"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "Правый клик" msgstr "Правый клик"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "Прокрутка" msgstr "Прокрутка"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "Поиск" msgstr "Поиск"
@@ -924,7 +901,6 @@ msgstr "Выбрать следующий непрочитанный фид/ка
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "Выбрать предыдущий непрочитанный фид/категорию" msgstr "Выбрать предыдущий непрочитанный фид/категорию"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "URL сервера" msgstr "URL сервера"
@@ -953,8 +929,6 @@ msgstr "Поделиться"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "Обмен сайтами" msgstr "Обмен сайтами"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "Shift" msgstr "Shift"
@@ -1003,7 +977,6 @@ msgstr "Показывать количество непрочитанных в
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "Показывать количество непрочитанных в заголовке вкладки" msgstr "Показывать количество непрочитанных в заголовке вкладки"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "Зарегистрироваться"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "Только что случилось что-то плохое..." msgstr "Только что случилось что-то плохое..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "Пробел" msgstr "Пробел"
@@ -1030,7 +1002,6 @@ msgstr "В избранное"
msgid "Starred" msgid "Starred"
msgstr "Избранное" msgstr "Избранное"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "Переключиться на светлую тему"
msgid "System" msgid "System"
msgstr "Системная" msgstr "Системная"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "Теги" msgstr "Теги"
@@ -1136,7 +1106,6 @@ msgstr "Не прочитано"
msgid "Unstar" msgid "Unstar"
msgstr "Удалить из избранного" msgstr "Удалить из избранного"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "Отписаться" msgstr "Отписаться"
@@ -1149,7 +1118,6 @@ msgstr "Ключ пользователя"
msgid "User name" msgid "User name"
msgstr "Имя пользователя" msgstr "Имя пользователя"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "Имя пользователя или адрес электронной почты" msgstr "Имя пользователя или адрес электронной почты"

View File

@@ -60,7 +60,6 @@ msgstr "Pridať užívateľa"
msgid "Admin" msgid "Admin"
msgstr "Správca" msgstr "Správca"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "Meno správcu" msgstr "Meno správcu"
@@ -73,7 +72,6 @@ msgstr "Meno správcu"
msgid "All" msgid "All"
msgstr "Všetky" msgstr "Všetky"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "Vždy" msgstr "Vždy"
@@ -173,18 +171,14 @@ msgstr "Vytvorte výraz filtra na určenie toho, čo chcete čítať. Záznamy,
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "Zrušiť" msgstr "Zrušiť"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "Potvrdiť"
msgid "Confirm password" msgid "Confirm password"
msgstr "Potvrďte heslo" msgstr "Potvrďte heslo"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "Potvrdiť heslo" msgstr "Potvrdiť heslo"
@@ -294,7 +287,6 @@ msgstr "dni"
msgid "Delete" msgid "Delete"
msgstr "Vymazať" msgstr "Vymazať"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "Vymažte účet" msgstr "Vymažte účet"
@@ -342,13 +334,10 @@ msgstr "Presuňte odkaz na lištu so záložkami"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "E-mail" msgstr "E-mail"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "E-mailová adresa" msgstr "E-mailová adresa"
@@ -399,7 +388,6 @@ msgstr "Možnosti rozšírenia"
msgid "Feed name" msgid "Feed name"
msgstr "Názov informačného kanála" msgstr "Názov informačného kanála"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "Načítavam odbery..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "Načítavam značky..." msgstr "Načítavam značky..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "Prejdite na predplatné zadaním jeho názvu"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "Pri označovaní všetkých položiek ako prečítaných prejdite na ďalšiu kategóriu/kanál s neprečítanými položkami" msgstr "Pri označovaní všetkých položiek ako prečítaných prejdite na ďalšiu kategóriu/kanál s neprečítanými položkami"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "Nikdy" msgstr "Nikdy"
@@ -657,7 +643,6 @@ msgstr "Nikdy"
msgid "New password" msgid "New password"
msgstr "Nové heslo" msgstr "Nové heslo"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "Nové heslo" msgstr "Nové heslo"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "Export OPML" msgstr "Export OPML"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "Súbor OPML" msgstr "Súbor OPML"
@@ -791,10 +775,7 @@ msgstr "Rodičovská kategória"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "Heslo" msgstr "Heslo"
@@ -874,7 +855,6 @@ msgstr "Obnoviť"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "V tejto inštancii CommaFeed sú registrácie uzavreté" msgstr "V tejto inštancii CommaFeed sú registrácie uzavreté"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "Obnoviť heslo" msgstr "Obnoviť heslo"
@@ -883,7 +863,6 @@ msgstr "Obnoviť heslo"
msgid "REST API" msgid "REST API"
msgstr "REST API" msgstr "REST API"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "Kliknutie pravým tlačidlom" msgstr "Kliknutie pravým tlačidlom"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "Rolovanie" msgstr "Rolovanie"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "Hľadaj" msgstr "Hľadaj"
@@ -924,7 +901,6 @@ msgstr "Vybrať ďalší neprečítaný kanál/kategóriu"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "Vybrať predchádzajúci neprečítaný kanál/kategóriu" msgstr "Vybrať predchádzajúci neprečítaný kanál/kategóriu"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "URL servera" msgstr "URL servera"
@@ -953,8 +929,6 @@ msgstr "Zdieľať"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "Zdieľanie stránok" msgstr "Zdieľanie stránok"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "Smena" msgstr "Smena"
@@ -1003,7 +977,6 @@ msgstr "Zobraziť počet neprečítaných v ikone karty"
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "Zobraziť počet neprečítaných v názve karty" msgstr "Zobraziť počet neprečítaných v názve karty"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "Zaregistrujte sa"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "Práve sa stalo niečo zlé..." msgstr "Práve sa stalo niečo zlé..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "Medzera" msgstr "Medzera"
@@ -1030,7 +1002,6 @@ msgstr "Hviezda"
msgid "Starred" msgid "Starred"
msgstr "S hviezdičkou" msgstr "S hviezdičkou"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "Prepnite na svetlú tému"
msgid "System" msgid "System"
msgstr "Systém" msgstr "Systém"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "Značky" msgstr "Značky"
@@ -1136,7 +1106,6 @@ msgstr "Neprečítané"
msgid "Unstar" msgid "Unstar"
msgstr "Odobrať hviezdičku" msgstr "Odobrať hviezdičku"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "Zrušte odber" msgstr "Zrušte odber"
@@ -1149,7 +1118,6 @@ msgstr "Používateľský kľúč"
msgid "User name" msgid "User name"
msgstr "Meno používateľa" msgstr "Meno používateľa"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "Meno používateľa alebo e-mail" msgstr "Meno používateľa alebo e-mail"

View File

@@ -60,7 +60,6 @@ msgstr "Lägg till användare"
msgid "Admin" msgid "Admin"
msgstr "Admin" msgstr "Admin"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "Administratörsanvändarnamn" msgstr "Administratörsanvändarnamn"
@@ -73,7 +72,6 @@ msgstr "Administratörsanvändarnamn"
msgid "All" msgid "All"
msgstr "Alla" msgstr "Alla"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "Alltid" msgstr "Alltid"
@@ -173,18 +171,14 @@ msgstr "Skapa ett filteruttryck för att ange vad du vill läsa. Poster som inte
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "Avbryt" msgstr "Avbryt"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "Bekräfta"
msgid "Confirm password" msgid "Confirm password"
msgstr "Bekräfta lösenord" msgstr "Bekräfta lösenord"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "Bekräfta lösenord" msgstr "Bekräfta lösenord"
@@ -294,7 +287,6 @@ msgstr "dagar"
msgid "Delete" msgid "Delete"
msgstr "Ta bort" msgstr "Ta bort"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "Radera konto" msgstr "Radera konto"
@@ -342,13 +334,10 @@ msgstr "Dra länken till bokmärkesfältet"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "E-post" msgstr "E-post"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "E-postadress" msgstr "E-postadress"
@@ -399,7 +388,6 @@ msgstr "Tilläggsalternativ"
msgid "Feed name" msgid "Feed name"
msgstr "Flödesnamn" msgstr "Flödesnamn"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "Laddar prenumerationer..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "Laddar taggar..." msgstr "Laddar taggar..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "Navigera till ett abonnemang genom att ange dess namn"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "Navigera till nästa kategori/flöde med olästa poster när alla poster markeras som lästa" msgstr "Navigera till nästa kategori/flöde med olästa poster när alla poster markeras som lästa"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "Aldrig" msgstr "Aldrig"
@@ -657,7 +643,6 @@ msgstr "Aldrig"
msgid "New password" msgid "New password"
msgstr "Nytt lösenord" msgstr "Nytt lösenord"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "Nytt lösenord" msgstr "Nytt lösenord"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "OPML-export" msgstr "OPML-export"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "OPML-fil" msgstr "OPML-fil"
@@ -791,10 +775,7 @@ msgstr "Föräldrakategori"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "Lösenord" msgstr "Lösenord"
@@ -874,7 +855,6 @@ msgstr "Uppdatera"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "Registreringar är stängda på denna CommaFeed-instans" msgstr "Registreringar är stängda på denna CommaFeed-instans"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "Återställ lösenord" msgstr "Återställ lösenord"
@@ -883,7 +863,6 @@ msgstr "Återställ lösenord"
msgid "REST API" msgid "REST API"
msgstr "REST API" msgstr "REST API"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "Högerklick" msgstr "Högerklick"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "Rullning" msgstr "Rullning"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "Sök" msgstr "Sök"
@@ -924,7 +901,6 @@ msgstr "Välj nästa olästa flöde/kategori"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "Välj föregående olästa flöde/kategori" msgstr "Välj föregående olästa flöde/kategori"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "Server-URL" msgstr "Server-URL"
@@ -953,8 +929,6 @@ msgstr "Dela"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "Delningssajter" msgstr "Delningssajter"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "Skift" msgstr "Skift"
@@ -1003,7 +977,6 @@ msgstr "Visa antal olästa i flikikonen"
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "Visa antal olästa i fliktiteln" msgstr "Visa antal olästa i fliktiteln"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "Anmäl dig"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "Något dåligt hände precis..." msgstr "Något dåligt hände precis..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "Rymden" msgstr "Rymden"
@@ -1030,7 +1002,6 @@ msgstr "Stjärna"
msgid "Starred" msgid "Starred"
msgstr "Starmed" msgstr "Starmed"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "Byt till ljustema"
msgid "System" msgid "System"
msgstr "System" msgstr "System"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "Taggar" msgstr "Taggar"
@@ -1136,7 +1106,6 @@ msgstr "Oläst"
msgid "Unstar" msgid "Unstar"
msgstr "Ta bort stjärna" msgstr "Ta bort stjärna"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "Avsluta prenumeration" msgstr "Avsluta prenumeration"
@@ -1149,7 +1118,6 @@ msgstr "Användarnyckel"
msgid "User name" msgid "User name"
msgstr "Användarnamn" msgstr "Användarnamn"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "Användarnamn eller e-post" msgstr "Användarnamn eller e-post"

View File

@@ -60,7 +60,6 @@ msgstr "Kullanıcı ekle"
msgid "Admin" msgid "Admin"
msgstr "Yönetici" msgstr "Yönetici"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "Yönetici kullanıcı adı" msgstr "Yönetici kullanıcı adı"
@@ -73,7 +72,6 @@ msgstr "Yönetici kullanıcı adı"
msgid "All" msgid "All"
msgstr "Tümü" msgstr "Tümü"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "Her zaman" msgstr "Her zaman"
@@ -173,18 +171,14 @@ msgstr "Ne okumak istediğinizi belirtmek için bir filtre ifadesi oluşturun. E
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "İptal" msgstr "İptal"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "Onayla"
msgid "Confirm password" msgid "Confirm password"
msgstr "Şifreyi onayla" msgstr "Şifreyi onayla"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "Şifreyi Onayla" msgstr "Şifreyi Onayla"
@@ -294,7 +287,6 @@ msgstr "gün"
msgid "Delete" msgid "Delete"
msgstr "Sil" msgstr "Sil"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "Hesabı sil" msgstr "Hesabı sil"
@@ -342,13 +334,10 @@ msgstr "Bağlantıyı yer işareti çubuğuna sürükleyin"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "E-posta" msgstr "E-posta"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "E-posta adresi" msgstr "E-posta adresi"
@@ -399,7 +388,6 @@ msgstr "Eklenti ayarları"
msgid "Feed name" msgid "Feed name"
msgstr "Yayın adı" msgstr "Yayın adı"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "Abonelikler yükleniyor..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "Etiketler yükleniyor..." msgstr "Etiketler yükleniyor..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "Adını girerek bir aboneliğe gidin"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "Tüm girişleri okundu olarak işaretlerken okunmamış girişleri olan bir sonraki kategoriye/beslemeye git" msgstr "Tüm girişleri okundu olarak işaretlerken okunmamış girişleri olan bir sonraki kategoriye/beslemeye git"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "Asla" msgstr "Asla"
@@ -657,7 +643,6 @@ msgstr "Asla"
msgid "New password" msgid "New password"
msgstr "Yeni şifre" msgstr "Yeni şifre"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "Yeni Şifre" msgstr "Yeni Şifre"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "OPML dışa aktarma" msgstr "OPML dışa aktarma"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "OPML dosyası" msgstr "OPML dosyası"
@@ -791,10 +775,7 @@ msgstr "Üst Kategori"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "Şifre" msgstr "Şifre"
@@ -874,7 +855,6 @@ msgstr "Yenile"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "Bu CommaFeed örneğinde kayıtlar kapalı" msgstr "Bu CommaFeed örneğinde kayıtlar kapalı"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "Şifreyi Sıfırla" msgstr "Şifreyi Sıfırla"
@@ -883,7 +863,6 @@ msgstr "Şifreyi Sıfırla"
msgid "REST API" msgid "REST API"
msgstr "REST API" msgstr "REST API"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "Sağ tık" msgstr "Sağ tık"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "Kaydırma" msgstr "Kaydırma"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "Ara" msgstr "Ara"
@@ -924,7 +901,6 @@ msgstr "Sonraki okunmamış beslemeyi/kategoriyi seç"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "Önceki okunmamış beslemeyi/kategoriyi seç" msgstr "Önceki okunmamış beslemeyi/kategoriyi seç"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "Sunucu URL'si" msgstr "Sunucu URL'si"
@@ -953,8 +929,6 @@ msgstr "Paylaş"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "Siteleri paylaşma" msgstr "Siteleri paylaşma"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "Vardiya" msgstr "Vardiya"
@@ -1003,7 +977,6 @@ msgstr "Sekme simgesinde okunmamış sayısını göster"
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "Sekme başlığında okunmamış sayısını göster" msgstr "Sekme başlığında okunmamış sayısını göster"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "Kaydolun"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "Az önce kötü bir şey oldu..." msgstr "Az önce kötü bir şey oldu..."
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "Uzay" msgstr "Uzay"
@@ -1030,7 +1002,6 @@ msgstr "Yıldız"
msgid "Starred" msgid "Starred"
msgstr "Yıldızlı" msgstr "Yıldızlı"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "Aydınlık temaya geç"
msgid "System" msgid "System"
msgstr "Sistem" msgstr "Sistem"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "Etiketler" msgstr "Etiketler"
@@ -1136,7 +1106,6 @@ msgstr "Okunmamış"
msgid "Unstar" msgid "Unstar"
msgstr "Yıldızı kaldır" msgstr "Yıldızı kaldır"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "Aboneliği iptal et" msgstr "Aboneliği iptal et"
@@ -1149,7 +1118,6 @@ msgstr "Kullanıcı anahtarı"
msgid "User name" msgid "User name"
msgstr "Kullanıcı adı" msgstr "Kullanıcı adı"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "Kullanıcı Adı veya E-posta" msgstr "Kullanıcı Adı veya E-posta"

View File

@@ -60,7 +60,6 @@ msgstr "添加用户"
msgid "Admin" msgid "Admin"
msgstr "管理员" msgstr "管理员"
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
msgid "Admin user name" msgid "Admin user name"
msgstr "管理员用户名" msgstr "管理员用户名"
@@ -73,7 +72,6 @@ msgstr "管理员用户名"
msgid "All" msgid "All"
msgstr "全部" msgstr "全部"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Always" msgid "Always"
msgstr "总是" msgstr "总是"
@@ -173,18 +171,14 @@ msgstr "构建过滤表达式以指示您想阅读的内容。不匹配的条目
#: src/components/MarkAllAsReadConfirmationDialog.tsx #: src/components/MarkAllAsReadConfirmationDialog.tsx
#: src/components/settings/CustomCodeSettings.tsx #: src/components/settings/CustomCodeSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx #: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/CategoryDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/TagDetailsPage.tsx #: src/pages/app/TagDetailsPage.tsx
msgid "Cancel" msgid "Cancel"
msgstr "取消" msgstr "取消"
#: src/components/content/add/AddCategory.tsx
#: src/components/content/add/AddCategory.tsx #: src/components/content/add/AddCategory.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AboutPage.tsx #: src/pages/app/AboutPage.tsx
@@ -240,7 +234,6 @@ msgstr "确认"
msgid "Confirm password" msgid "Confirm password"
msgstr "确认密码" msgstr "确认密码"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Confirm Password" msgid "Confirm Password"
msgstr "确认密码" msgstr "确认密码"
@@ -294,7 +287,6 @@ msgstr "天"
msgid "Delete" msgid "Delete"
msgstr "删除" msgstr "删除"
#: src/components/settings/ProfileSettings.tsx
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
msgid "Delete account" msgid "Delete account"
msgstr "删除帐号" msgstr "删除帐号"
@@ -342,13 +334,10 @@ msgstr "拖动链接到书签栏"
#: src/components/settings/ProfileSettings.tsx #: src/components/settings/ProfileSettings.tsx
#: src/pages/admin/AdminUsersPage.tsx #: src/pages/admin/AdminUsersPage.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx
#: src/pages/auth/PasswordRecoveryPage.tsx #: src/pages/auth/PasswordRecoveryPage.tsx
msgid "E-mail" msgid "E-mail"
msgstr "电子邮件" msgstr "电子邮件"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "E-mail address" msgid "E-mail address"
msgstr "电子邮件地址" msgstr "电子邮件地址"
@@ -399,7 +388,6 @@ msgstr "扩展选项"
msgid "Feed name" msgid "Feed name"
msgstr "信息流名称" msgstr "信息流名称"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Feed URL" msgid "Feed URL"
@@ -570,7 +558,6 @@ msgstr "正在加载订阅..."
msgid "Loading tags..." msgid "Loading tags..."
msgstr "正在加载标签..." msgstr "正在加载标签..."
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Log in" msgid "Log in"
@@ -648,7 +635,6 @@ msgstr "通过输入订阅名称导航到订阅"
msgid "Navigate to the next category/feed with unread entries when marking all entries as read" msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
msgstr "将所有条目标记为已读时导航到下一个包含未读条目的类别/信息流" msgstr "将所有条目标记为已读时导航到下一个包含未读条目的类别/信息流"
#: src/components/settings/DisplaySettings.tsx
#: src/components/settings/DisplaySettings.tsx #: src/components/settings/DisplaySettings.tsx
msgid "Never" msgid "Never"
msgstr "从不" msgstr "从不"
@@ -657,7 +643,6 @@ msgstr "从不"
msgid "New password" msgid "New password"
msgstr "新密码" msgstr "新密码"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "New Password" msgid "New Password"
msgstr "新密码" msgstr "新密码"
@@ -764,7 +749,6 @@ msgstr "OPML"
msgid "OPML export" msgid "OPML export"
msgstr "OPML 导出" msgstr "OPML 导出"
#: src/components/content/add/ImportOpml.tsx
#: src/components/content/add/ImportOpml.tsx #: src/components/content/add/ImportOpml.tsx
msgid "OPML file" msgid "OPML file"
msgstr "OPML 文件" msgstr "OPML 文件"
@@ -791,10 +775,7 @@ msgstr "父类别"
#: src/components/admin/UserEdit.tsx #: src/components/admin/UserEdit.tsx
#: src/pages/auth/InitialSetupPage.tsx #: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/InitialSetupPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
msgid "Password" msgid "Password"
msgstr "密码" msgstr "密码"
@@ -874,7 +855,6 @@ msgstr "刷新"
msgid "Registrations are closed on this CommaFeed instance" msgid "Registrations are closed on this CommaFeed instance"
msgstr "此 CommaFeed 实例上的注册已关闭" msgstr "此 CommaFeed 实例上的注册已关闭"
#: src/pages/auth/PasswordResetPage.tsx
#: src/pages/auth/PasswordResetPage.tsx #: src/pages/auth/PasswordResetPage.tsx
msgid "Reset Password" msgid "Reset Password"
msgstr "重置密码" msgstr "重置密码"
@@ -883,7 +863,6 @@ msgstr "重置密码"
msgid "REST API" msgid "REST API"
msgstr "REST API" msgstr "REST API"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Right click" msgid "Right click"
msgstr "右键单击" msgstr "右键单击"
@@ -910,8 +889,6 @@ msgid "Scrolling"
msgstr "滚动" msgstr "滚动"
#: src/components/header/Header.tsx #: src/components/header/Header.tsx
#: src/components/header/Header.tsx
#: src/components/sidebar/TreeSearch.tsx
#: src/components/sidebar/TreeSearch.tsx #: src/components/sidebar/TreeSearch.tsx
msgid "Search" msgid "Search"
msgstr "搜索" msgstr "搜索"
@@ -924,7 +901,6 @@ msgstr "选择下一个未读信息流/类别"
msgid "Select previous unread feed/category" msgid "Select previous unread feed/category"
msgstr "选择上一个未读信息流/类别" msgstr "选择上一个未读信息流/类别"
#: src/components/settings/PushNotificationSettings.tsx
#: src/components/settings/PushNotificationSettings.tsx #: src/components/settings/PushNotificationSettings.tsx
msgid "Server URL" msgid "Server URL"
msgstr "服务器网址" msgstr "服务器网址"
@@ -953,8 +929,6 @@ msgstr "分享"
msgid "Sharing sites" msgid "Sharing sites"
msgstr "共享站点" msgstr "共享站点"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Shift" msgid "Shift"
msgstr "Shift" msgstr "Shift"
@@ -1003,7 +977,6 @@ msgstr "在标签页图标上显示未读数量"
msgid "Show unread count in tab title" msgid "Show unread count in tab title"
msgstr "在标签页标题中显示未读数量" msgstr "在标签页标题中显示未读数量"
#: src/pages/auth/RegistrationPage.tsx
#: src/pages/auth/RegistrationPage.tsx #: src/pages/auth/RegistrationPage.tsx
#: src/pages/WelcomePage.tsx #: src/pages/WelcomePage.tsx
msgid "Sign up" msgid "Sign up"
@@ -1013,7 +986,6 @@ msgstr "注册"
msgid "Something bad just happened..." msgid "Something bad just happened..."
msgstr "刚刚发生了不好的事情……" msgstr "刚刚发生了不好的事情……"
#: src/components/KeyboardShortcutsHelp.tsx
#: src/components/KeyboardShortcutsHelp.tsx #: src/components/KeyboardShortcutsHelp.tsx
msgid "Space" msgid "Space"
msgstr "空格" msgstr "空格"
@@ -1030,7 +1002,6 @@ msgstr "星标"
msgid "Starred" msgid "Starred"
msgstr "已加星标" msgstr "已加星标"
#: src/components/content/add/Subscribe.tsx
#: src/components/content/add/Subscribe.tsx #: src/components/content/add/Subscribe.tsx
#: src/pages/app/AddPage.tsx #: src/pages/app/AddPage.tsx
msgid "Subscribe" msgid "Subscribe"
@@ -1064,7 +1035,6 @@ msgstr "切换到浅色主题"
msgid "System" msgid "System"
msgstr "跟随系统" msgstr "跟随系统"
#: src/components/content/FeedEntryFooter.tsx
#: src/components/content/FeedEntryFooter.tsx #: src/components/content/FeedEntryFooter.tsx
msgid "Tags" msgid "Tags"
msgstr "标签" msgstr "标签"
@@ -1136,7 +1106,6 @@ msgstr "未读"
msgid "Unstar" msgid "Unstar"
msgstr "取消星标" msgstr "取消星标"
#: src/pages/app/FeedDetailsPage.tsx
#: src/pages/app/FeedDetailsPage.tsx #: src/pages/app/FeedDetailsPage.tsx
msgid "Unsubscribe" msgid "Unsubscribe"
msgstr "取消订阅" msgstr "取消订阅"
@@ -1149,7 +1118,6 @@ msgstr "用户密钥"
msgid "User name" msgid "User name"
msgstr "用户名" msgstr "用户名"
#: src/pages/auth/LoginPage.tsx
#: src/pages/auth/LoginPage.tsx #: src/pages/auth/LoginPage.tsx
msgid "User Name or E-mail" msgid "User Name or E-mail"
msgstr "用户名或电子邮件" msgstr "用户名或电子邮件"

View File

@@ -8,9 +8,11 @@ import { Constants } from "@/app/constants"
import type { EntrySourceType } from "@/app/entries/slice" import type { EntrySourceType } from "@/app/entries/slice"
import { loadEntries } from "@/app/entries/thunks" import { loadEntries } from "@/app/entries/thunks"
import { redirectToCategoryDetails, redirectToFeedDetails, redirectToTagDetails } from "@/app/redirect/thunks" import { redirectToCategoryDetails, redirectToFeedDetails, redirectToTagDetails } from "@/app/redirect/thunks"
import { useAppDispatch, useAppSelector } from "@/app/store" import { useAppDispatch, useAppSelector, useShallowEqualAppSelector } from "@/app/store"
import { flattenCategoryTree } from "@/app/utils" import { categoryHasNewEntries, categoryUnreadCount, flattenCategoryTree } from "@/app/utils"
import { FeedEntries } from "@/components/content/FeedEntries" import { FeedEntries } from "@/components/content/FeedEntries"
import { UnreadCount } from "@/components/sidebar/UnreadCount"
import { useMobile } from "@/hooks/useMobile"
import { tss } from "@/tss" import { tss } from "@/tss"
function NoSubscriptionHelp() { function NoSubscriptionHelp() {
@@ -33,6 +35,12 @@ const useStyles = tss.create(() => ({
sourceWebsiteLink: { sourceWebsiteLink: {
color: "inherit", color: "inherit",
textDecoration: "none", textDecoration: "none",
overflow: "hidden",
},
titleText: {
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
}, },
})) }))
@@ -48,6 +56,33 @@ export function FeedEntriesPage(props: Readonly<FeedEntriesPageProps>) {
const sourceLabel = useAppSelector(state => state.entries.sourceLabel) const sourceLabel = useAppSelector(state => state.entries.sourceLabel)
const sourceWebsiteUrl = useAppSelector(state => state.entries.sourceWebsiteUrl) const sourceWebsiteUrl = useAppSelector(state => state.entries.sourceWebsiteUrl)
const hasMore = useAppSelector(state => state.entries.hasMore) const hasMore = useAppSelector(state => state.entries.hasMore)
const mobile = useMobile()
const sidebarVisible = useAppSelector(state => state.tree.sidebarVisible)
const { unreadCount, hasNewEntries } = useShallowEqualAppSelector(state => {
const root = state.tree.rootCategory
if (!root) return { unreadCount: 0, hasNewEntries: false }
if (props.sourceType === "category") {
const category = id === Constants.categories.all.id ? root : flattenCategoryTree(root).find(c => c.id === id)
return {
unreadCount: categoryUnreadCount(category),
hasNewEntries: categoryHasNewEntries(category),
}
}
if (props.sourceType === "feed") {
const feed = flattenCategoryTree(root)
.flatMap(c => c.feeds)
.find(f => f.id === +id)
return {
unreadCount: feed?.unread ?? 0,
hasNewEntries: !!feed?.hasNewEntries,
}
}
return { unreadCount: 0, hasNewEntries: false }
})
const showUnreadCount = mobile || !sidebarVisible
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
let title: React.ReactNode = sourceLabel let title: React.ReactNode = sourceLabel
@@ -89,16 +124,23 @@ export function FeedEntriesPage(props: Readonly<FeedEntriesPageProps>) {
return ( return (
// add some room at the bottom of the page in order to be able to scroll the current entry at the top of the page when expanding // add some room at the bottom of the page in order to be able to scroll the current entry at the top of the page when expanding
<Box mb={viewport.height * 0.7}> <Box mb={viewport.height * 0.7}>
<Group gap="xl" className="cf-entries-title"> <Group className="cf-entries-title" wrap="nowrap">
{sourceWebsiteUrl && ( {sourceWebsiteUrl && (
<a href={sourceWebsiteUrl} target="_blank" rel="noreferrer" className={classes.sourceWebsiteLink}> <a href={sourceWebsiteUrl} target="_blank" rel="noreferrer" className={classes.sourceWebsiteLink}>
<Title order={3}>{title}</Title> <Title order={3} className={classes.titleText}>
{title}
</Title>
</a> </a>
)} )}
{!sourceWebsiteUrl && <Title order={3}>{title}</Title>} {!sourceWebsiteUrl && (
<Title order={3} className={classes.titleText}>
{title}
</Title>
)}
<ActionIcon onClick={titleClicked} variant="subtle" color={theme.primaryColor}> <ActionIcon onClick={titleClicked} variant="subtle" color={theme.primaryColor}>
<TbEdit size={18} /> <TbEdit size={18} />
</ActionIcon> </ActionIcon>
{showUnreadCount && <UnreadCount unreadCount={unreadCount} showIndicator={hasNewEntries} />}
</Group> </Group>
<FeedEntries /> <FeedEntries />

View File

@@ -1,10 +1,11 @@
import { msg } from "@lingui/core/macro" import { msg } from "@lingui/core/macro"
import { ActionIcon, AppShell, Box, Center, Group, ScrollArea, Title, useMantineTheme } from "@mantine/core" import { ActionIcon, AppShell, Box, Center, Group, ScrollArea, Title, useMantineTheme } from "@mantine/core"
import { type ReactNode, type RefObject, Suspense, useEffect, useRef } from "react" import { type ReactNode, type RefObject, Suspense, useEffect, useRef, useState } from "react"
import Draggable from "react-draggable" import Draggable from "react-draggable"
import { TbMenu2, TbPlus, TbX } from "react-icons/tb" import { TbMenu2, TbPlus, TbX } from "react-icons/tb"
import { Outlet } from "react-router-dom" import { Outlet } from "react-router-dom"
import { useSwipeable } from "react-swipeable" import { useSwipeable } from "react-swipeable"
import Tinycon from "tinycon"
import { Constants } from "@/app/constants" import { Constants } from "@/app/constants"
import { redirectToAdd, redirectToRootCategory } from "@/app/redirect/thunks" import { redirectToAdd, redirectToRootCategory } from "@/app/redirect/thunks"
import { useAppDispatch, useAppSelector } from "@/app/store" import { useAppDispatch, useAppSelector } from "@/app/store"
@@ -12,8 +13,10 @@ import { setMobileMenuOpen } from "@/app/tree/slice"
import { reloadTree } from "@/app/tree/thunks" import { reloadTree } from "@/app/tree/thunks"
import { setSidebarWidth } from "@/app/user/slice" import { setSidebarWidth } from "@/app/user/slice"
import { reloadProfile, reloadSettings, reloadTags } from "@/app/user/thunks" import { reloadProfile, reloadSettings, reloadTags } from "@/app/user/thunks"
import { categoryUnreadCount } from "@/app/utils"
import { ActionButton } from "@/components/ActionButton" import { ActionButton } from "@/components/ActionButton"
import { AnnouncementDialog } from "@/components/AnnouncementDialog" import { AnnouncementDialog } from "@/components/AnnouncementDialog"
import { DisablePullToRefresh } from "@/components/DisablePullToRefresh"
import { Loader } from "@/components/Loader" import { Loader } from "@/components/Loader"
import { Logo } from "@/components/Logo" import { Logo } from "@/components/Logo"
import { MarkAllAsReadConfirmationDialog } from "@/components/MarkAllAsReadConfirmationDialog" import { MarkAllAsReadConfirmationDialog } from "@/components/MarkAllAsReadConfirmationDialog"
@@ -51,6 +54,78 @@ function LogoAndTitle() {
) )
} }
function UnreadCountTitleHandler({
enabled,
}: Readonly<{
enabled?: boolean
}>) {
const root = useAppSelector(state => state.tree.rootCategory)
const unreadCount = categoryUnreadCount(root)
return <title>{enabled && unreadCount > 0 ? `(${unreadCount}) CommaFeed` : "CommaFeed"}</title>
}
function UnreadCountFaviconHandler({ enabled }: { enabled?: boolean }) {
const root = useAppSelector(state => state.tree.rootCategory)
const unreadCount = categoryUnreadCount(root)
useEffect(() => {
if (enabled && unreadCount > 0) {
Tinycon.setBubble(unreadCount)
} else {
Tinycon.reset()
}
}, [unreadCount, enabled])
return null
}
function BrowserExtensionBadgeUnreadCountHandler() {
const root = useAppSelector(state => state.tree.rootCategory)
const { setBadgeUnreadCount } = useBrowserExtension()
useEffect(() => {
if (!root) return
const unreadCount = categoryUnreadCount(root)
setBadgeUnreadCount(unreadCount)
}, [root, setBadgeUnreadCount])
return null
}
function CustomJsHandler() {
const [scriptLoaded, setScriptLoaded] = useState(false)
const { loading } = useAppLoading()
useEffect(() => {
if (scriptLoaded || loading) {
return
}
const script = document.createElement("script")
script.src = "custom_js.js"
script.async = true
document.body.appendChild(script)
setScriptLoaded(true)
return () => script.remove()
}, [scriptLoaded, loading])
return null
}
function CustomCssHandler() {
useEffect(() => {
const link = document.createElement("link")
link.rel = "stylesheet"
link.type = "text/css"
link.href = "custom_css.css"
document.head.appendChild(link)
return () => link.remove()
}, [])
return null
}
const useStyles = tss const useStyles = tss
.withParams<{ .withParams<{
sidebarWidth: number sidebarWidth: number
@@ -75,6 +150,9 @@ export default function Layout(props: Readonly<LayoutProps>) {
const draggableSeparator = useRef<HTMLDivElement>(null) const draggableSeparator = useRef<HTMLDivElement>(null)
const { loading } = useAppLoading() const { loading } = useAppLoading()
const unreadCountTitle = useAppSelector(state => state.user.settings?.unreadCountTitle)
const unreadCountFavicon = useAppSelector(state => state.user.settings?.unreadCountFavicon)
const disablePullToRefresh = useAppSelector(state => state.user.settings?.disablePullToRefresh)
const mobileMenuOpen = useAppSelector(state => state.tree.mobileMenuOpen) const mobileMenuOpen = useAppSelector(state => state.tree.mobileMenuOpen)
const webSocketConnected = useAppSelector(state => state.server.webSocketConnected) const webSocketConnected = useAppSelector(state => state.server.webSocketConnected)
const treeReloadInterval = useAppSelector(state => state.server.serverInfos?.treeReloadInterval) const treeReloadInterval = useAppSelector(state => state.server.serverInfos?.treeReloadInterval)
@@ -173,61 +251,69 @@ export default function Layout(props: Readonly<LayoutProps>) {
if (loading) return <LoadingPage /> if (loading) return <LoadingPage />
return ( return (
<Box {...swipeHandlers}> <>
<AppShell <UnreadCountTitleHandler enabled={unreadCountTitle} />
header={{ height: Constants.layout.headerHeight, collapsed: headerInFooter }} <UnreadCountFaviconHandler enabled={unreadCountFavicon} />
footer={{ height: Constants.layout.headerHeight, collapsed: !headerInFooter }} <BrowserExtensionBadgeUnreadCountHandler />
navbar={{ <CustomJsHandler />
width: sidebarWidth, <CustomCssHandler />
breakpoint: Constants.layout.mobileBreakpoint, <DisablePullToRefresh enabled={disablePullToRefresh} />
collapsed: { mobile: !mobileMenuOpen, desktop: !props.sidebarVisible }, <Box {...swipeHandlers}>
}} <AppShell
padding={{ base: 6, [Constants.layout.mobileBreakpointName]: "md" }} header={{ height: Constants.layout.headerHeight, collapsed: headerInFooter }}
> footer={{ height: Constants.layout.headerHeight, collapsed: !headerInFooter }}
<AppShell.Header>{!headerInFooter && header}</AppShell.Header> navbar={{
<AppShell.Footer>{headerInFooter && header}</AppShell.Footer> width: sidebarWidth,
<AppShell.Navbar p={sidebarPadding}> breakpoint: Constants.layout.mobileBreakpoint,
<AppShell.Section grow component={ScrollArea} mx="-sm" px="sm"> collapsed: { mobile: !mobileMenuOpen, desktop: !props.sidebarVisible },
<Box className={classes.sidebarContent}>{props.sidebar}</Box> }}
</AppShell.Section> padding={{ base: 6, [Constants.layout.mobileBreakpointName]: "md" }}
</AppShell.Navbar> >
<OnDesktop> <AppShell.Header>{!headerInFooter && header}</AppShell.Header>
<Draggable <AppShell.Footer>{headerInFooter && header}</AppShell.Footer>
nodeRef={draggableSeparator as RefObject<HTMLElement>} <AppShell.Navbar p={sidebarPadding}>
axis="x" <AppShell.Section grow component={ScrollArea} mx="-sm" px="sm">
defaultPosition={{ <Box className={classes.sidebarContent}>{props.sidebar}</Box>
x: sidebarWidth, </AppShell.Section>
y: 0, </AppShell.Navbar>
}} <OnDesktop>
bounds={{ <Draggable
left: 120, nodeRef={draggableSeparator as RefObject<HTMLElement>}
right: 1000, axis="x"
}} defaultPosition={{
grid={[30, 30]} x: sidebarWidth,
onDrag={(_e, data) => { y: 0,
dispatch(setSidebarWidth(data.x))
}}
>
<Box
ref={draggableSeparator}
style={{
position: "fixed",
height: "100%",
width: "10px",
cursor: "ew-resize",
}} }}
/> bounds={{
</Draggable> left: 120,
</OnDesktop> right: 1000,
}}
grid={[30, 30]}
onDrag={(_e, data) => {
dispatch(setSidebarWidth(data.x))
}}
>
<Box
ref={draggableSeparator}
style={{
position: "fixed",
height: "100%",
width: "10px",
cursor: "ew-resize",
}}
/>
</Draggable>
</OnDesktop>
<AppShell.Main> <AppShell.Main>
<Suspense fallback={<Loader />}> <Suspense fallback={<Loader />}>
<AnnouncementDialog /> <AnnouncementDialog />
<MarkAllAsReadConfirmationDialog /> <MarkAllAsReadConfirmationDialog />
<Outlet /> <Outlet />
</Suspense> </Suspense>
</AppShell.Main> </AppShell.Main>
</AppShell> </AppShell>
</Box> </Box>
</>
) )
} }

View File

@@ -8,12 +8,11 @@
"lib": ["DOM", "DOM.Iterable", "ESNext"], "lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": false, "allowJs": false,
"skipLibCheck": true, "skipLibCheck": true,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"strict": true, "strict": true,
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"module": "ESNext", "module": "ESNext",
"moduleResolution": "Node", "moduleResolution": "bundler",
"resolveJsonModule": true, "resolveJsonModule": true,
"isolatedModules": true, "isolatedModules": true,
"noEmit": true, "noEmit": true,

View File

@@ -1,27 +1,20 @@
import { lingui } from "@lingui/vite-plugin" import { lingui } from "@lingui/vite-plugin"
import react from "@vitejs/plugin-react" import babel from "@rolldown/plugin-babel"
import react, { reactCompilerPreset } from "@vitejs/plugin-react"
import { defineConfig } from "vite" import { defineConfig } from "vite"
import checker from "vite-plugin-checker" import checker from "vite-plugin-checker"
import tsconfigPaths from "vite-tsconfig-paths"
// https://vitejs.dev/config/
export default defineConfig(() => ({ export default defineConfig(() => ({
plugins: [ plugins: [
react({ react(),
babel: { babel({
plugins: [ presets: [reactCompilerPreset()],
// support for lingui macros plugins: ["@lingui/babel-plugin-lingui-macro"],
// needs to be before the react compiler plugin
"@lingui/babel-plugin-lingui-macro",
// react compiler
["babel-plugin-react-compiler", { target: "19" }],
],
},
}), }),
lingui(), lingui(),
tsconfigPaths(),
checker({ checker({
typescript: true, // temporary disabled until TypeScript 7 exposes a stable api
// typescript: true,
biome: { biome: {
command: "check", command: "check",
flags: "--error-on-warnings", flags: "--error-on-warnings",
@@ -43,22 +36,32 @@ export default defineConfig(() => ({
"/logout": "http://localhost:8083", "/logout": "http://localhost:8083",
}, },
}, },
build: { resolve: {
chunkSizeWarningLimit: 3500, tsconfigPaths: true,
rollupOptions: { },
output: { legacy: {
manualChunks: id => { // required for websocket-heartbeat-js
// output mantine as its own chunk because it is quite large inconsistentCjsInterop: true,
if (id.includes("@mantine")) {
return "mantine"
}
},
},
},
}, },
test: { test: {
environment: "jsdom", environment: "jsdom",
globals: true, globals: true,
setupFiles: "./src/setupTests.ts", setupFiles: "./src/setupTests.ts",
}, },
build: {
chunkSizeWarningLimit: 4000,
rolldownOptions: {
output: {
codeSplitting: {
groups: [
// output mantine as its own chunk because it is quite large
{
name: "mantine",
test: "@mantine",
},
],
},
},
},
},
})) }))

View File

@@ -1,401 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="23">
<profile kind="CodeFormatterProfile" name="CommaFeed" version="23">
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_with_spaces" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="48"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
<setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_record_components" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_logical_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_shift_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_loops" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_switch_case_arrow_operator" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enum_constant" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.text_block_indentation" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_permitted_types" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_annotations" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="2147483647"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_not_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="48"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_permitted_types_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.comment.javadoc_do_not_separate_block_tags" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_tag_description" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_constructor" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_string_concatenation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_shift_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_shift_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_additive_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_relational_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_logical_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="48"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.keep_switch_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_arrow" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="140"/>
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_method_body_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_additive_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_relational_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_relational_operator" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_additive_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.align_selector_in_method_invocation_on_expression_first_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_switch_case_with_arrow_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_colon" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_additive_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_shift_operator" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.keep_code_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="48"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_switch_case_with_arrow" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assertion_message" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_logical_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_relational_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_logical_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_permitted_types" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="tab"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_string_concatenation" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="140"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
</profile>
</profiles>

View File

@@ -1,8 +1,8 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<!DOCTYPE module PUBLIC <!DOCTYPE module PUBLIC
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN" "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd"> "https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker"> <module name="Checker">
<property name="charset" value="UTF-8" /> <property name="charset" value="UTF-8" />
<property name="fileExtensions" value="java" /> <property name="fileExtensions" value="java" />
@@ -40,11 +40,6 @@
<module name="AvoidStarImport" /> <module name="AvoidStarImport" />
<module name="AvoidStaticImport" /> <module name="AvoidStaticImport" />
<module name="IllegalImport" /> <module name="IllegalImport" />
<module name="ImportOrder">
<property name="groups" value="/^java\./,javax,jakarta,org,com" />
<property name="ordered" value="true" />
<property name="separated" value="true" />
</module>
<module name="RedundantImport" /> <module name="RedundantImport" />
<module name="UnusedImports" /> <module name="UnusedImports" />
@@ -60,7 +55,7 @@
<module name="EmptyCatchBlock"> <module name="EmptyCatchBlock">
<property name="exceptionVariableName" value="ignore|ignored" /> <property name="exceptionVariableName" value="ignore|ignored" />
<message key="catch.block.empty" <message key="catch.block.empty"
value="Empty catch block. You can use the name 'ignore' or 'ignored' for the exception variable if you really want an empty catch block, but you should strongly consider at the very least logging something." /> value="Empty catch block. You can use the name 'ignore' or 'ignored' for the exception variable if you really want an empty catch block, but you should strongly consider at the very least logging something." />
</module> </module>
<module name="LeftCurly" /> <module name="LeftCurly" />
<module name="NeedBraces" /> <module name="NeedBraces" />
@@ -76,7 +71,7 @@
<module name="FallThrough" /> <module name="FallThrough" />
<module name="IllegalInstantiation"> <module name="IllegalInstantiation">
<property name="classes" <property name="classes"
value="java.lang.Boolean, java.lang.Byte, java.lang.Character, java.lang.Double, java.lang.Float, java.lang.Integer, java.lang.Long, java.lang.Short" /> value="java.lang.Boolean, java.lang.Byte, java.lang.Character, java.lang.Double, java.lang.Float, java.lang.Integer, java.lang.Long, java.lang.Short" />
</module> </module>
<module name="IllegalType" /> <module name="IllegalType" />
<module name="ModifiedControlVariable"> <module name="ModifiedControlVariable">
@@ -113,12 +108,6 @@
<module name="NoLineWrap" /> <module name="NoLineWrap" />
<module name="NoWhitespaceBefore" /> <module name="NoWhitespaceBefore" />
<module name="ParenPad" /> <module name="ParenPad" />
<module name="RegexpSinglelineJava">
<property name="format" value="^\t* +\t*\S" />
<property name="message" value="Line has leading space characters; indentation should be performed with tabs only." />
<property name="ignoreComments" value="true" />
</module>
<module name="WhitespaceAround" />
</module> </module>
</module> </module>

View File

@@ -1,7 +0,0 @@
#Organize Import Order
#Wed Jan 29 15:15:04 CET 2025
0=java
1=javax
2=jakarta
3=org
4=com

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
FROM ibm-semeru-runtimes:open-jdk-25.0.2_10-jre@sha256:b02e4cd184d9ece59b01129af1d0a069fa01e4f0f798f0bc4f3ff1a8391ba694 FROM ibm-semeru-runtimes:open-jdk-25.0.3.0-jre@sha256:43ec947fee9c4c2ed880620ae9e78911ac5eef66391e5a2c43f956dcc9000491
EXPOSE 8082 EXPOSE 8082
RUN mkdir -p /commafeed/data RUN mkdir -p /commafeed/data

View File

@@ -1,4 +1,4 @@
FROM debian:13.3@sha256:2c91e484d93f0830a7e05a2b9d92a7b102be7cab562198b984a84fdbc7806d91 FROM debian:13.6@sha256:fac46bff2e02f51425b6e33b0e1169f55dfb053d83511ca28aa50c09fd5ed7a4
ARG TARGETARCH ARG TARGETARCH
EXPOSE 8082 EXPOSE 8082

View File

@@ -1,34 +1,46 @@
package com.commafeed; package com.commafeed;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Singleton;
import com.commafeed.backend.feed.FeedRefreshEngine; import com.commafeed.backend.feed.FeedRefreshEngine;
import com.commafeed.backend.feed.ImageProxyUrl;
import com.commafeed.backend.task.TaskScheduler; import com.commafeed.backend.task.TaskScheduler;
import com.commafeed.security.password.PasswordConstraintValidator; import com.commafeed.security.password.PasswordConstraintValidator;
import io.quarkus.runtime.ShutdownEvent; import io.quarkus.runtime.ShutdownEvent;
import io.quarkus.runtime.StartupEvent; import io.quarkus.runtime.StartupEvent;
import lombok.RequiredArgsConstructor;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Singleton;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Singleton @Singleton
@RequiredArgsConstructor @RequiredArgsConstructor
public class CommaFeedApplication { public class CommaFeedApplication {
private final FeedRefreshEngine feedRefreshEngine; private final FeedRefreshEngine feedRefreshEngine;
private final TaskScheduler taskScheduler; private final TaskScheduler taskScheduler;
private final CommaFeedConfiguration config; private final CommaFeedConfiguration config;
public void start(@Observes StartupEvent ev) { public void start(@Observes StartupEvent ev) {
PasswordConstraintValidator.setMinimumPasswordLength(config.users().minimumPasswordLength()); log.info("starting up...");
feedRefreshEngine.start(); PasswordConstraintValidator.setMinimumPasswordLength(
taskScheduler.start(); config.users().minimumPasswordLength());
}
public void stop(@Observes ShutdownEvent ev) { if (config.imageProxyEnabled()) {
feedRefreshEngine.stop(); ImageProxyUrl.generateKey();
taskScheduler.stop(); }
}
feedRefreshEngine.start();
taskScheduler.start();
}
public void stop(@Observes ShutdownEvent ev) {
log.info("shutting down...");
feedRefreshEngine.stop();
taskScheduler.stop();
}
} }

View File

@@ -1,12 +1,5 @@
package com.commafeed; package com.commafeed;
import java.time.Duration;
import java.time.Instant;
import java.util.Optional;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.Positive;
import com.commafeed.backend.feed.FeedRefreshIntervalCalculator; import com.commafeed.backend.feed.FeedRefreshIntervalCalculator;
import io.quarkus.runtime.annotations.ConfigDocSection; import io.quarkus.runtime.annotations.ConfigDocSection;
@@ -16,385 +9,355 @@ import io.quarkus.runtime.configuration.MemorySize;
import io.smallrye.config.ConfigMapping; import io.smallrye.config.ConfigMapping;
import io.smallrye.config.WithDefault; import io.smallrye.config.WithDefault;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.Positive;
import java.time.Duration;
import java.time.Instant;
import java.util.Optional;
/** /**
* CommaFeed configuration * CommaFeed configuration
* *
* Default values are for production, they can be overridden in application.properties for other profiles * <p>Default values are for production, they can be overridden in application.properties for other
* profiles
*/ */
@ConfigMapping(prefix = "commafeed") @ConfigMapping(prefix = "commafeed")
@ConfigRoot(phase = ConfigPhase.RUN_TIME) @ConfigRoot(phase = ConfigPhase.RUN_TIME)
public interface CommaFeedConfiguration { public interface CommaFeedConfiguration {
/** /**
* Whether to expose a robots.txt file that disallows web crawlers and search engine indexers. * Whether to expose a robots.txt file that disallows web crawlers and search engine indexers.
*/ */
@WithDefault("true") @WithDefault("true")
boolean hideFromWebCrawlers(); boolean hideFromWebCrawlers();
/** /**
* If enabled, images in feed entries will be proxied through the server instead of accessed directly by the browser. * If enabled, images in feed entries will be proxied through the server instead of accessed
* * directly by the browser.
* This is useful if commafeed is accessed through a restricting proxy that blocks some feeds that are followed. *
*/ * <p>This is useful if commafeed is accessed through a restricting proxy that blocks some feeds
@WithDefault("false") * that are followed.
boolean imageProxyEnabled(); */
@WithDefault("false")
boolean imageProxyEnabled();
/** /**
* Enable password recovery via email. * Enable password recovery via email.
* *
* Quarkus mailer will need to be configured. * <p>Quarkus mailer will need to be configured.
*/ */
@WithDefault("false") @WithDefault("false")
boolean passwordRecoveryEnabled(); boolean passwordRecoveryEnabled();
/** /** Message displayed in a notification at the bottom of the page. */
* Message displayed in a notification at the bottom of the page. Optional<String> announcement();
*/
Optional<String> announcement();
/** /** Google Auth key for fetching Youtube channel favicons. */
* Google Auth key for fetching Youtube channel favicons. Optional<String> googleAuthKey();
*/
Optional<String> googleAuthKey();
/** /** HTTP client configuration */
* HTTP client configuration @ConfigDocSection
*/ HttpClient httpClient();
@ConfigDocSection
HttpClient httpClient();
/** /** Feed refresh engine settings. */
* Feed refresh engine settings. @ConfigDocSection
*/ FeedRefresh feedRefresh();
@ConfigDocSection
FeedRefresh feedRefresh();
/** /** Push notification settings. */
* Push notification settings. @ConfigDocSection
*/ PushNotifications pushNotifications();
@ConfigDocSection
PushNotifications pushNotifications();
/** /** Database settings. */
* Database settings. @ConfigDocSection
*/ Database database();
@ConfigDocSection
Database database();
/** /** Users settings. */
* Users settings. @ConfigDocSection
*/ Users users();
@ConfigDocSection
Users users();
/** /** Websocket settings. */
* Websocket settings. @ConfigDocSection
*/ Websocket websocket();
@ConfigDocSection
Websocket websocket();
interface HttpClient { /**
/** * Duration to wait for the feed refresh engine and the task scheduler to stop when the
* User-Agent string that will be used by the http client, leave empty for the default one. * application is shutting down.
*/ */
Optional<String> userAgent(); @WithDefault("2s")
Duration shutdownTimeout();
/** interface HttpClient {
* Time to wait for a connection to be established. /**
*/ * User-Agent string that will be used by the http client, leave empty for the default one.
@WithDefault("5s") */
Duration connectTimeout(); Optional<String> userAgent();
/** /** Time to wait for a connection to be established. */
* Time to wait for SSL handshake to complete. @WithDefault("5s")
*/ Duration connectTimeout();
@WithDefault("5s")
Duration sslHandshakeTimeout();
/** /** Time to wait for SSL handshake to complete. */
* Time to wait between two packets before timeout. @WithDefault("5s")
*/ Duration sslHandshakeTimeout();
@WithDefault("10s")
Duration socketTimeout();
/** /** Time to wait between two packets before timeout. */
* Time to wait for the full response to be received. @WithDefault("10s")
*/ Duration socketTimeout();
@WithDefault("10s")
Duration responseTimeout();
/** /** Time to wait for the full response to be received. */
* Time to live for a connection in the pool. @WithDefault("10s")
*/ Duration responseTimeout();
@WithDefault("30s")
Duration connectionTimeToLive();
/** /** Time to live for a connection in the pool. */
* Time between eviction runs for idle connections. @WithDefault("30s")
*/ Duration connectionTimeToLive();
@WithDefault("1m")
Duration idleConnectionsEvictionInterval();
/** /** Time between eviction runs for idle connections. */
* If a feed is larger than this, it will be discarded to prevent memory issues while parsing the feed. @WithDefault("1m")
*/ Duration idleConnectionsEvictionInterval();
@WithDefault("5M")
MemorySize maxResponseSize();
/** /**
* Prevent access to local addresses to mitigate server-side request forgery (SSRF) attacks, which could potentially expose internal * If a feed is larger than this, it will be discarded to prevent memory issues while
* resources. * parsing the feed.
* */
* You may want to enable this if you host a public instance of CommaFeed with regisration open. @WithDefault("5M")
*/ MemorySize maxResponseSize();
@WithDefault("false")
boolean blockLocalAddresses();
/** /**
* HTTP client cache configuration * Prevent access to local addresses to mitigate server-side request forgery (SSRF) attacks,
*/ * which could potentially expose internal resources.
@ConfigDocSection *
HttpClientCache cache(); * <p>You may want to enable this if you host a public instance of CommaFeed with
} * registrations open.
*/
@WithDefault("false")
boolean blockLocalAddresses();
interface HttpClientCache { /** HTTP client cache configuration */
/** @ConfigDocSection
* Whether to enable the cache. This cache is used to avoid spamming feeds in short bursts (e.g. when subscribing to a feed for the HttpClientCache cache();
* first time or when clicking "fetch all my feeds now"). }
*/
@WithDefault("true")
boolean enabled();
/** interface HttpClientCache {
* Maximum amount of memory the cache can use. /**
*/ * Whether to enable the cache. This cache is used to avoid spamming feeds in short bursts
@WithDefault("10M") * (e.g. when subscribing to a feed for the first time or when clicking "fetch all my feeds
MemorySize maximumMemorySize(); * now").
*/
@WithDefault("true")
boolean enabled();
/** /** Maximum amount of memory the cache can use. */
* Duration after which an entry is removed from the cache. @WithDefault("10M")
*/ MemorySize maximumMemorySize();
@WithDefault("1m")
Duration expiration();
}
interface FeedRefresh { /** Duration after which an entry is removed from the cache. */
/** @WithDefault("1m")
* Default amount of time CommaFeed will wait before refreshing a feed. Duration expiration();
*/ }
@WithDefault("5m")
Duration interval();
/** interface FeedRefresh {
* Maximum amount of time CommaFeed will wait before refreshing a feed. This is used as an upper bound when: /** Default amount of time CommaFeed will wait before refreshing a feed. */
* @WithDefault("5m")
* <ul> Duration interval();
* <li>an error occurs while refreshing a feed and we're backing off exponentially</li>
* <li>we receive a Cache-Control header from the feed</li>
* <li>we receive a Retry-After header from the feed</li>
* </ul>
*/
@WithDefault("4h")
Duration maxInterval();
/** /**
* If enabled, CommaFeed will calculate the next refresh time based on the feed's average time between entries and the time since * Maximum amount of time CommaFeed will wait before refreshing a feed. This is used as an
* the last entry was published. The interval will be sometimes between the default refresh interval * upper bound when:
* (`commafeed.feed-refresh.interval`) and the maximum refresh interval (`commafeed.feed-refresh.max-interval`). *
* * <ul>
* See {@link FeedRefreshIntervalCalculator} for details. * <li>an error occurs while refreshing a feed and we're backing off exponentially
*/ * <li>we receive a Cache-Control header from the feed
@WithDefault("true") * <li>we receive a Retry-After header from the feed
boolean intervalEmpirical(); * </ul>
*/
@WithDefault("4h")
Duration maxInterval();
/** /**
* Feed refresh engine error handling settings. * If enabled, CommaFeed will calculate the next refresh time based on the feed's average
*/ * time between entries and the time since the last entry was published. The interval will
@ConfigDocSection * be sometimes between the default refresh interval (`commafeed.feed-refresh.interval`) and
FeedRefreshErrorHandling errors(); * the maximum refresh interval (`commafeed.feed-refresh.max-interval`).
*
* <p>See {@link FeedRefreshIntervalCalculator} for details.
*/
@WithDefault("true")
boolean intervalEmpirical();
/** /** Feed refresh engine error handling settings. */
* Amount of http threads used to fetch feeds. @ConfigDocSection
*/ FeedRefreshErrorHandling errors();
@Min(1)
@WithDefault("3")
int httpThreads();
/** /** Amount of http threads used to fetch feeds. */
* Amount of threads used to insert new entries in the database. @Min(1)
*/ @WithDefault("3")
@Min(1) int httpThreads();
@WithDefault("1")
int databaseThreads();
/** /** Amount of threads used to insert new entries in the database. */
* Duration after which a user is considered inactive. Feeds for inactive users are not refreshed until they log in again. @Min(1)
* @WithDefault("1")
* 0 to disable. int databaseThreads();
*/
@WithDefault("0")
Duration userInactivityPeriod();
/** /**
* Duration after which the evaluation of a filtering expresion to mark an entry as read is considered to have timed out. * Duration after which a user is considered inactive. Feeds for inactive users are not
*/ * refreshed until they log in again.
@WithDefault("500ms") *
Duration filteringExpressionEvaluationTimeout(); * <p>0 to disable.
*/
@WithDefault("0")
Duration userInactivityPeriod();
/** /**
* Duration after which the "Fetch all my feeds now" action is available again after use to avoid spamming feeds. * Duration after which the evaluation of a filtering expresion to mark an entry as read is
*/ * considered to have timed out.
@WithDefault("0") */
Duration forceRefreshCooldownDuration(); @WithDefault("500ms")
} Duration filteringExpressionEvaluationTimeout();
interface PushNotifications { /**
/** * Duration after which the "Fetch all my feeds now" action is available again after use to
* Whether to enable push notifications to notify users of new entries in their feeds. * avoid spamming feeds.
*/ */
@WithDefault("true") @WithDefault("0")
boolean enabled(); Duration forceRefreshCooldownDuration();
}
/** interface PushNotifications {
* Amount of threads used to send external notifications about new entries. /** Whether to enable push notifications to notify users of new entries in their feeds. */
*/ @WithDefault("true")
@Min(1) boolean enabled();
@WithDefault("5")
int threads();
/** /** Amount of threads used to send external notifications about new entries. */
* Maximum amount of notifications that can be queued before new notifications are discarded. @Min(1)
*/ @WithDefault("5")
@Min(1) int threads();
@WithDefault("100")
int queueCapacity();
}
interface FeedRefreshErrorHandling { /**
/** * Maximum amount of notifications that can be queued before new notifications are
* Number of retries before backoff is applied. * discarded.
*/ */
@Min(0) @Min(1)
@WithDefault("3") @WithDefault("100")
int retriesBeforeBackoff(); int queueCapacity();
}
/** interface FeedRefreshErrorHandling {
* Duration to wait before retrying after an error. Will be multiplied by the number of errors since the last successful fetch. /** Number of retries before backoff is applied. */
*/ @Min(0)
@WithDefault("1h") @WithDefault("3")
Duration backoffInterval(); int retriesBeforeBackoff();
}
interface Database { /**
/** * Duration to wait before retrying after an error. Will be multiplied by the number of
* Timeout applied to all database queries. * errors since the last successful fetch.
* */
* 0 to disable. @WithDefault("1h")
*/ Duration backoffInterval();
@WithDefault("0") }
Duration queryTimeout();
/** interface Database {
* Database cleanup settings. /**
*/ * Timeout applied to all database queries.
@ConfigDocSection *
Cleanup cleanup(); * <p>0 to disable.
*/
@WithDefault("0")
Duration queryTimeout();
interface Cleanup { /** Database cleanup settings. */
/** @ConfigDocSection
* Maximum age of feed entries in the database. Older entries will be deleted. Cleanup cleanup();
*
* 0 to disable.
*/
@WithDefault("365d")
Duration entriesMaxAge();
/** interface Cleanup {
* Maximum age of feed entry statuses (read/unread) in the database. Older statuses will be deleted. /**
* * Maximum age of feed entries in the database. Older entries will be deleted.
* 0 to disable. *
*/ * <p>0 to disable.
@WithDefault("0") */
Duration statusesMaxAge(); @WithDefault("365d")
Duration entriesMaxAge();
/** /**
* Maximum number of entries per feed to keep in the database. * Maximum age of feed entry statuses (read/unread) in the database. Older statuses will
* * be deleted.
* 0 to disable. *
*/ * <p>0 to disable.
@WithDefault("500") */
int maxFeedCapacity(); @WithDefault("0")
Duration statusesMaxAge();
/** /**
* Limit the number of feeds a user can subscribe to. * Maximum number of entries per feed to keep in the database.
* *
* 0 to disable. * <p>0 to disable.
*/ */
@WithDefault("0") @WithDefault("500")
int maxFeedsPerUser(); int maxFeedCapacity();
/** /**
* Rows to delete per query while cleaning up old entries. * Limit the number of feeds a user can subscribe to.
*/ *
@Positive * <p>0 to disable.
@WithDefault("100") */
int batchSize(); @WithDefault("0")
int maxFeedsPerUser();
/** /** Rows to delete per query while cleaning up old entries. */
* Whether to keep starred entries when cleaning up old entries. @Positive
*/ @WithDefault("100")
@WithDefault("true") int batchSize();
boolean keepStarredEntries();
default Instant statusesInstantThreshold() { /** Whether to keep starred entries when cleaning up old entries. */
return statusesMaxAge().toMillis() > 0 ? Instant.now().minus(statusesMaxAge()) : null; @WithDefault("true")
} boolean keepStarredEntries();
}
}
interface Users { default Instant statusesInstantThreshold() {
/** return statusesMaxAge().toMillis() > 0
* Whether to let users create accounts for themselves. ? Instant.now().minus(statusesMaxAge())
*/ : null;
@WithDefault("false") }
boolean allowRegistrations(); }
}
/** interface Users {
* Minimum password length for user accounts. /** Whether to let users create accounts for themselves. */
*/ @WithDefault("false")
@WithDefault("4") boolean allowRegistrations();
int minimumPasswordLength();
/** /** Minimum password length for user accounts. */
* Whether an email address is required when creating a user account. @WithDefault("4")
*/ int minimumPasswordLength();
@WithDefault("false")
boolean emailAddressRequired();
/** /** Whether an email address is required when creating a user account. */
* Whether to create a demo account the first time the app starts. @WithDefault("false")
*/ boolean emailAddressRequired();
@WithDefault("false")
boolean createDemoAccount();
}
interface Websocket { /** Whether to create a demo account the first time the app starts. */
/** @WithDefault("false")
* Enable websocket connection so the server can notify web clients that there are new entries for feeds. boolean createDemoAccount();
*/ }
@WithDefault("true")
boolean enabled();
/** interface Websocket {
* Interval at which the client will send a ping message on the websocket to keep the connection alive. /**
*/ * Enable websocket connection so the server can notify web clients that there are new
@WithDefault("15m") * entries for feeds.
Duration pingInterval(); */
@WithDefault("true")
boolean enabled();
/** /**
* If the websocket connection is disabled or the connection is lost, the client will reload the feed tree at this interval. * Interval at which the client will send a ping message on the websocket to keep the
*/ * connection alive.
@WithDefault("30s") */
Duration treeReloadInterval(); @WithDefault("15m")
} Duration pingInterval();
/**
* If the websocket connection is disabled or the connection is lost, the client will reload
* the feed tree at this interval.
*/
@WithDefault("30s")
Duration treeReloadInterval();
}
} }

View File

@@ -4,5 +4,5 @@ import lombok.experimental.UtilityClass;
@UtilityClass @UtilityClass
public class CommaFeedConstants { public class CommaFeedConstants {
public static final String USERNAME_DEMO = "demo"; public static final String USERNAME_DEMO = "demo";
} }

View File

@@ -1,25 +1,24 @@
package com.commafeed; package com.commafeed;
import java.time.InstantSource; import com.codahale.metrics.MetricRegistry;
import jakarta.enterprise.inject.Produces; import jakarta.enterprise.inject.Produces;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
import com.codahale.metrics.MetricRegistry; import java.time.InstantSource;
@Singleton @Singleton
public class CommaFeedProducers { public class CommaFeedProducers {
@Produces @Produces
@Singleton @Singleton
public InstantSource instantSource() { public InstantSource instantSource() {
return InstantSource.system(); return InstantSource.system();
} }
@Produces
@Singleton
public MetricRegistry metricRegistry() {
return new MetricRegistry();
}
@Produces
@Singleton
public MetricRegistry metricRegistry() {
return new MetricRegistry();
}
} }

View File

@@ -1,30 +1,29 @@
package com.commafeed; package com.commafeed;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
import lombok.Getter; import lombok.Getter;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
@Singleton @Singleton
@Getter @Getter
public class CommaFeedVersion { public class CommaFeedVersion {
private final String version; private final String version;
private final String gitCommit; private final String gitCommit;
public CommaFeedVersion() throws IOException { public CommaFeedVersion() throws IOException {
Properties properties = new Properties(); Properties properties = new Properties();
try (InputStream stream = getClass().getResourceAsStream("/git.properties")) { try (InputStream stream = getClass().getResourceAsStream("/git.properties")) {
if (stream != null) { if (stream != null) {
properties.load(stream); properties.load(stream);
} }
} }
this.version = properties.getProperty("git.build.version", "unknown");
this.gitCommit = properties.getProperty("git.commit.id.abbrev", "unknown");
}
this.version = properties.getProperty("git.build.version", "unknown");
this.gitCommit = properties.getProperty("git.commit.id.abbrev", "unknown");
}
} }

View File

@@ -1,55 +1,58 @@
package com.commafeed; package com.commafeed;
import jakarta.annotation.Priority;
import jakarta.validation.ValidationException;
import jakarta.ws.rs.core.NewCookie;
import jakarta.ws.rs.ext.Provider;
import org.jboss.resteasy.reactive.RestResponse;
import org.jboss.resteasy.reactive.RestResponse.ResponseBuilder;
import org.jboss.resteasy.reactive.RestResponse.Status;
import org.jboss.resteasy.reactive.server.ServerExceptionMapper;
import com.commafeed.security.CookieService; import com.commafeed.security.CookieService;
import io.quarkus.runtime.annotations.RegisterForReflection; import io.quarkus.runtime.annotations.RegisterForReflection;
import io.quarkus.security.AuthenticationFailedException; import io.quarkus.security.AuthenticationFailedException;
import io.quarkus.security.UnauthorizedException; import io.quarkus.security.UnauthorizedException;
import jakarta.annotation.Priority;
import jakarta.validation.ValidationException;
import jakarta.ws.rs.core.NewCookie;
import jakarta.ws.rs.ext.Provider;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.jboss.resteasy.reactive.RestResponse;
import org.jboss.resteasy.reactive.RestResponse.ResponseBuilder;
import org.jboss.resteasy.reactive.RestResponse.Status;
import org.jboss.resteasy.reactive.server.ServerExceptionMapper;
@RequiredArgsConstructor @RequiredArgsConstructor
@Provider @Provider
@Priority(1) @Priority(1)
public class ExceptionMappers { public class ExceptionMappers {
private final CookieService cookieService; private final CookieService cookieService;
private final CommaFeedConfiguration config; private final CommaFeedConfiguration config;
@ServerExceptionMapper(UnauthorizedException.class) @ServerExceptionMapper(UnauthorizedException.class)
public RestResponse<UnauthorizedResponse> unauthorized(UnauthorizedException e) { public RestResponse<UnauthorizedResponse> unauthorized(UnauthorizedException e) {
return RestResponse.status(Status.UNAUTHORIZED, new UnauthorizedResponse(e.getMessage(), config.users().allowRegistrations())); return RestResponse.status(
} Status.UNAUTHORIZED,
new UnauthorizedResponse(e.getMessage(), config.users().allowRegistrations()));
}
@ServerExceptionMapper(AuthenticationFailedException.class) @ServerExceptionMapper(AuthenticationFailedException.class)
public RestResponse<AuthenticationFailed> authenticationFailed(AuthenticationFailedException e) { public RestResponse<AuthenticationFailed> authenticationFailed(
NewCookie logoutCookie = cookieService.buildLogoutCookie(); AuthenticationFailedException e) {
return ResponseBuilder.create(Status.UNAUTHORIZED, new AuthenticationFailed(e.getMessage())).cookie(logoutCookie).build(); NewCookie logoutCookie = cookieService.buildLogoutCookie();
} return ResponseBuilder.create(Status.UNAUTHORIZED, new AuthenticationFailed(e.getMessage()))
.cookie(logoutCookie)
.build();
}
@ServerExceptionMapper(ValidationException.class) @ServerExceptionMapper(ValidationException.class)
public RestResponse<ValidationFailed> validationFailed(ValidationException e) { public RestResponse<ValidationFailed> validationFailed(ValidationException e) {
return RestResponse.status(Status.BAD_REQUEST, new ValidationFailed(e.getMessage())); return RestResponse.status(Status.BAD_REQUEST, new ValidationFailed(e.getMessage()));
} }
@RegisterForReflection @RegisterForReflection
public record UnauthorizedResponse(String message, boolean allowRegistrations) { public record UnauthorizedResponse(String message, boolean allowRegistrations) {}
}
@RegisterForReflection @RegisterForReflection
public record AuthenticationFailed(String message) { public record AuthenticationFailed(String message) {}
}
@RegisterForReflection @RegisterForReflection
public record ValidationFailed(String message) { public record ValidationFailed(String message) {}
}
} }

View File

@@ -1,9 +1,5 @@
package com.commafeed; package com.commafeed;
import java.util.concurrent.TimeUnit;
import jakarta.inject.Singleton;
import com.codahale.metrics.json.MetricsModule; import com.codahale.metrics.json.MetricsModule;
import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
@@ -12,18 +8,23 @@ import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import io.quarkus.jackson.ObjectMapperCustomizer; import io.quarkus.jackson.ObjectMapperCustomizer;
import jakarta.inject.Singleton;
import java.util.concurrent.TimeUnit;
@Singleton @Singleton
public class JacksonCustomizer implements ObjectMapperCustomizer { public class JacksonCustomizer implements ObjectMapperCustomizer {
@Override @Override
public void customize(ObjectMapper objectMapper) { public void customize(ObjectMapper objectMapper) {
objectMapper.registerModule(new JavaTimeModule()); objectMapper.registerModule(new JavaTimeModule());
// read and write instants as milliseconds instead of nanoseconds // read and write instants as milliseconds instead of nanoseconds
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true) objectMapper
.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false) .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true)
.configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false); .configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false)
.configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false);
// add support for serializing metrics // add support for serializing metrics
objectMapper.registerModule(new MetricsModule(TimeUnit.SECONDS, TimeUnit.SECONDS, false)); objectMapper.registerModule(new MetricsModule(TimeUnit.SECONDS, TimeUnit.SECONDS, false));
} }
} }

View File

@@ -10,217 +10,340 @@ import com.codahale.metrics.Timer;
import io.quarkus.runtime.annotations.RegisterForReflection; import io.quarkus.runtime.annotations.RegisterForReflection;
@RegisterForReflection( @RegisterForReflection(
targets = { targets = {
// metrics // metrics
MetricRegistry.class, Meter.class, Gauge.class, Counter.class, Timer.class, Histogram.class, MetricRegistry.class,
Meter.class,
Gauge.class,
Counter.class,
Timer.class,
Histogram.class,
// rome // rome
java.util.Date.class, com.rometools.opml.feed.synd.impl.TreeCategoryImpl.class, java.util.Date.class,
com.rometools.rome.feed.synd.SyndFeedImpl.class, com.rometools.rome.feed.module.DCSubjectImpl.class, com.rometools.opml.feed.synd.impl.TreeCategoryImpl.class,
com.rometools.rome.feed.synd.SyndEntryImpl.class, com.rometools.modules.psc.types.SimpleChapter.class, com.rometools.rome.feed.synd.SyndFeedImpl.class,
com.rometools.rome.feed.synd.SyndCategoryImpl.class, com.rometools.rome.feed.synd.SyndImageImpl.class, com.rometools.rome.feed.module.DCSubjectImpl.class,
com.rometools.rome.feed.synd.SyndContentImpl.class, com.rometools.rome.feed.synd.SyndEnclosureImpl.class, com.rometools.rome.feed.synd.SyndEntryImpl.class,
com.rometools.modules.psc.types.SimpleChapter.class,
com.rometools.rome.feed.synd.SyndCategoryImpl.class,
com.rometools.rome.feed.synd.SyndImageImpl.class,
com.rometools.rome.feed.synd.SyndContentImpl.class,
com.rometools.rome.feed.synd.SyndEnclosureImpl.class,
// rome cloneable // rome cloneable
com.rometools.modules.activitystreams.types.Article.class, com.rometools.modules.activitystreams.types.Audio.class, com.rometools.modules.activitystreams.types.Article.class,
com.rometools.modules.activitystreams.types.Bookmark.class, com.rometools.modules.activitystreams.types.Comment.class, com.rometools.modules.activitystreams.types.Audio.class,
com.rometools.modules.activitystreams.types.Event.class, com.rometools.modules.activitystreams.types.File.class, com.rometools.modules.activitystreams.types.Bookmark.class,
com.rometools.modules.activitystreams.types.Folder.class, com.rometools.modules.activitystreams.types.List.class, com.rometools.modules.activitystreams.types.Comment.class,
com.rometools.modules.activitystreams.types.Note.class, com.rometools.modules.activitystreams.types.Person.class, com.rometools.modules.activitystreams.types.Event.class,
com.rometools.modules.activitystreams.types.Photo.class, com.rometools.modules.activitystreams.types.PhotoAlbum.class, com.rometools.modules.activitystreams.types.File.class,
com.rometools.modules.activitystreams.types.Place.class, com.rometools.modules.activitystreams.types.Playlist.class, com.rometools.modules.activitystreams.types.Folder.class,
com.rometools.modules.activitystreams.types.Product.class, com.rometools.modules.activitystreams.types.Review.class, com.rometools.modules.activitystreams.types.List.class,
com.rometools.modules.activitystreams.types.Service.class, com.rometools.modules.activitystreams.types.Song.class, com.rometools.modules.activitystreams.types.Note.class,
com.rometools.modules.activitystreams.types.Status.class, com.rometools.modules.base.types.DateTimeRange.class, com.rometools.modules.activitystreams.types.Person.class,
com.rometools.modules.base.types.FloatUnit.class, com.rometools.modules.base.types.GenderEnumeration.class, com.rometools.modules.activitystreams.types.Photo.class,
com.rometools.modules.base.types.IntUnit.class, com.rometools.modules.base.types.PriceTypeEnumeration.class, com.rometools.modules.activitystreams.types.PhotoAlbum.class,
com.rometools.modules.base.types.ShippingType.class, com.rometools.modules.base.types.ShortDate.class, com.rometools.modules.activitystreams.types.Place.class,
com.rometools.modules.base.types.Size.class, com.rometools.modules.base.types.YearType.class, com.rometools.modules.activitystreams.types.Playlist.class,
com.rometools.modules.content.ContentItem.class, com.rometools.modules.georss.GeoRSSPoint.class, com.rometools.modules.activitystreams.types.Product.class,
com.rometools.modules.georss.geometries.Envelope.class, com.rometools.modules.georss.geometries.LineString.class, com.rometools.modules.activitystreams.types.Review.class,
com.rometools.modules.georss.geometries.LinearRing.class, com.rometools.modules.georss.geometries.Point.class, com.rometools.modules.activitystreams.types.Service.class,
com.rometools.modules.georss.geometries.Polygon.class, com.rometools.modules.georss.geometries.Position.class, com.rometools.modules.activitystreams.types.Song.class,
com.rometools.modules.georss.geometries.PositionList.class, com.rometools.modules.mediarss.types.MediaGroup.class, com.rometools.modules.activitystreams.types.Status.class,
com.rometools.modules.mediarss.types.Metadata.class, com.rometools.modules.mediarss.types.Thumbnail.class, com.rometools.modules.base.types.DateTimeRange.class,
com.rometools.modules.opensearch.entity.OSQuery.class, com.rometools.modules.photocast.types.PhotoDate.class, com.rometools.modules.base.types.FloatUnit.class,
com.rometools.modules.sle.types.DateValue.class, com.rometools.modules.sle.types.Group.class, com.rometools.modules.base.types.GenderEnumeration.class,
com.rometools.modules.sle.types.NumberValue.class, com.rometools.modules.sle.types.Sort.class, com.rometools.modules.base.types.IntUnit.class,
com.rometools.modules.sle.types.StringValue.class, com.rometools.modules.yahooweather.types.Astronomy.class, com.rometools.modules.base.types.PriceTypeEnumeration.class,
com.rometools.modules.yahooweather.types.Atmosphere.class, com.rometools.modules.yahooweather.types.Condition.class, com.rometools.modules.base.types.ShippingType.class,
com.rometools.modules.yahooweather.types.Forecast.class, com.rometools.modules.yahooweather.types.Location.class, com.rometools.modules.base.types.ShortDate.class,
com.rometools.modules.yahooweather.types.Units.class, com.rometools.modules.yahooweather.types.Wind.class, com.rometools.modules.base.types.Size.class,
com.rometools.opml.feed.opml.Attribute.class, com.rometools.opml.feed.opml.Opml.class, com.rometools.modules.base.types.YearType.class,
com.rometools.opml.feed.opml.Outline.class, com.rometools.rome.feed.atom.Category.class, com.rometools.modules.content.ContentItem.class,
com.rometools.rome.feed.atom.Content.class, com.rometools.rome.feed.atom.Entry.class, com.rometools.modules.georss.GeoRSSPoint.class,
com.rometools.rome.feed.atom.Feed.class, com.rometools.rome.feed.atom.Generator.class, com.rometools.modules.georss.geometries.Envelope.class,
com.rometools.rome.feed.atom.Link.class, com.rometools.rome.feed.atom.Person.class, com.rometools.modules.georss.geometries.LineString.class,
com.rometools.rome.feed.rss.Category.class, com.rometools.rome.feed.rss.Channel.class, com.rometools.modules.georss.geometries.LinearRing.class,
com.rometools.rome.feed.rss.Cloud.class, com.rometools.rome.feed.rss.Content.class, com.rometools.modules.georss.geometries.Point.class,
com.rometools.rome.feed.rss.Description.class, com.rometools.rome.feed.rss.Enclosure.class, com.rometools.modules.georss.geometries.Polygon.class,
com.rometools.rome.feed.rss.Guid.class, com.rometools.rome.feed.rss.Image.class, com.rometools.rome.feed.rss.Item.class, com.rometools.modules.georss.geometries.Position.class,
com.rometools.rome.feed.rss.Source.class, com.rometools.rome.feed.rss.TextInput.class, com.rometools.modules.georss.geometries.PositionList.class,
com.rometools.rome.feed.synd.SyndLinkImpl.class, com.rometools.rome.feed.synd.SyndPersonImpl.class, com.rometools.modules.mediarss.types.MediaGroup.class,
java.util.ArrayList.class, com.rometools.modules.mediarss.types.Metadata.class,
com.rometools.modules.mediarss.types.Thumbnail.class,
com.rometools.modules.opensearch.entity.OSQuery.class,
com.rometools.modules.photocast.types.PhotoDate.class,
com.rometools.modules.sle.types.DateValue.class,
com.rometools.modules.sle.types.Group.class,
com.rometools.modules.sle.types.NumberValue.class,
com.rometools.modules.sle.types.Sort.class,
com.rometools.modules.sle.types.StringValue.class,
com.rometools.modules.yahooweather.types.Astronomy.class,
com.rometools.modules.yahooweather.types.Atmosphere.class,
com.rometools.modules.yahooweather.types.Condition.class,
com.rometools.modules.yahooweather.types.Forecast.class,
com.rometools.modules.yahooweather.types.Location.class,
com.rometools.modules.yahooweather.types.Units.class,
com.rometools.modules.yahooweather.types.Wind.class,
com.rometools.opml.feed.opml.Attribute.class,
com.rometools.opml.feed.opml.Opml.class,
com.rometools.opml.feed.opml.Outline.class,
com.rometools.rome.feed.atom.Category.class,
com.rometools.rome.feed.atom.Content.class,
com.rometools.rome.feed.atom.Entry.class,
com.rometools.rome.feed.atom.Feed.class,
com.rometools.rome.feed.atom.Generator.class,
com.rometools.rome.feed.atom.Link.class,
com.rometools.rome.feed.atom.Person.class,
com.rometools.rome.feed.rss.Category.class,
com.rometools.rome.feed.rss.Channel.class,
com.rometools.rome.feed.rss.Cloud.class,
com.rometools.rome.feed.rss.Content.class,
com.rometools.rome.feed.rss.Description.class,
com.rometools.rome.feed.rss.Enclosure.class,
com.rometools.rome.feed.rss.Guid.class,
com.rometools.rome.feed.rss.Image.class,
com.rometools.rome.feed.rss.Item.class,
com.rometools.rome.feed.rss.Source.class,
com.rometools.rome.feed.rss.TextInput.class,
com.rometools.rome.feed.synd.SyndLinkImpl.class,
com.rometools.rome.feed.synd.SyndPersonImpl.class,
java.util.ArrayList.class,
// rome modules // rome modules
com.rometools.modules.sse.modules.Conflict.class, com.rometools.modules.sse.modules.Conflicts.class, com.rometools.modules.sse.modules.Conflict.class,
com.rometools.modules.cc.CreativeCommonsImpl.class, com.rometools.modules.feedpress.modules.FeedpressModuleImpl.class, com.rometools.modules.sse.modules.Conflicts.class,
com.rometools.modules.opensearch.impl.OpenSearchModuleImpl.class, com.rometools.modules.sse.modules.Sharing.class, com.rometools.modules.cc.CreativeCommonsImpl.class,
com.rometools.modules.georss.SimpleModuleImpl.class, com.rometools.modules.atom.modules.AtomLinkModuleImpl.class, com.rometools.modules.feedpress.modules.FeedpressModuleImpl.class,
com.rometools.modules.itunes.EntryInformationImpl.class, com.rometools.modules.sse.modules.Update.class, com.rometools.modules.opensearch.impl.OpenSearchModuleImpl.class,
com.rometools.modules.photocast.PhotocastModuleImpl.class, com.rometools.modules.itunes.FeedInformationImpl.class, com.rometools.modules.sse.modules.Sharing.class,
com.rometools.modules.yahooweather.YWeatherModuleImpl.class, com.rometools.modules.feedburner.FeedBurnerImpl.class, com.rometools.modules.georss.SimpleModuleImpl.class,
com.rometools.modules.sse.modules.Related.class, com.rometools.modules.fyyd.modules.FyydModuleImpl.class, com.rometools.modules.atom.modules.AtomLinkModuleImpl.class,
com.rometools.modules.psc.modules.PodloveSimpleChapterModuleImpl.class, com.rometools.modules.thr.ThreadingModuleImpl.class, com.rometools.modules.itunes.EntryInformationImpl.class,
com.rometools.modules.sse.modules.Sync.class, com.rometools.modules.sle.SimpleListExtensionImpl.class, com.rometools.modules.sse.modules.Update.class,
com.rometools.modules.slash.SlashImpl.class, com.rometools.modules.sse.modules.History.class, com.rometools.modules.photocast.PhotocastModuleImpl.class,
com.rometools.modules.georss.GMLModuleImpl.class, com.rometools.modules.base.CustomTagsImpl.class, com.rometools.modules.itunes.FeedInformationImpl.class,
com.rometools.modules.base.GoogleBaseImpl.class, com.rometools.modules.sle.SleEntryImpl.class, com.rometools.modules.yahooweather.YWeatherModuleImpl.class,
com.rometools.modules.mediarss.MediaEntryModuleImpl.class, com.rometools.modules.content.ContentModuleImpl.class, com.rometools.modules.feedburner.FeedBurnerImpl.class,
com.rometools.modules.georss.W3CGeoModuleImpl.class, com.rometools.rome.feed.module.DCModuleImpl.class, com.rometools.modules.sse.modules.Related.class,
com.rometools.modules.mediarss.MediaModuleImpl.class, com.rometools.rome.feed.module.SyModuleImpl.class, com.rometools.modules.fyyd.modules.FyydModuleImpl.class,
com.rometools.modules.psc.modules.PodloveSimpleChapterModuleImpl.class,
com.rometools.modules.thr.ThreadingModuleImpl.class,
com.rometools.modules.sse.modules.Sync.class,
com.rometools.modules.sle.SimpleListExtensionImpl.class,
com.rometools.modules.slash.SlashImpl.class,
com.rometools.modules.sse.modules.History.class,
com.rometools.modules.georss.GMLModuleImpl.class,
com.rometools.modules.base.CustomTagsImpl.class,
com.rometools.modules.base.GoogleBaseImpl.class,
com.rometools.modules.sle.SleEntryImpl.class,
com.rometools.modules.mediarss.MediaEntryModuleImpl.class,
com.rometools.modules.content.ContentModuleImpl.class,
com.rometools.modules.georss.W3CGeoModuleImpl.class,
com.rometools.rome.feed.module.DCModuleImpl.class,
com.rometools.modules.mediarss.MediaModuleImpl.class,
com.rometools.rome.feed.module.SyModuleImpl.class,
// extracted from all 3 rome.properties files of rome library // extracted from all 3 rome.properties files of rome library
com.rometools.rome.io.impl.RSS090Parser.class, com.rometools.rome.io.impl.RSS091NetscapeParser.class, com.rometools.rome.io.impl.RSS090Parser.class,
com.rometools.rome.io.impl.RSS091UserlandParser.class, com.rometools.rome.io.impl.RSS092Parser.class, com.rometools.rome.io.impl.RSS091NetscapeParser.class,
com.rometools.rome.io.impl.RSS093Parser.class, com.rometools.rome.io.impl.RSS094Parser.class, com.rometools.rome.io.impl.RSS091UserlandParser.class,
com.rometools.rome.io.impl.RSS10Parser.class, com.rometools.rome.io.impl.RSS20wNSParser.class, com.rometools.rome.io.impl.RSS092Parser.class,
com.rometools.rome.io.impl.RSS20Parser.class, com.rometools.rome.io.impl.Atom10Parser.class, com.rometools.rome.io.impl.RSS093Parser.class,
com.rometools.rome.io.impl.Atom03Parser.class, com.rometools.rome.io.impl.RSS094Parser.class,
com.rometools.rome.io.impl.RSS10Parser.class,
com.rometools.rome.io.impl.SyModuleParser.class, com.rometools.rome.io.impl.DCModuleParser.class, com.rometools.rome.io.impl.RSS20wNSParser.class,
com.rometools.rome.io.impl.RSS20Parser.class,
com.rometools.rome.io.impl.RSS090Generator.class, com.rometools.rome.io.impl.RSS091NetscapeGenerator.class, com.rometools.rome.io.impl.Atom10Parser.class,
com.rometools.rome.io.impl.RSS091UserlandGenerator.class, com.rometools.rome.io.impl.RSS092Generator.class, com.rometools.rome.io.impl.Atom03Parser.class,
com.rometools.rome.io.impl.RSS093Generator.class, com.rometools.rome.io.impl.RSS094Generator.class, com.rometools.rome.io.impl.SyModuleParser.class,
com.rometools.rome.io.impl.RSS10Generator.class, com.rometools.rome.io.impl.RSS20Generator.class, com.rometools.rome.io.impl.DCModuleParser.class,
com.rometools.rome.io.impl.Atom10Generator.class, com.rometools.rome.io.impl.Atom03Generator.class, com.rometools.rome.io.impl.RSS090Generator.class,
com.rometools.rome.io.impl.RSS091NetscapeGenerator.class,
com.rometools.rome.feed.synd.impl.ConverterForAtom10.class, com.rometools.rome.feed.synd.impl.ConverterForAtom03.class, com.rometools.rome.io.impl.RSS091UserlandGenerator.class,
com.rometools.rome.feed.synd.impl.ConverterForRSS090.class, com.rometools.rome.io.impl.RSS092Generator.class,
com.rometools.rome.feed.synd.impl.ConverterForRSS091Netscape.class, com.rometools.rome.io.impl.RSS093Generator.class,
com.rometools.rome.feed.synd.impl.ConverterForRSS091Userland.class, com.rometools.rome.io.impl.RSS094Generator.class,
com.rometools.rome.feed.synd.impl.ConverterForRSS092.class, com.rometools.rome.feed.synd.impl.ConverterForRSS093.class, com.rometools.rome.io.impl.RSS10Generator.class,
com.rometools.rome.feed.synd.impl.ConverterForRSS094.class, com.rometools.rome.feed.synd.impl.ConverterForRSS10.class, com.rometools.rome.io.impl.RSS20Generator.class,
com.rometools.rome.feed.synd.impl.ConverterForRSS20.class, com.rometools.rome.io.impl.Atom10Generator.class,
com.rometools.rome.io.impl.Atom03Generator.class,
com.rometools.modules.mediarss.io.RSS20YahooParser.class, com.rometools.rome.feed.synd.impl.ConverterForAtom10.class,
com.rometools.rome.feed.synd.impl.ConverterForAtom03.class,
com.rometools.modules.cc.io.ModuleParserRSS2.class, com.rometools.modules.content.io.ContentModuleParser.class, com.rometools.rome.feed.synd.impl.ConverterForRSS090.class,
com.rometools.modules.itunes.io.ITunesParser.class, com.rometools.modules.mediarss.io.MediaModuleParser.class, com.rometools.rome.feed.synd.impl.ConverterForRSS091Netscape.class,
com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class, com.rometools.modules.georss.SimpleParser.class, com.rometools.rome.feed.synd.impl.ConverterForRSS091Userland.class,
com.rometools.modules.georss.W3CGeoParser.class, com.rometools.modules.photocast.io.Parser.class, com.rometools.rome.feed.synd.impl.ConverterForRSS092.class,
com.rometools.modules.mediarss.io.MediaModuleParser.class, com.rometools.modules.atom.io.AtomModuleParser.class, com.rometools.rome.feed.synd.impl.ConverterForRSS093.class,
com.rometools.modules.itunes.io.ITunesParserOldNamespace.class, com.rometools.rome.feed.synd.impl.ConverterForRSS094.class,
com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class, com.rometools.modules.sle.io.ModuleParser.class, com.rometools.rome.feed.synd.impl.ConverterForRSS10.class,
com.rometools.modules.yahooweather.io.WeatherModuleParser.class, com.rometools.modules.feedpress.io.FeedpressParser.class, com.rometools.rome.feed.synd.impl.ConverterForRSS20.class,
com.rometools.modules.fyyd.io.FyydParser.class, com.rometools.modules.mediarss.io.RSS20YahooParser.class,
com.rometools.modules.cc.io.ModuleParserRSS2.class,
com.rometools.modules.cc.io.ModuleParserRSS2.class, com.rometools.modules.content.io.ContentModuleParser.class, com.rometools.modules.content.io.ContentModuleParser.class,
com.rometools.modules.itunes.io.ITunesParser.class, com.rometools.modules.mediarss.io.MediaModuleParser.class, com.rometools.modules.itunes.io.ITunesParser.class,
com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class, com.rometools.modules.georss.SimpleParser.class, com.rometools.modules.mediarss.io.MediaModuleParser.class,
com.rometools.modules.georss.W3CGeoParser.class, com.rometools.modules.photocast.io.Parser.class, com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class,
com.rometools.modules.mediarss.io.MediaModuleParser.class, com.rometools.modules.atom.io.AtomModuleParser.class, com.rometools.modules.georss.SimpleParser.class,
com.rometools.modules.itunes.io.ITunesParserOldNamespace.class, com.rometools.modules.georss.W3CGeoParser.class,
com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class, com.rometools.modules.sle.io.ModuleParser.class, com.rometools.modules.photocast.io.Parser.class,
com.rometools.modules.yahooweather.io.WeatherModuleParser.class, com.rometools.modules.feedpress.io.FeedpressParser.class, com.rometools.modules.mediarss.io.MediaModuleParser.class,
com.rometools.modules.fyyd.io.FyydParser.class, com.rometools.modules.atom.io.AtomModuleParser.class,
com.rometools.modules.itunes.io.ITunesParserOldNamespace.class,
com.rometools.modules.cc.io.ModuleParserRSS1.class, com.rometools.modules.content.io.ContentModuleParser.class, com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class,
com.rometools.modules.sle.io.ModuleParser.class,
com.rometools.modules.cc.io.ModuleParserRSS2.class, com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class, com.rometools.modules.yahooweather.io.WeatherModuleParser.class,
com.rometools.modules.georss.SimpleParser.class, com.rometools.modules.georss.W3CGeoParser.class, com.rometools.modules.feedpress.io.FeedpressParser.class,
com.rometools.modules.photocast.io.Parser.class, com.rometools.modules.mediarss.io.MediaModuleParser.class, com.rometools.modules.fyyd.io.FyydParser.class,
com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class, com.rometools.modules.cc.io.ModuleParserRSS2.class,
com.rometools.modules.content.io.ContentModuleParser.class,
com.rometools.modules.cc.io.ModuleParserRSS2.class, com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class, com.rometools.modules.itunes.io.ITunesParser.class,
com.rometools.modules.georss.SimpleParser.class, com.rometools.modules.georss.W3CGeoParser.class, com.rometools.modules.mediarss.io.MediaModuleParser.class,
com.rometools.modules.photocast.io.Parser.class, com.rometools.modules.mediarss.io.MediaModuleParser.class, com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class,
com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class, com.rometools.modules.georss.SimpleParser.class,
com.rometools.modules.feedpress.io.FeedpressParser.class, com.rometools.modules.fyyd.io.FyydParser.class, com.rometools.modules.georss.W3CGeoParser.class,
com.rometools.modules.photocast.io.Parser.class,
com.rometools.modules.cc.io.ModuleParserRSS2.class, com.rometools.modules.base.io.GoogleBaseParser.class, com.rometools.modules.mediarss.io.MediaModuleParser.class,
com.rometools.modules.content.io.ContentModuleParser.class, com.rometools.modules.slash.io.SlashModuleParser.class, com.rometools.modules.atom.io.AtomModuleParser.class,
com.rometools.modules.itunes.io.ITunesParser.class, com.rometools.modules.mediarss.io.MediaModuleParser.class, com.rometools.modules.itunes.io.ITunesParserOldNamespace.class,
com.rometools.modules.atom.io.AtomModuleParser.class, com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class, com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class,
com.rometools.modules.georss.SimpleParser.class, com.rometools.modules.georss.W3CGeoParser.class, com.rometools.modules.sle.io.ModuleParser.class,
com.rometools.modules.photocast.io.Parser.class, com.rometools.modules.itunes.io.ITunesParserOldNamespace.class, com.rometools.modules.yahooweather.io.WeatherModuleParser.class,
com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class, com.rometools.modules.sle.io.ItemParser.class, com.rometools.modules.feedpress.io.FeedpressParser.class,
com.rometools.modules.yahooweather.io.WeatherModuleParser.class, com.rometools.modules.fyyd.io.FyydParser.class,
com.rometools.modules.psc.io.PodloveSimpleChapterParser.class, com.rometools.modules.cc.io.ModuleParserRSS1.class,
com.rometools.modules.content.io.ContentModuleParser.class,
com.rometools.modules.cc.io.ModuleParserRSS1.class, com.rometools.modules.base.io.GoogleBaseParser.class, com.rometools.modules.cc.io.ModuleParserRSS2.class,
com.rometools.modules.base.io.CustomTagParser.class, com.rometools.modules.content.io.ContentModuleParser.class, com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class,
com.rometools.modules.slash.io.SlashModuleParser.class, com.rometools.modules.georss.SimpleParser.class,
com.rometools.modules.georss.W3CGeoParser.class,
com.rometools.modules.cc.io.ModuleParserRSS2.class, com.rometools.modules.base.io.GoogleBaseParser.class, com.rometools.modules.photocast.io.Parser.class,
com.rometools.modules.base.io.CustomTagParser.class, com.rometools.modules.slash.io.SlashModuleParser.class, com.rometools.modules.mediarss.io.MediaModuleParser.class,
com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class, com.rometools.modules.georss.SimpleParser.class, com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class,
com.rometools.modules.georss.W3CGeoParser.class, com.rometools.modules.photocast.io.Parser.class, com.rometools.modules.cc.io.ModuleParserRSS2.class,
com.rometools.modules.mediarss.io.MediaModuleParser.class, com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class,
com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class, com.rometools.modules.georss.SimpleParser.class,
com.rometools.modules.georss.W3CGeoParser.class,
com.rometools.modules.cc.io.ModuleParserRSS2.class, com.rometools.modules.base.io.GoogleBaseParser.class, com.rometools.modules.photocast.io.Parser.class,
com.rometools.modules.base.io.CustomTagParser.class, com.rometools.modules.slash.io.SlashModuleParser.class, com.rometools.modules.mediarss.io.MediaModuleParser.class,
com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class, com.rometools.modules.georss.SimpleParser.class, com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class,
com.rometools.modules.georss.W3CGeoParser.class, com.rometools.modules.photocast.io.Parser.class, com.rometools.modules.feedpress.io.FeedpressParser.class,
com.rometools.modules.mediarss.io.MediaModuleParser.class, com.rometools.modules.fyyd.io.FyydParser.class,
com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class, com.rometools.modules.cc.io.ModuleParserRSS2.class,
com.rometools.modules.thr.io.ThreadingModuleParser.class, com.rometools.modules.psc.io.PodloveSimpleChapterParser.class, com.rometools.modules.base.io.GoogleBaseParser.class,
com.rometools.modules.content.io.ContentModuleParser.class,
com.rometools.modules.cc.io.CCModuleGenerator.class, com.rometools.modules.content.io.ContentModuleGenerator.class, com.rometools.modules.slash.io.SlashModuleParser.class,
com.rometools.modules.itunes.io.ITunesGenerator.class, com.rometools.modules.itunes.io.ITunesParser.class,
com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator.class, com.rometools.modules.georss.SimpleGenerator.class, com.rometools.modules.mediarss.io.MediaModuleParser.class,
com.rometools.modules.georss.W3CGeoGenerator.class, com.rometools.modules.photocast.io.Generator.class, com.rometools.modules.atom.io.AtomModuleParser.class,
com.rometools.modules.mediarss.io.MediaModuleGenerator.class, com.rometools.modules.atom.io.AtomModuleGenerator.class, com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class,
com.rometools.modules.sle.io.ModuleGenerator.class, com.rometools.modules.yahooweather.io.WeatherModuleGenerator.class, com.rometools.modules.georss.SimpleParser.class,
com.rometools.modules.feedpress.io.FeedpressGenerator.class, com.rometools.modules.fyyd.io.FyydGenerator.class, com.rometools.modules.georss.W3CGeoParser.class,
com.rometools.modules.photocast.io.Parser.class,
com.rometools.modules.content.io.ContentModuleGenerator.class, com.rometools.modules.itunes.io.ITunesParserOldNamespace.class,
com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class,
com.rometools.modules.cc.io.CCModuleGenerator.class, com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator.class, com.rometools.modules.sle.io.ItemParser.class,
com.rometools.modules.georss.SimpleGenerator.class, com.rometools.modules.georss.W3CGeoGenerator.class, com.rometools.modules.yahooweather.io.WeatherModuleParser.class,
com.rometools.modules.photocast.io.Generator.class, com.rometools.modules.mediarss.io.MediaModuleGenerator.class, com.rometools.modules.psc.io.PodloveSimpleChapterParser.class,
com.rometools.modules.cc.io.ModuleParserRSS1.class,
com.rometools.modules.cc.io.CCModuleGenerator.class, com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator.class, com.rometools.modules.base.io.GoogleBaseParser.class,
com.rometools.modules.georss.SimpleGenerator.class, com.rometools.modules.georss.W3CGeoGenerator.class, com.rometools.modules.base.io.CustomTagParser.class,
com.rometools.modules.photocast.io.Generator.class, com.rometools.modules.mediarss.io.MediaModuleGenerator.class, com.rometools.modules.content.io.ContentModuleParser.class,
com.rometools.modules.feedpress.io.FeedpressGenerator.class, com.rometools.modules.fyyd.io.FyydGenerator.class, com.rometools.modules.slash.io.SlashModuleParser.class,
com.rometools.modules.cc.io.ModuleParserRSS2.class,
com.rometools.modules.cc.io.CCModuleGenerator.class, com.rometools.modules.base.io.GoogleBaseGenerator.class, com.rometools.modules.base.io.GoogleBaseParser.class,
com.rometools.modules.base.io.CustomTagGenerator.class, com.rometools.modules.content.io.ContentModuleGenerator.class, com.rometools.modules.base.io.CustomTagParser.class,
com.rometools.modules.slash.io.SlashModuleGenerator.class, com.rometools.modules.itunes.io.ITunesGenerator.class, com.rometools.modules.slash.io.SlashModuleParser.class,
com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator.class, com.rometools.modules.georss.SimpleGenerator.class, com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class,
com.rometools.modules.georss.W3CGeoGenerator.class, com.rometools.modules.photocast.io.Generator.class, com.rometools.modules.georss.SimpleParser.class,
com.rometools.modules.mediarss.io.MediaModuleGenerator.class, com.rometools.modules.atom.io.AtomModuleGenerator.class, com.rometools.modules.georss.W3CGeoParser.class,
com.rometools.modules.yahooweather.io.WeatherModuleGenerator.class, com.rometools.modules.photocast.io.Parser.class,
com.rometools.modules.psc.io.PodloveSimpleChapterGenerator.class, com.rometools.modules.mediarss.io.MediaModuleParser.class,
com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class,
com.rometools.modules.base.io.GoogleBaseGenerator.class, com.rometools.modules.content.io.ContentModuleGenerator.class, com.rometools.modules.cc.io.ModuleParserRSS2.class,
com.rometools.modules.slash.io.SlashModuleGenerator.class, com.rometools.modules.base.io.GoogleBaseParser.class,
com.rometools.modules.base.io.CustomTagParser.class,
com.rometools.modules.cc.io.CCModuleGenerator.class, com.rometools.modules.base.io.GoogleBaseGenerator.class, com.rometools.modules.slash.io.SlashModuleParser.class,
com.rometools.modules.base.io.CustomTagGenerator.class, com.rometools.modules.slash.io.SlashModuleGenerator.class, com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class,
com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator.class, com.rometools.modules.georss.SimpleGenerator.class, com.rometools.modules.georss.SimpleParser.class,
com.rometools.modules.georss.W3CGeoGenerator.class, com.rometools.modules.photocast.io.Generator.class, com.rometools.modules.georss.W3CGeoParser.class,
com.rometools.modules.mediarss.io.MediaModuleGenerator.class, com.rometools.modules.photocast.io.Parser.class,
com.rometools.modules.mediarss.io.MediaModuleParser.class,
com.rometools.modules.cc.io.CCModuleGenerator.class, com.rometools.modules.base.io.CustomTagGenerator.class, com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class,
com.rometools.modules.slash.io.SlashModuleGenerator.class, com.rometools.modules.thr.io.ThreadingModuleParser.class,
com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator.class, com.rometools.modules.georss.SimpleGenerator.class, com.rometools.modules.psc.io.PodloveSimpleChapterParser.class,
com.rometools.modules.georss.W3CGeoGenerator.class, com.rometools.modules.photocast.io.Generator.class, com.rometools.modules.cc.io.CCModuleGenerator.class,
com.rometools.modules.mediarss.io.MediaModuleGenerator.class, com.rometools.modules.thr.io.ThreadingModuleGenerator.class, com.rometools.modules.content.io.ContentModuleGenerator.class,
com.rometools.modules.psc.io.PodloveSimpleChapterGenerator.class, com.rometools.modules.itunes.io.ITunesGenerator.class,
com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator.class,
com.rometools.modules.mediarss.io.MediaModuleParser.class, com.rometools.modules.georss.SimpleGenerator.class,
com.rometools.modules.georss.W3CGeoGenerator.class,
com.rometools.modules.mediarss.io.MediaModuleGenerator.class, com.rometools.modules.photocast.io.Generator.class,
com.rometools.modules.mediarss.io.MediaModuleGenerator.class,
com.rometools.opml.io.impl.OPML10Generator.class, com.rometools.opml.io.impl.OPML20Generator.class, com.rometools.modules.atom.io.AtomModuleGenerator.class,
com.rometools.modules.sle.io.ModuleGenerator.class,
com.rometools.opml.io.impl.OPML10Parser.class, com.rometools.opml.io.impl.OPML20Parser.class, com.rometools.modules.yahooweather.io.WeatherModuleGenerator.class,
com.rometools.modules.feedpress.io.FeedpressGenerator.class,
com.rometools.opml.feed.synd.impl.ConverterForOPML10.class, com.rometools.opml.feed.synd.impl.ConverterForOPML20.class, }) com.rometools.modules.fyyd.io.FyydGenerator.class,
com.rometools.modules.content.io.ContentModuleGenerator.class,
public class NativeImageClasses { com.rometools.modules.cc.io.CCModuleGenerator.class,
} com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator.class,
com.rometools.modules.georss.SimpleGenerator.class,
com.rometools.modules.georss.W3CGeoGenerator.class,
com.rometools.modules.photocast.io.Generator.class,
com.rometools.modules.mediarss.io.MediaModuleGenerator.class,
com.rometools.modules.cc.io.CCModuleGenerator.class,
com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator.class,
com.rometools.modules.georss.SimpleGenerator.class,
com.rometools.modules.georss.W3CGeoGenerator.class,
com.rometools.modules.photocast.io.Generator.class,
com.rometools.modules.mediarss.io.MediaModuleGenerator.class,
com.rometools.modules.feedpress.io.FeedpressGenerator.class,
com.rometools.modules.fyyd.io.FyydGenerator.class,
com.rometools.modules.cc.io.CCModuleGenerator.class,
com.rometools.modules.base.io.GoogleBaseGenerator.class,
com.rometools.modules.base.io.CustomTagGenerator.class,
com.rometools.modules.content.io.ContentModuleGenerator.class,
com.rometools.modules.slash.io.SlashModuleGenerator.class,
com.rometools.modules.itunes.io.ITunesGenerator.class,
com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator.class,
com.rometools.modules.georss.SimpleGenerator.class,
com.rometools.modules.georss.W3CGeoGenerator.class,
com.rometools.modules.photocast.io.Generator.class,
com.rometools.modules.mediarss.io.MediaModuleGenerator.class,
com.rometools.modules.atom.io.AtomModuleGenerator.class,
com.rometools.modules.yahooweather.io.WeatherModuleGenerator.class,
com.rometools.modules.psc.io.PodloveSimpleChapterGenerator.class,
com.rometools.modules.base.io.GoogleBaseGenerator.class,
com.rometools.modules.content.io.ContentModuleGenerator.class,
com.rometools.modules.slash.io.SlashModuleGenerator.class,
com.rometools.modules.cc.io.CCModuleGenerator.class,
com.rometools.modules.base.io.GoogleBaseGenerator.class,
com.rometools.modules.base.io.CustomTagGenerator.class,
com.rometools.modules.slash.io.SlashModuleGenerator.class,
com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator.class,
com.rometools.modules.georss.SimpleGenerator.class,
com.rometools.modules.georss.W3CGeoGenerator.class,
com.rometools.modules.photocast.io.Generator.class,
com.rometools.modules.mediarss.io.MediaModuleGenerator.class,
com.rometools.modules.cc.io.CCModuleGenerator.class,
com.rometools.modules.base.io.CustomTagGenerator.class,
com.rometools.modules.slash.io.SlashModuleGenerator.class,
com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator.class,
com.rometools.modules.georss.SimpleGenerator.class,
com.rometools.modules.georss.W3CGeoGenerator.class,
com.rometools.modules.photocast.io.Generator.class,
com.rometools.modules.mediarss.io.MediaModuleGenerator.class,
com.rometools.modules.thr.io.ThreadingModuleGenerator.class,
com.rometools.modules.psc.io.PodloveSimpleChapterGenerator.class,
com.rometools.modules.mediarss.io.MediaModuleParser.class,
com.rometools.modules.mediarss.io.MediaModuleGenerator.class,
com.rometools.opml.io.impl.OPML10Generator.class,
com.rometools.opml.io.impl.OPML20Generator.class,
com.rometools.opml.io.impl.OPML10Parser.class,
com.rometools.opml.io.impl.OPML20Parser.class,
com.rometools.opml.feed.synd.impl.ConverterForOPML10.class,
com.rometools.opml.feed.synd.impl.ConverterForOPML20.class,
})
public class NativeImageClasses {}

View File

@@ -1,29 +1,29 @@
package com.commafeed.backend; package com.commafeed.backend;
import java.nio.charset.StandardCharsets;
import com.google.common.hash.HashFunction; import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing; import com.google.common.hash.Hashing;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
import java.nio.charset.StandardCharsets;
@UtilityClass @UtilityClass
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public class Digests { public class Digests {
public static String sha1Hex(byte[] input) { public static String sha1Hex(byte[] input) {
return hashBytesToHex(Hashing.sha1(), input); return hashBytesToHex(Hashing.sha1(), input);
} }
public static String sha1Hex(String input) { public static String sha1Hex(String input) {
return hashBytesToHex(Hashing.sha1(), input.getBytes(StandardCharsets.UTF_8)); return hashBytesToHex(Hashing.sha1(), input.getBytes(StandardCharsets.UTF_8));
} }
public static String md5Hex(String input) { public static String md5Hex(String input) {
return hashBytesToHex(Hashing.md5(), input.getBytes(StandardCharsets.UTF_8)); return hashBytesToHex(Hashing.md5(), input.getBytes(StandardCharsets.UTF_8));
} }
private static String hashBytesToHex(HashFunction function, byte[] input) { private static String hashBytesToHex(HashFunction function, byte[] input) {
return function.hashBytes(input).toString(); return function.hashBytes(input).toString();
} }
} }

View File

@@ -1,16 +1,20 @@
package com.commafeed.backend; package com.commafeed.backend;
import java.net.InetAddress; import com.commafeed.CommaFeedConfiguration;
import java.net.URI; import com.commafeed.CommaFeedVersion;
import java.net.UnknownHostException; import com.google.common.net.HttpHeaders;
import java.util.ArrayList;
import java.util.LinkedHashMap; import inet.ipaddr.IPAddress;
import java.util.List; import inet.ipaddr.IPAddressNetwork;
import java.util.SequencedMap; import inet.ipaddr.IPAddressString;
import java.util.zip.GZIPInputStream;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
import lombok.RequiredArgsConstructor;
import nl.altindag.ssl.SSLFactory;
import nl.altindag.ssl.apache5.util.Apache5SslUtils;
import org.apache.hc.client5.http.DnsResolver; import org.apache.hc.client5.http.DnsResolver;
import org.apache.hc.client5.http.SystemDefaultDnsResolver; import org.apache.hc.client5.http.SystemDefaultDnsResolver;
import org.apache.hc.client5.http.config.ConnectionConfig; import org.apache.hc.client5.http.config.ConnectionConfig;
@@ -35,132 +39,157 @@ import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout; import org.apache.hc.core5.util.Timeout;
import org.brotli.dec.BrotliInputStream; import org.brotli.dec.BrotliInputStream;
import com.commafeed.CommaFeedConfiguration; import java.net.InetAddress;
import com.commafeed.CommaFeedVersion; import java.net.URI;
import com.google.common.net.HttpHeaders; import java.net.UnknownHostException;
import java.util.ArrayList;
import lombok.RequiredArgsConstructor; import java.util.LinkedHashMap;
import nl.altindag.ssl.SSLFactory; import java.util.List;
import nl.altindag.ssl.apache5.util.Apache5SslUtils; import java.util.SequencedMap;
import java.util.zip.GZIPInputStream;
@Singleton @Singleton
@RequiredArgsConstructor @RequiredArgsConstructor
public class HttpClientFactory { public class HttpClientFactory {
private static final DnsResolver DNS_RESOLVER = SystemDefaultDnsResolver.INSTANCE; private static final DnsResolver DNS_RESOLVER = SystemDefaultDnsResolver.INSTANCE;
private static final IPAddress CGNAT_RANGE = new IPAddressString("100.64.0.0/10").getAddress();
private final CommaFeedConfiguration config; private final CommaFeedConfiguration config;
private final CommaFeedVersion version; private final CommaFeedVersion version;
public CloseableHttpClient newClient(int poolSize) { public CloseableHttpClient newClient(int poolSize) {
PoolingHttpClientConnectionManager connectionManager = newConnectionManager(config, poolSize); PoolingHttpClientConnectionManager connectionManager =
String userAgent = config.httpClient() newConnectionManager(config, poolSize);
.userAgent() String userAgent =
.orElseGet(() -> String.format("CommaFeed/%s (https://github.com/Athou/commafeed)", version.getVersion())); config.httpClient()
return newClient(config, connectionManager, userAgent); .userAgent()
} .orElseGet(
() ->
String.format(
"CommaFeed/%s (https://github.com/Athou/commafeed)",
version.getVersion()));
return newClient(config, connectionManager, userAgent);
}
private CloseableHttpClient newClient(CommaFeedConfiguration config, HttpClientConnectionManager connectionManager, String userAgent) { private CloseableHttpClient newClient(
List<Header> headers = new ArrayList<>(); CommaFeedConfiguration config,
headers.add(new BasicHeader(HttpHeaders.ACCEPT_LANGUAGE, "en")); HttpClientConnectionManager connectionManager,
headers.add(new BasicHeader(HttpHeaders.PRAGMA, "No-cache")); String userAgent) {
headers.add(new BasicHeader(HttpHeaders.CACHE_CONTROL, "no-cache")); List<Header> headers = new ArrayList<>();
headers.add(new BasicHeader(HttpHeaders.ACCEPT_LANGUAGE, "en"));
headers.add(new BasicHeader(HttpHeaders.PRAGMA, "No-cache"));
headers.add(new BasicHeader(HttpHeaders.CACHE_CONTROL, "no-cache"));
SequencedMap<String, InputStreamFactory> contentDecoderMap = new LinkedHashMap<>(); SequencedMap<String, InputStreamFactory> contentDecoderMap = new LinkedHashMap<>();
contentDecoderMap.put(ContentCoding.GZIP.token(), GZIPInputStream::new); contentDecoderMap.put(ContentCoding.GZIP.token(), GZIPInputStream::new);
contentDecoderMap.put(ContentCoding.DEFLATE.token(), DeflateInputStream::new); contentDecoderMap.put(ContentCoding.DEFLATE.token(), DeflateInputStream::new);
contentDecoderMap.put(ContentCoding.BROTLI.token(), BrotliInputStream::new); contentDecoderMap.put(ContentCoding.BROTLI.token(), BrotliInputStream::new);
RedirectStrategy redirectStrategy = config.httpClient().blockLocalAddresses() RedirectStrategy redirectStrategy =
? new BlockLocalAddressesRedirectStrategy(DNS_RESOLVER) config.httpClient().blockLocalAddresses()
: new DefaultRedirectStrategy(); ? new BlockLocalAddressesRedirectStrategy(DNS_RESOLVER)
: new DefaultRedirectStrategy();
return HttpClientBuilder.create() return HttpClientBuilder.create()
.useSystemProperties() .disableConnectionState()
.disableAutomaticRetries() .useSystemProperties()
.disableCookieManagement() .disableAutomaticRetries()
.setUserAgent(userAgent) .disableCookieManagement()
.setDefaultHeaders(headers) .setUserAgent(userAgent)
.setConnectionManager(connectionManager) .setDefaultHeaders(headers)
.evictExpiredConnections() .setConnectionManager(connectionManager)
.evictIdleConnections(TimeValue.of(config.httpClient().idleConnectionsEvictionInterval())) .evictExpiredConnections()
.setContentDecoderRegistry(new LinkedHashMap<>(contentDecoderMap)) .evictIdleConnections(
.setRedirectStrategy(redirectStrategy) TimeValue.of(config.httpClient().idleConnectionsEvictionInterval()))
.build(); .setContentDecoderRegistry(new LinkedHashMap<>(contentDecoderMap))
} .setRedirectStrategy(redirectStrategy)
.build();
}
private PoolingHttpClientConnectionManager newConnectionManager(CommaFeedConfiguration config, int poolSize) { private PoolingHttpClientConnectionManager newConnectionManager(
SSLFactory sslFactory = SSLFactory.builder().withUnsafeTrustMaterial().withUnsafeHostnameVerifier().build(); CommaFeedConfiguration config, int poolSize) {
DnsResolver dnsResolver = config.httpClient().blockLocalAddresses() ? new BlockLocalAddressesDnsResolver(DNS_RESOLVER) SSLFactory sslFactory =
: DNS_RESOLVER; SSLFactory.builder().withUnsafeTrustMaterial().withUnsafeHostnameVerifier().build();
DnsResolver dnsResolver =
config.httpClient().blockLocalAddresses()
? new BlockLocalAddressesDnsResolver(DNS_RESOLVER)
: DNS_RESOLVER;
return PoolingHttpClientConnectionManagerBuilder.create() return PoolingHttpClientConnectionManagerBuilder.create()
.setTlsSocketStrategy(Apache5SslUtils.toTlsSocketStrategy(sslFactory)) .setTlsSocketStrategy(Apache5SslUtils.toTlsSocketStrategy(sslFactory))
.setDefaultConnectionConfig(ConnectionConfig.custom() .setDefaultConnectionConfig(
.setConnectTimeout(Timeout.of(config.httpClient().connectTimeout())) ConnectionConfig.custom()
.setSocketTimeout(Timeout.of(config.httpClient().socketTimeout())) .setConnectTimeout(Timeout.of(config.httpClient().connectTimeout()))
.setTimeToLive(Timeout.of(config.httpClient().connectionTimeToLive())) .setSocketTimeout(Timeout.of(config.httpClient().socketTimeout()))
.build()) .setTimeToLive(
.setDefaultTlsConfig(TlsConfig.custom().setHandshakeTimeout(Timeout.of(config.httpClient().sslHandshakeTimeout())).build()) Timeout.of(config.httpClient().connectionTimeToLive()))
.setMaxConnPerRoute(poolSize) .build())
.setMaxConnTotal(poolSize) .setDefaultTlsConfig(
.setDnsResolver(dnsResolver) TlsConfig.custom()
.build(); .setHandshakeTimeout(
Timeout.of(config.httpClient().sslHandshakeTimeout()))
.build())
.setMaxConnPerRoute(poolSize)
.setMaxConnTotal(poolSize)
.setDnsResolver(dnsResolver)
.build();
}
} private static boolean isLocalAddress(InetAddress address) {
IPAddress ip = new IPAddressNetwork.IPAddressGenerator().from(address);
return ip.isLocal() || ip.isLoopback() || ip.isMulticast() || CGNAT_RANGE.contains(ip);
}
private static boolean isLocalAddress(InetAddress address) { private record BlockLocalAddressesDnsResolver(DnsResolver delegate) implements DnsResolver {
return address.isSiteLocalAddress() || address.isAnyLocalAddress() || address.isLinkLocalAddress() || address.isLoopbackAddress() @Override
|| address.isMulticastAddress(); public InetAddress[] resolve(String host) throws UnknownHostException {
} InetAddress[] addresses = delegate.resolve(host);
for (InetAddress addr : addresses) {
if (isLocalAddress(addr)) {
throw new UnknownHostException(
"Access to local address blocked: " + addr.getHostAddress());
}
}
return addresses;
}
private record BlockLocalAddressesDnsResolver(DnsResolver delegate) implements DnsResolver { @Override
@Override public String resolveCanonicalHostname(String host) throws UnknownHostException {
public InetAddress[] resolve(String host) throws UnknownHostException { return delegate.resolveCanonicalHostname(host);
InetAddress[] addresses = delegate.resolve(host); }
for (InetAddress addr : addresses) { }
if (isLocalAddress(addr)) {
throw new UnknownHostException("Access to local address blocked: " + addr.getHostAddress());
}
}
return addresses;
}
@Override @RequiredArgsConstructor
public String resolveCanonicalHostname(String host) throws UnknownHostException { private static class BlockLocalAddressesRedirectStrategy extends DefaultRedirectStrategy {
return delegate.resolveCanonicalHostname(host);
}
}
@RequiredArgsConstructor private final DnsResolver delegate;
private static class BlockLocalAddressesRedirectStrategy extends DefaultRedirectStrategy {
private final DnsResolver delegate; @Override
public URI getLocationURI(HttpRequest request, HttpResponse response, HttpContext context)
throws HttpException {
URI redirectUri = super.getLocationURI(request, response, context);
@Override String host = redirectUri.getHost();
public URI getLocationURI(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException { if (host == null) {
URI redirectUri = super.getLocationURI(request, response, context); throw new HttpException("Redirect URI does not have a host: " + redirectUri);
}
String host = redirectUri.getHost(); InetAddress[] addresses;
if (host == null) { try {
throw new HttpException("Redirect URI does not have a host: " + redirectUri); addresses = delegate.resolve(host);
} } catch (UnknownHostException e) {
throw new HttpException("Unknown host: " + host);
}
InetAddress[] addresses; for (InetAddress addr : addresses) {
try { if (isLocalAddress(addr)) {
addresses = delegate.resolve(host); throw new HttpException(
} catch (UnknownHostException e) { "Access to local address blocked: " + addr.getHostAddress());
throw new HttpException("Unknown host: " + host); }
} }
for (InetAddress addr : addresses) {
if (isLocalAddress(addr)) {
throw new HttpException("Access to local address blocked: " + addr.getHostAddress());
}
}
return redirectUri;
}
}
return redirectUri;
}
}
} }

View File

@@ -1,17 +1,24 @@
package com.commafeed.backend; package com.commafeed.backend;
import java.io.IOException; import com.codahale.metrics.MetricRegistry;
import java.io.InputStream; import com.commafeed.CommaFeedConfiguration;
import java.net.URI; import com.commafeed.CommaFeedConfiguration.HttpClientCache;
import java.time.Duration; import com.google.common.cache.Cache;
import java.time.Instant; import com.google.common.cache.CacheBuilder;
import java.time.InstantSource; import com.google.common.collect.Iterables;
import java.util.Optional; import com.google.common.io.ByteStreams;
import java.util.concurrent.ExecutionException; import com.google.common.net.HttpHeaders;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
import jakarta.ws.rs.core.CacheControl; import jakarta.ws.rs.core.CacheControl;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Lombok;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.hc.client5.http.config.RequestConfig; import org.apache.hc.client5.http.config.RequestConfig;
@@ -27,284 +34,335 @@ import org.apache.hc.core5.http.io.support.ClassicRequestBuilder;
import org.apache.hc.core5.util.Timeout; import org.apache.hc.core5.util.Timeout;
import org.jboss.resteasy.reactive.common.headers.CacheControlDelegate; import org.jboss.resteasy.reactive.common.headers.CacheControlDelegate;
import com.codahale.metrics.MetricRegistry; import java.io.IOException;
import com.commafeed.CommaFeedConfiguration; import java.io.InputStream;
import com.commafeed.CommaFeedConfiguration.HttpClientCache; import java.net.URI;
import com.google.common.cache.Cache; import java.time.Duration;
import com.google.common.cache.CacheBuilder; import java.time.Instant;
import com.google.common.collect.Iterables; import java.time.InstantSource;
import com.google.common.io.ByteStreams; import java.util.Optional;
import com.google.common.net.HttpHeaders; import java.util.concurrent.ExecutionException;
import lombok.Builder; /** Smart HTTP getter: handles gzip, ssl, last modified and etag headers */
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Lombok;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
/**
* Smart HTTP getter: handles gzip, ssl, last modified and etag headers
*/
@Singleton @Singleton
@Slf4j @Slf4j
public class HttpGetter { public class HttpGetter {
private final CommaFeedConfiguration config; private final CommaFeedConfiguration config;
private final InstantSource instantSource; private final InstantSource instantSource;
private final CloseableHttpClient client; private final CloseableHttpClient client;
private final Cache<HttpRequest, HttpResponse> cache; private final Cache<HttpRequest, HttpResponse> cache;
public HttpGetter(CommaFeedConfiguration config, InstantSource instantSource, HttpClientFactory httpClientFactory, public HttpGetter(
MetricRegistry metrics) { CommaFeedConfiguration config,
this.config = config; InstantSource instantSource,
this.instantSource = instantSource; HttpClientFactory httpClientFactory,
this.client = httpClientFactory.newClient(config.feedRefresh().httpThreads()); MetricRegistry metrics) {
this.cache = newCache(config); this.config = config;
this.instantSource = instantSource;
this.client = httpClientFactory.newClient(config.feedRefresh().httpThreads());
this.cache = newCache(config);
metrics.registerGauge(MetricRegistry.name(getClass(), "cache", "size"), () -> cache == null ? 0 : cache.size()); metrics.registerGauge(
metrics.registerGauge(MetricRegistry.name(getClass(), "cache", "memoryUsage"), MetricRegistry.name(getClass(), "cache", "size"),
() -> cache == null ? 0 : cache.asMap().values().stream().mapToInt(e -> ArrayUtils.getLength(e.content)).sum()); () -> cache == null ? 0 : cache.size());
} metrics.registerGauge(
MetricRegistry.name(getClass(), "cache", "memoryUsage"),
() ->
cache == null
? 0
: cache.asMap().values().stream()
.mapToInt(e -> ArrayUtils.getLength(e.content))
.sum());
}
public HttpResult get(String url) throws IOException, NotModifiedException, TooManyRequestsException, SchemeNotAllowedException { public HttpResult get(String url)
return get(HttpRequest.builder(url).build()); throws IOException,
} NotModifiedException,
TooManyRequestsException,
SchemeNotAllowedException {
return get(HttpRequest.builder(url).build());
}
public HttpResult get(HttpRequest request) public HttpResult get(HttpRequest request)
throws IOException, NotModifiedException, TooManyRequestsException, SchemeNotAllowedException { throws IOException,
URI uri = URI.create(request.getUrl()); NotModifiedException,
ensureHttpScheme(uri.getScheme()); TooManyRequestsException,
SchemeNotAllowedException {
URI uri = URI.create(request.getUrl());
ensureHttpScheme(uri.getScheme());
final HttpResponse response; final HttpResponse response;
if (cache == null) { if (cache == null) {
response = invoke(request); response = invoke(request);
} else { } else {
try { try {
response = cache.get(request, () -> invoke(request)); response = cache.get(request, () -> invoke(request));
} catch (ExecutionException e) { } catch (ExecutionException e) {
if (e.getCause() instanceof IOException ioe) { if (e.getCause() instanceof IOException ioe) {
throw ioe; throw ioe;
} else { } else {
throw Lombok.sneakyThrow(e); throw Lombok.sneakyThrow(e);
} }
} }
} }
int code = response.code(); int code = response.code();
if (code == HttpStatus.SC_TOO_MANY_REQUESTS || code == HttpStatus.SC_SERVICE_UNAVAILABLE && response.retryAfter() != null) { if (code == HttpStatus.SC_TOO_MANY_REQUESTS
throw new TooManyRequestsException(response.retryAfter()); || code == HttpStatus.SC_SERVICE_UNAVAILABLE && response.retryAfter() != null) {
} throw new TooManyRequestsException(response.retryAfter());
}
if (code == HttpStatus.SC_NOT_MODIFIED) { if (code == HttpStatus.SC_NOT_MODIFIED) {
throw new NotModifiedException("'304 - not modified' http code received"); throw new NotModifiedException("'304 - not modified' http code received");
} }
if (code >= 300) { if (code >= 300) {
throw new HttpResponseException(code, "Server returned HTTP error code " + code); throw new HttpResponseException(code, "Server returned HTTP error code " + code);
} }
String lastModifiedHeader = response.lastModifiedHeader(); String lastModifiedHeader = response.lastModifiedHeader();
String eTagHeader = response.eTagHeader(); String eTagHeader = response.eTagHeader();
Duration validFor = Optional.ofNullable(response.cacheControl()) Duration validFor =
.filter(cc -> cc.getMaxAge() >= 0) Optional.ofNullable(response.cacheControl())
.map(cc -> Duration.ofSeconds(cc.getMaxAge())) .filter(cc -> cc.getMaxAge() >= 0)
.orElse(Duration.ZERO); .map(cc -> Duration.ofSeconds(cc.getMaxAge()))
.orElse(Duration.ZERO);
return new HttpResult(response.content(), response.contentType(), lastModifiedHeader, eTagHeader, response.urlAfterRedirect(), return new HttpResult(
validFor); response.content(),
} response.contentType(),
lastModifiedHeader,
eTagHeader,
response.urlAfterRedirect(),
validFor);
}
private void ensureHttpScheme(String scheme) throws SchemeNotAllowedException { private void ensureHttpScheme(String scheme) throws SchemeNotAllowedException {
if (!"http".equalsIgnoreCase(scheme) && !"https".equalsIgnoreCase(scheme)) { if (!"http".equalsIgnoreCase(scheme) && !"https".equalsIgnoreCase(scheme)) {
throw new SchemeNotAllowedException(scheme); throw new SchemeNotAllowedException(scheme);
} }
} }
private HttpResponse invoke(HttpRequest request) throws IOException { private HttpResponse invoke(HttpRequest request) throws IOException {
log.debug("fetching {}", request.getUrl()); log.debug("fetching {}", request.getUrl());
HttpClientContext context = HttpClientContext.create(); HttpClientContext context = HttpClientContext.create();
context.setRequestConfig(RequestConfig.custom() context.setRequestConfig(
.setResponseTimeout(Timeout.of(config.httpClient().responseTimeout())) RequestConfig.custom()
// causes issues with some feeds .setResponseTimeout(Timeout.of(config.httpClient().responseTimeout()))
// see https://github.com/Athou/commafeed/issues/1572 // causes issues with some feeds
// and https://issues.apache.org/jira/browse/HTTPCLIENT-2344 // see https://github.com/Athou/commafeed/issues/1572
.setProtocolUpgradeEnabled(false) // and https://issues.apache.org/jira/browse/HTTPCLIENT-2344
.build()); .setProtocolUpgradeEnabled(false)
.build());
return client.execute(request.toClassicHttpRequest(), context, resp -> { return client.execute(
byte[] content = resp.getEntity() == null ? null request.toClassicHttpRequest(),
: toByteArray(resp.getEntity(), config.httpClient().maxResponseSize().asLongValue()); context,
int code = resp.getCode(); resp -> {
String lastModifiedHeader = Optional.ofNullable(resp.getFirstHeader(HttpHeaders.LAST_MODIFIED)) byte[] content =
.map(NameValuePair::getValue) resp.getEntity() == null
.map(StringUtils::trimToNull) ? null
.orElse(null); : toByteArray(
String eTagHeader = Optional.ofNullable(resp.getFirstHeader(HttpHeaders.ETAG)) resp.getEntity(),
.map(NameValuePair::getValue) config.httpClient().maxResponseSize().asLongValue());
.map(StringUtils::trimToNull) int code = resp.getCode();
.orElse(null); String lastModifiedHeader =
Optional.ofNullable(resp.getFirstHeader(HttpHeaders.LAST_MODIFIED))
.map(NameValuePair::getValue)
.map(StringUtils::trimToNull)
.orElse(null);
String eTagHeader =
Optional.ofNullable(resp.getFirstHeader(HttpHeaders.ETAG))
.map(NameValuePair::getValue)
.map(StringUtils::trimToNull)
.orElse(null);
CacheControl cacheControl = Optional.ofNullable(resp.getFirstHeader(HttpHeaders.CACHE_CONTROL)) CacheControl cacheControl =
.map(NameValuePair::getValue) Optional.ofNullable(resp.getFirstHeader(HttpHeaders.CACHE_CONTROL))
.map(StringUtils::trimToNull) .map(NameValuePair::getValue)
.map(HttpGetter::toCacheControl) .map(StringUtils::trimToNull)
.orElse(null); .map(HttpGetter::toCacheControl)
.orElse(null);
Instant retryAfter = Optional.ofNullable(resp.getFirstHeader(HttpHeaders.RETRY_AFTER)) Instant retryAfter =
.map(NameValuePair::getValue) Optional.ofNullable(resp.getFirstHeader(HttpHeaders.RETRY_AFTER))
.map(StringUtils::trimToNull) .map(NameValuePair::getValue)
.map(this::toInstant) .map(StringUtils::trimToNull)
.orElse(null); .map(this::toInstant)
.orElse(null);
String contentType = Optional.ofNullable(resp.getEntity()).map(HttpEntity::getContentType).orElse(null); String contentType =
String urlAfterRedirect = Optional.ofNullable(context.getRedirectLocations()) Optional.ofNullable(resp.getEntity())
.map(RedirectLocations::getAll) .map(HttpEntity::getContentType)
.map(l -> Iterables.getLast(l, null)) .orElse(null);
.map(URI::toString) String urlAfterRedirect =
.orElse(request.getUrl()); Optional.ofNullable(context.getRedirectLocations())
.map(RedirectLocations::getAll)
.map(l -> Iterables.getLast(l, null))
.map(URI::toString)
.orElse(request.getUrl());
return new HttpResponse(code, lastModifiedHeader, eTagHeader, cacheControl, retryAfter, content, contentType, urlAfterRedirect); return new HttpResponse(
}); code,
} lastModifiedHeader,
eTagHeader,
cacheControl,
retryAfter,
content,
contentType,
urlAfterRedirect);
});
}
private static CacheControl toCacheControl(String headerValue) { private static CacheControl toCacheControl(String headerValue) {
try { try {
return CacheControlDelegate.INSTANCE.fromString(headerValue); return CacheControlDelegate.INSTANCE.fromString(headerValue);
} catch (Exception e) { } catch (Exception e) {
log.debug("Invalid Cache-Control header: {}", headerValue); log.debug("Invalid Cache-Control header: {}", headerValue);
return null; return null;
} }
} }
private Instant toInstant(String headerValue) { private Instant toInstant(String headerValue) {
if (headerValue == null) { if (headerValue == null) {
return null; return null;
} }
if (StringUtils.isNumeric(headerValue)) { if (StringUtils.isNumeric(headerValue)) {
return instantSource.instant().plusSeconds(Long.parseLong(headerValue)); return instantSource.instant().plusSeconds(Long.parseLong(headerValue));
} }
return DateUtils.parseStandardDate(headerValue); return DateUtils.parseStandardDate(headerValue);
} }
private static byte[] toByteArray(HttpEntity entity, long maxBytes) throws IOException { private static byte[] toByteArray(HttpEntity entity, long maxBytes) throws IOException {
if (entity.getContentLength() > maxBytes) { if (entity.getContentLength() > maxBytes) {
throw new IOException( throw new IOException(
"Response size (%s bytes) exceeds the maximum allowed size (%s bytes)".formatted(entity.getContentLength(), maxBytes)); "Response size (%s bytes) exceeds the maximum allowed size (%s bytes)"
} .formatted(entity.getContentLength(), maxBytes));
}
try (InputStream input = entity.getContent()) { try (InputStream input = entity.getContent()) {
if (input == null) { if (input == null) {
return null; return null;
} }
byte[] bytes = ByteStreams.limit(input, maxBytes + 1).readAllBytes(); byte[] bytes = ByteStreams.limit(input, maxBytes + 1).readAllBytes();
if (bytes.length > maxBytes) { if (bytes.length > maxBytes) {
throw new IOException("Response size exceeds the maximum allowed size (%s bytes)".formatted(maxBytes)); throw new IOException(
} "Response size exceeds the maximum allowed size (%s bytes)"
return bytes; .formatted(maxBytes));
} }
} return bytes;
}
}
private static Cache<HttpRequest, HttpResponse> newCache(CommaFeedConfiguration config) { private static Cache<HttpRequest, HttpResponse> newCache(CommaFeedConfiguration config) {
HttpClientCache cacheConfig = config.httpClient().cache(); HttpClientCache cacheConfig = config.httpClient().cache();
if (!cacheConfig.enabled()) { if (!cacheConfig.enabled()) {
return null; return null;
} }
return CacheBuilder.newBuilder() return CacheBuilder.newBuilder()
.weigher((HttpRequest key, HttpResponse value) -> value.content() != null ? value.content().length : 0) .weigher(
.maximumWeight(cacheConfig.maximumMemorySize().asLongValue()) (HttpRequest key, HttpResponse value) ->
.expireAfterWrite(cacheConfig.expiration()) value.content() != null ? value.content().length : 0)
.build(); .maximumWeight(cacheConfig.maximumMemorySize().asLongValue())
} .expireAfterWrite(cacheConfig.expiration())
.build();
}
public static class SchemeNotAllowedException extends Exception { public static class SchemeNotAllowedException extends Exception {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public SchemeNotAllowedException(String scheme) { public SchemeNotAllowedException(String scheme) {
super("Scheme not allowed: " + scheme); super("Scheme not allowed: " + scheme);
} }
} }
@Getter @Getter
public static class NotModifiedException extends Exception { public static class NotModifiedException extends Exception {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** /** if the value of this header changed, this is its new value */
* if the value of this header changed, this is its new value private final String newLastModifiedHeader;
*/
private final String newLastModifiedHeader;
/** /** if the value of this header changed, this is its new value */
* if the value of this header changed, this is its new value private final String newEtagHeader;
*/
private final String newEtagHeader;
public NotModifiedException(String message) { public NotModifiedException(String message) {
this(message, null, null); this(message, null, null);
} }
public NotModifiedException(String message, String newLastModifiedHeader, String newEtagHeader) { public NotModifiedException(
super(message); String message, String newLastModifiedHeader, String newEtagHeader) {
this.newLastModifiedHeader = newLastModifiedHeader; super(message);
this.newEtagHeader = newEtagHeader; this.newLastModifiedHeader = newLastModifiedHeader;
} this.newEtagHeader = newEtagHeader;
} }
}
@RequiredArgsConstructor @RequiredArgsConstructor
@Getter @Getter
public static class TooManyRequestsException extends Exception { public static class TooManyRequestsException extends Exception {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final Instant retryAfter; private final Instant retryAfter;
} }
@Getter @Getter
public static class HttpResponseException extends IOException { public static class HttpResponseException extends IOException {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final int code; private final int code;
public HttpResponseException(int code, String message) { public HttpResponseException(int code, String message) {
super(message); super(message);
this.code = code; this.code = code;
} }
} }
@Builder(builderMethodName = "") @Builder(builderMethodName = "")
@EqualsAndHashCode @EqualsAndHashCode
@Getter @Getter
public static class HttpRequest { public static class HttpRequest {
private String url; private String url;
private String lastModified; private String lastModified;
private String eTag; private String eTag;
public static HttpRequestBuilder builder(String url) { public static HttpRequestBuilder builder(String url) {
return new HttpRequestBuilder().url(url); return new HttpRequestBuilder().url(url);
} }
public ClassicHttpRequest toClassicHttpRequest() { public ClassicHttpRequest toClassicHttpRequest() {
ClassicHttpRequest req = ClassicRequestBuilder.get(url).build(); ClassicHttpRequest req = ClassicRequestBuilder.get(url).build();
if (lastModified != null) { if (lastModified != null) {
req.addHeader(HttpHeaders.IF_MODIFIED_SINCE, lastModified); req.addHeader(HttpHeaders.IF_MODIFIED_SINCE, lastModified);
} }
if (eTag != null) { if (eTag != null) {
req.addHeader(HttpHeaders.IF_NONE_MATCH, eTag); req.addHeader(HttpHeaders.IF_NONE_MATCH, eTag);
} }
return req; return req;
} }
} }
private record HttpResponse(int code, String lastModifiedHeader, String eTagHeader, CacheControl cacheControl, Instant retryAfter, private record HttpResponse(
byte[] content, String contentType, String urlAfterRedirect) { int code,
} String lastModifiedHeader,
String eTagHeader,
public record HttpResult(byte[] content, String contentType, String lastModifiedSince, String eTag, String urlAfterRedirect, CacheControl cacheControl,
Duration validFor) { Instant retryAfter,
} byte[] content,
String contentType,
String urlAfterRedirect) {}
public record HttpResult(
byte[] content,
String contentType,
String lastModifiedSince,
String eTag,
String urlAfterRedirect,
Duration validFor) {}
} }

View File

@@ -1,106 +1,129 @@
package com.commafeed.backend; package com.commafeed.backend;
import java.net.URI; import lombok.experimental.UtilityClass;
import java.util.regex.Pattern; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.Strings; import org.apache.commons.lang3.Strings;
import org.netpreserve.urlcanon.Canonicalizer; import org.netpreserve.urlcanon.Canonicalizer;
import org.netpreserve.urlcanon.ParsedUrl; import org.netpreserve.urlcanon.ParsedUrl;
import lombok.experimental.UtilityClass; import java.net.URI;
import lombok.extern.slf4j.Slf4j; import java.util.Locale;
import java.util.regex.Pattern;
@UtilityClass @UtilityClass
@Slf4j @Slf4j
public class Urls { public class Urls {
private static final String ESCAPED_QUESTION_MARK = Pattern.quote("?"); private static final Pattern QUESTION_MARK = Pattern.compile(Pattern.quote("?"));
public static boolean isHttp(String url) { public static boolean isHttp(String url) {
return url.startsWith("http://"); if (url == null) {
} return false;
}
public static boolean isHttps(String url) { return url.toLowerCase(Locale.ROOT).startsWith("http://");
return url.startsWith("https://"); }
}
public static boolean isAbsolute(String url) { public static boolean isHttps(String url) {
return isHttp(url) || isHttps(url); if (url == null) {
} return false;
}
/** return url.toLowerCase(Locale.ROOT).startsWith("https://");
* }
* @param relativeUrl
* the url of the entry
* @param feedLink
* the url of the feed as described in the feed
* @param feedUrl
* the url of the feed that we used to fetch the feed
* @return an absolute url pointing to the entry
*/
public static String toAbsolute(String relativeUrl, String feedLink, String feedUrl) {
String baseUrl = (feedLink != null && isAbsolute(feedLink)) ? feedLink : feedUrl;
if (baseUrl == null) {
return null;
}
try { public static boolean isAbsolute(String url) {
return URI.create(baseUrl).resolve(relativeUrl).toString(); return isHttp(url) || isHttps(url);
} catch (IllegalArgumentException e) { }
log.debug("Unable to create absolute url from relative url: {} base: {}", relativeUrl, baseUrl, e);
return null;
}
}
public static String removeTrailingSlash(String url) { /** remove malicious 'javascript: 'URLs * */
if (url == null) { public static String sanitize(String url) {
return null; if (url == null) {
} return null;
}
if (url.endsWith("/")) { if (!isHttp(url) && !isHttps(url)) {
url = url.substring(0, url.length() - 1); return null;
} }
return url;
}
/** return url;
* Normalize the url. The resulting url is not meant to be fetched but rather used as a mean to identify a feed and avoid duplicates }
*/
public static String normalize(String url) {
if (url == null) {
return null;
}
ParsedUrl parsedUrl = ParsedUrl.parseUrl(url); /**
Canonicalizer.AGGRESSIVE.canonicalize(parsedUrl); * @param relativeUrl the url of the entry
String normalized = parsedUrl.toString(); * @param feedLink the url of the feed as described in the feed
if (normalized == null) { * @param feedUrl the url of the feed that we used to fetch the feed
normalized = url; * @return an absolute url pointing to the entry
} */
public static String toAbsolute(String relativeUrl, String feedLink, String feedUrl) {
String baseUrl = (feedLink != null && isAbsolute(feedLink)) ? feedLink : feedUrl;
if (baseUrl == null) {
return null;
}
// convert to lower case, the url probably won't work in some cases try {
// after that but we don't care we just want to compare urls to avoid return URI.create(baseUrl).resolve(relativeUrl).toString();
// duplicates } catch (IllegalArgumentException e) {
normalized = normalized.toLowerCase(); log.debug(
"Unable to create absolute url from relative url: {} base: {}",
relativeUrl,
baseUrl,
e);
return null;
}
}
// store all urls as http public static String removeTrailingSlash(String url) {
if (normalized.startsWith("https")) { if (url == null) {
normalized = "http" + normalized.substring(5); return null;
} }
// remove the www. part if (url.endsWith("/")) {
normalized = normalized.replace("//www.", "//"); url = url.substring(0, url.length() - 1);
}
return url;
}
// feedproxy redirects to feedburner /**
normalized = normalized.replace("feedproxy.google.com", "feeds.feedburner.com"); * Normalize the url. The resulting url is not meant to be fetched but rather used as a mean to
* identify a feed and avoid duplicates
*/
public static String normalize(String url) {
if (url == null) {
return null;
}
// feedburner feeds have a special treatment ParsedUrl parsedUrl = ParsedUrl.parseUrl(url);
if (normalized.split(ESCAPED_QUESTION_MARK)[0].contains("feedburner.com")) { Canonicalizer.AGGRESSIVE.canonicalize(parsedUrl);
normalized = normalized.replace("feeds2.feedburner.com", "feeds.feedburner.com"); String normalized = parsedUrl.toString();
normalized = normalized.split(ESCAPED_QUESTION_MARK)[0]; if (normalized == null) {
normalized = Strings.CS.removeEnd(normalized, "/"); normalized = url;
} }
return normalized; // convert to lower case, the url probably won't work in some cases
} // after that but we don't care we just want to compare urls to avoid
// duplicates
normalized = normalized.toLowerCase();
// store all urls as http
if (normalized.startsWith("https")) {
normalized = "http" + normalized.substring(5);
}
// remove the www. part
normalized = normalized.replace("//www.", "//");
// feedproxy redirects to feedburner
normalized = normalized.replace("feedproxy.google.com", "feeds.feedburner.com");
// feedburner feeds have a special treatment
if (QUESTION_MARK.split(normalized)[0].contains("feedburner.com")) {
normalized = normalized.replace("feeds2.feedburner.com", "feeds.feedburner.com");
normalized = QUESTION_MARK.split(normalized)[0];
normalized = Strings.CS.removeEnd(normalized, "/");
}
return normalized;
}
} }

View File

@@ -1,71 +1,78 @@
package com.commafeed.backend.dao; package com.commafeed.backend.dao;
import java.util.List;
import java.util.Objects;
import jakarta.inject.Singleton;
import jakarta.persistence.EntityManager;
import com.commafeed.backend.model.FeedCategory; import com.commafeed.backend.model.FeedCategory;
import com.commafeed.backend.model.QFeedCategory; import com.commafeed.backend.model.QFeedCategory;
import com.commafeed.backend.model.QUser; import com.commafeed.backend.model.QUser;
import com.commafeed.backend.model.User; import com.commafeed.backend.model.User;
import com.querydsl.core.types.Predicate; import com.querydsl.core.types.Predicate;
import jakarta.inject.Singleton;
import jakarta.persistence.EntityManager;
import java.util.List;
import java.util.Objects;
@Singleton @Singleton
public class FeedCategoryDAO extends GenericDAO<FeedCategory> { public class FeedCategoryDAO extends GenericDAO<FeedCategory> {
private static final QFeedCategory CATEGORY = QFeedCategory.feedCategory; private static final QFeedCategory CATEGORY = QFeedCategory.feedCategory;
public FeedCategoryDAO(EntityManager entityManager) { public FeedCategoryDAO(EntityManager entityManager) {
super(entityManager, FeedCategory.class); super(entityManager, FeedCategory.class);
} }
public List<FeedCategory> findAll(User user) { public List<FeedCategory> findAll(User user) {
return query().selectFrom(CATEGORY).where(CATEGORY.user.eq(user)).join(CATEGORY.user, QUser.user).fetchJoin().fetch(); return query().selectFrom(CATEGORY)
} .where(CATEGORY.user.eq(user))
.join(CATEGORY.user, QUser.user)
.fetchJoin()
.fetch();
}
public FeedCategory findById(User user, Long id) { public FeedCategory findById(User user, Long id) {
return query().selectFrom(CATEGORY).where(CATEGORY.user.eq(user), CATEGORY.id.eq(id)).fetchOne(); return query().selectFrom(CATEGORY)
} .where(CATEGORY.user.eq(user), CATEGORY.id.eq(id))
.fetchOne();
}
public FeedCategory findByName(User user, String name, FeedCategory parent) { public FeedCategory findByName(User user, String name, FeedCategory parent) {
Predicate parentPredicate; Predicate parentPredicate;
if (parent == null) { if (parent == null) {
parentPredicate = CATEGORY.parent.isNull(); parentPredicate = CATEGORY.parent.isNull();
} else { } else {
parentPredicate = CATEGORY.parent.eq(parent); parentPredicate = CATEGORY.parent.eq(parent);
} }
return query().selectFrom(CATEGORY).where(CATEGORY.user.eq(user), CATEGORY.name.eq(name), parentPredicate).fetchOne(); return query().selectFrom(CATEGORY)
} .where(CATEGORY.user.eq(user), CATEGORY.name.eq(name), parentPredicate)
.fetchOne();
}
public List<FeedCategory> findByParent(User user, FeedCategory parent) { public List<FeedCategory> findByParent(User user, FeedCategory parent) {
Predicate parentPredicate; Predicate parentPredicate;
if (parent == null) { if (parent == null) {
parentPredicate = CATEGORY.parent.isNull(); parentPredicate = CATEGORY.parent.isNull();
} else { } else {
parentPredicate = CATEGORY.parent.eq(parent); parentPredicate = CATEGORY.parent.eq(parent);
} }
return query().selectFrom(CATEGORY).where(CATEGORY.user.eq(user), parentPredicate).fetch(); return query().selectFrom(CATEGORY).where(CATEGORY.user.eq(user), parentPredicate).fetch();
} }
public List<FeedCategory> findAllChildrenCategories(User user, FeedCategory parent) { public List<FeedCategory> findAllChildrenCategories(User user, FeedCategory parent) {
return findAll(user).stream().filter(c -> isChild(c, parent)).toList(); return findAll(user).stream().filter(c -> isChild(c, parent)).toList();
} }
private boolean isChild(FeedCategory child, FeedCategory parent) {
if (parent == null) {
return true;
}
boolean isChild = false;
while (child != null) {
if (Objects.equals(child.getId(), parent.getId())) {
isChild = true;
break;
}
child = child.getParent();
}
return isChild;
}
private boolean isChild(FeedCategory child, FeedCategory parent) {
if (parent == null) {
return true;
}
boolean isChild = false;
while (child != null) {
if (Objects.equals(child.getId(), parent.getId())) {
isChild = true;
break;
}
child = child.getParent();
}
return isChild;
}
} }

View File

@@ -1,64 +1,72 @@
package com.commafeed.backend.dao; package com.commafeed.backend.dao;
import java.time.Instant;
import java.util.List;
import jakarta.inject.Singleton;
import jakarta.persistence.EntityManager;
import org.apache.commons.lang3.Strings;
import com.commafeed.backend.model.Feed; import com.commafeed.backend.model.Feed;
import com.commafeed.backend.model.QFeed; import com.commafeed.backend.model.QFeed;
import com.commafeed.backend.model.QFeedSubscription; import com.commafeed.backend.model.QFeedSubscription;
import com.querydsl.jpa.JPAExpressions; import com.querydsl.jpa.JPAExpressions;
import com.querydsl.jpa.impl.JPAQuery; import com.querydsl.jpa.impl.JPAQuery;
import jakarta.inject.Singleton;
import jakarta.persistence.EntityManager;
import org.apache.commons.lang3.Strings;
import java.time.Instant;
import java.util.List;
@Singleton @Singleton
public class FeedDAO extends GenericDAO<Feed> { public class FeedDAO extends GenericDAO<Feed> {
private static final QFeed FEED = QFeed.feed; private static final QFeed FEED = QFeed.feed;
private static final QFeedSubscription SUBSCRIPTION = QFeedSubscription.feedSubscription; private static final QFeedSubscription SUBSCRIPTION = QFeedSubscription.feedSubscription;
public FeedDAO(EntityManager entityManager) { public FeedDAO(EntityManager entityManager) {
super(entityManager, Feed.class); super(entityManager, Feed.class);
} }
public List<Feed> findByIds(List<Long> id) { public List<Feed> findByIds(List<Long> id) {
return query().selectFrom(FEED).where(FEED.id.in(id)).fetch(); return query().selectFrom(FEED).where(FEED.id.in(id)).fetch();
} }
public List<Feed> findNextUpdatable(int count, Instant lastLoginThreshold) { public List<Feed> findNextUpdatable(int count, Instant lastLoginThreshold) {
JPAQuery<Feed> query = query().selectFrom(FEED) JPAQuery<Feed> query =
.distinct() query().selectFrom(FEED)
// join on subscriptions to only refresh feeds that have subscribers .distinct()
.join(SUBSCRIPTION) // join on subscriptions to only refresh feeds that have subscribers
.on(SUBSCRIPTION.feed.eq(FEED)) .join(SUBSCRIPTION)
.where(FEED.disabledUntil.isNull().or(FEED.disabledUntil.lt(Instant.now()))); .on(SUBSCRIPTION.feed.eq(FEED))
.where(
FEED.disabledUntil
.isNull()
.or(FEED.disabledUntil.lt(Instant.now())));
if (lastLoginThreshold != null) { if (lastLoginThreshold != null) {
query.join(SUBSCRIPTION.user).where(SUBSCRIPTION.user.lastLogin.gt(lastLoginThreshold)); query.join(SUBSCRIPTION.user).where(SUBSCRIPTION.user.lastLogin.gt(lastLoginThreshold));
} }
return query.orderBy(FEED.disabledUntil.asc()).limit(count).fetch(); return query.orderBy(FEED.disabledUntil.asc()).limit(count).fetch();
} }
public void setDisabledUntil(List<Long> feedIds, Instant date) { public void setDisabledUntil(List<Long> feedIds, Instant date) {
updateQuery(FEED).set(FEED.disabledUntil, date).where(FEED.id.in(feedIds)).execute(); updateQuery(FEED).set(FEED.disabledUntil, date).where(FEED.id.in(feedIds)).execute();
} }
public Feed findByUrl(String normalizedUrl, String normalizedUrlHash) { public Feed findByUrl(String normalizedUrl, String normalizedUrlHash) {
return query().selectFrom(FEED) return query()
.where(FEED.normalizedUrlHash.eq(normalizedUrlHash)) .selectFrom(FEED)
.fetch() .where(FEED.normalizedUrlHash.eq(normalizedUrlHash))
.stream() .fetch()
.filter(f -> Strings.CS.equals(normalizedUrl, f.getNormalizedUrl())) .stream()
.findFirst() .filter(f -> Strings.CS.equals(normalizedUrl, f.getNormalizedUrl()))
.orElse(null); .findFirst()
} .orElse(null);
}
public List<Feed> findWithoutSubscriptions(int max) { public List<Feed> findWithoutSubscriptions(int max) {
QFeedSubscription sub = QFeedSubscription.feedSubscription; QFeedSubscription sub = QFeedSubscription.feedSubscription;
return query().selectFrom(FEED).where(JPAExpressions.selectOne().from(sub).where(sub.feed.eq(FEED)).notExists()).limit(max).fetch(); return query().selectFrom(FEED)
} .where(JPAExpressions.selectOne().from(sub).where(sub.feed.eq(FEED)).notExists())
.limit(max)
.fetch();
}
} }

View File

@@ -1,36 +1,40 @@
package com.commafeed.backend.dao; package com.commafeed.backend.dao;
import java.util.List;
import jakarta.inject.Singleton;
import jakarta.persistence.EntityManager;
import com.commafeed.backend.model.FeedEntryContent; import com.commafeed.backend.model.FeedEntryContent;
import com.commafeed.backend.model.QFeedEntry; import com.commafeed.backend.model.QFeedEntry;
import com.commafeed.backend.model.QFeedEntryContent; import com.commafeed.backend.model.QFeedEntryContent;
import jakarta.inject.Singleton;
import jakarta.persistence.EntityManager;
import java.util.List;
@Singleton @Singleton
public class FeedEntryContentDAO extends GenericDAO<FeedEntryContent> { public class FeedEntryContentDAO extends GenericDAO<FeedEntryContent> {
private static final QFeedEntryContent CONTENT = QFeedEntryContent.feedEntryContent; private static final QFeedEntryContent CONTENT = QFeedEntryContent.feedEntryContent;
private static final QFeedEntry ENTRY = QFeedEntry.feedEntry; private static final QFeedEntry ENTRY = QFeedEntry.feedEntry;
public FeedEntryContentDAO(EntityManager entityManager) { public FeedEntryContentDAO(EntityManager entityManager) {
super(entityManager, FeedEntryContent.class); super(entityManager, FeedEntryContent.class);
} }
public List<FeedEntryContent> findExisting(String contentHash, String titleHash) { public List<FeedEntryContent> findExisting(String contentHash, String titleHash) {
return query().select(CONTENT).from(CONTENT).where(CONTENT.contentHash.eq(contentHash), CONTENT.titleHash.eq(titleHash)).fetch(); return query().select(CONTENT)
} .from(CONTENT)
.where(CONTENT.contentHash.eq(contentHash), CONTENT.titleHash.eq(titleHash))
.fetch();
}
public long deleteWithoutEntries(int max) { public long deleteWithoutEntries(int max) {
List<Long> ids = query().select(CONTENT.id) List<Long> ids =
.from(CONTENT) query().select(CONTENT.id)
.leftJoin(ENTRY) .from(CONTENT)
.on(ENTRY.content.id.eq(CONTENT.id)) .leftJoin(ENTRY)
.where(ENTRY.id.isNull()) .on(ENTRY.content.id.eq(CONTENT.id))
.limit(max) .where(ENTRY.id.isNull())
.fetch(); .limit(max)
return deleteQuery(CONTENT).where(CONTENT.id.in(ids)).execute(); .fetch();
} return deleteQuery(CONTENT).where(CONTENT.id.in(ids)).execute();
}
} }

View File

@@ -1,82 +1,106 @@
package com.commafeed.backend.dao; package com.commafeed.backend.dao;
import java.time.Instant;
import java.util.List;
import jakarta.inject.Singleton;
import jakarta.persistence.EntityManager;
import com.commafeed.backend.model.Feed; import com.commafeed.backend.model.Feed;
import com.commafeed.backend.model.FeedEntry; import com.commafeed.backend.model.FeedEntry;
import com.commafeed.backend.model.QFeedEntry; import com.commafeed.backend.model.QFeedEntry;
import com.google.common.collect.Lists;
import com.querydsl.core.Tuple; import com.querydsl.core.Tuple;
import com.querydsl.core.types.dsl.NumberExpression; import com.querydsl.core.types.dsl.NumberExpression;
import com.querydsl.jpa.impl.JPAQuery; import com.querydsl.jpa.impl.JPAQuery;
import jakarta.inject.Singleton;
import jakarta.persistence.EntityManager;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Singleton @Singleton
public class FeedEntryDAO extends GenericDAO<FeedEntry> { public class FeedEntryDAO extends GenericDAO<FeedEntry> {
private static final QFeedEntry ENTRY = QFeedEntry.feedEntry; private static final QFeedEntry ENTRY = QFeedEntry.feedEntry;
private static final int IN_CLAUSE_BATCH_SIZE = 1000;
public FeedEntryDAO(EntityManager entityManager) { public FeedEntryDAO(EntityManager entityManager) {
super(entityManager, FeedEntry.class); super(entityManager, FeedEntry.class);
} }
public FeedEntry findExisting(String guidHash, Feed feed) { public FeedEntry findExisting(String guidHash, Feed feed) {
return query().select(ENTRY).from(ENTRY).where(ENTRY.guidHash.eq(guidHash), ENTRY.feed.eq(feed)).limit(1).fetchOne(); return query().select(ENTRY)
} .from(ENTRY)
.where(ENTRY.guidHash.eq(guidHash), ENTRY.feed.eq(feed))
.limit(1)
.fetchOne();
}
public List<FeedCapacity> findFeedsExceedingCapacity(long maxCapacity, long max, boolean keepStarredEntries) { public Set<String> findExistingGuidHashes(Set<String> guidHashes, Feed feed) {
NumberExpression<Long> count = ENTRY.id.count(); if (guidHashes.isEmpty()) {
JPAQuery<Tuple> query = query().select(ENTRY.feed.id, count).from(ENTRY); return Set.of();
}
if (keepStarredEntries) { Set<String> result = new HashSet<>();
query.where(Predicates.isNotStarred(ENTRY)); for (List<String> batch :
} Lists.partition(new ArrayList<>(guidHashes), IN_CLAUSE_BATCH_SIZE)) {
result.addAll(
query().select(ENTRY.guidHash)
.from(ENTRY)
.where(ENTRY.feed.eq(feed), ENTRY.guidHash.in(batch))
.fetch());
}
return result;
}
return query.groupBy(ENTRY.feed) public List<FeedCapacity> findFeedsExceedingCapacity(
.having(count.gt(maxCapacity)) long maxCapacity, long max, boolean keepStarredEntries) {
.limit(max) NumberExpression<Long> count = ENTRY.id.count();
.fetch() JPAQuery<Tuple> query = query().select(ENTRY.feed.id, count).from(ENTRY);
.stream()
.map(t -> new FeedCapacity(t.get(ENTRY.feed.id), t.get(count)))
.toList();
}
public int delete(Long feedId, long max) { if (keepStarredEntries) {
List<FeedEntry> list = query().selectFrom(ENTRY).where(ENTRY.feed.id.eq(feedId)).limit(max).fetch(); query.where(Predicates.isNotStarred(ENTRY));
return delete(list); }
}
/** return query.groupBy(ENTRY.feed).having(count.gt(maxCapacity)).limit(max).fetch().stream()
* Delete entries older than a certain date .map(t -> new FeedCapacity(t.get(ENTRY.feed.id), t.get(count)))
*/ .toList();
public int deleteEntriesOlderThan(Instant olderThan, long max, boolean keepStarredEntries) { }
JPAQuery<FeedEntry> query = query().selectFrom(ENTRY)
.where(ENTRY.published.lt(olderThan))
.orderBy(ENTRY.published.asc())
.limit(max);
if (keepStarredEntries) { public int delete(Long feedId, long max) {
query.where(Predicates.isNotStarred(ENTRY)); List<FeedEntry> list =
} query().selectFrom(ENTRY).where(ENTRY.feed.id.eq(feedId)).limit(max).fetch();
return delete(list);
}
return delete(query.fetch()); /** Delete entries older than a certain date */
} public int deleteEntriesOlderThan(Instant olderThan, long max, boolean keepStarredEntries) {
JPAQuery<FeedEntry> query =
query().selectFrom(ENTRY)
.where(ENTRY.published.lt(olderThan))
.orderBy(ENTRY.published.asc())
.limit(max);
/** if (keepStarredEntries) {
* Delete the oldest entries of a feed query.where(Predicates.isNotStarred(ENTRY));
*/ }
public int deleteOldEntries(Long feedId, long max, boolean keepStarredEntries) {
JPAQuery<FeedEntry> query = query().selectFrom(ENTRY).where(ENTRY.feed.id.eq(feedId)).orderBy(ENTRY.published.asc()).limit(max);
if (keepStarredEntries) { return delete(query.fetch());
query.where(Predicates.isNotStarred(ENTRY)); }
}
return delete(query.fetch()); /** Delete the oldest entries of a feed */
} public int deleteOldEntries(Long feedId, long max, boolean keepStarredEntries) {
JPAQuery<FeedEntry> query =
query().selectFrom(ENTRY)
.where(ENTRY.feed.id.eq(feedId))
.orderBy(ENTRY.published.asc())
.limit(max);
public record FeedCapacity(Long id, Long capacity) { if (keepStarredEntries) {
} query.where(Predicates.isNotStarred(ENTRY));
}
return delete(query.fetch());
}
public record FeedCapacity(Long id, Long capacity) {}
} }

View File

@@ -1,16 +1,5 @@
package com.commafeed.backend.dao; package com.commafeed.backend.dao;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import jakarta.inject.Singleton;
import jakarta.persistence.EntityManager;
import org.apache.commons.collections4.CollectionUtils;
import com.commafeed.CommaFeedConfiguration; import com.commafeed.CommaFeedConfiguration;
import com.commafeed.backend.feed.FeedEntryKeyword; import com.commafeed.backend.feed.FeedEntryKeyword;
import com.commafeed.backend.feed.FeedEntryKeyword.Mode; import com.commafeed.backend.feed.FeedEntryKeyword.Mode;
@@ -33,263 +22,318 @@ import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.core.types.dsl.NumberExpression; import com.querydsl.core.types.dsl.NumberExpression;
import com.querydsl.jpa.impl.JPAQuery; import com.querydsl.jpa.impl.JPAQuery;
import jakarta.inject.Singleton;
import jakarta.persistence.EntityManager;
import org.apache.commons.collections4.CollectionUtils;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Singleton @Singleton
public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> { public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
private static final QFeedEntryStatus STATUS = QFeedEntryStatus.feedEntryStatus; private static final QFeedEntryStatus STATUS = QFeedEntryStatus.feedEntryStatus;
private static final QFeedEntry ENTRY = QFeedEntry.feedEntry; private static final QFeedEntry ENTRY = QFeedEntry.feedEntry;
private static final QFeed FEED = QFeed.feed; private static final QFeed FEED = QFeed.feed;
private static final QFeedEntryContent CONTENT = QFeedEntryContent.feedEntryContent; private static final QFeedEntryContent CONTENT = QFeedEntryContent.feedEntryContent;
private static final QFeedEntryTag TAG = QFeedEntryTag.feedEntryTag; private static final QFeedEntryTag TAG = QFeedEntryTag.feedEntryTag;
private static final QFeedSubscription SUBSCRIPTION = QFeedSubscription.feedSubscription; private static final QFeedSubscription SUBSCRIPTION = QFeedSubscription.feedSubscription;
private final FeedEntryTagDAO feedEntryTagDAO; private final FeedEntryTagDAO feedEntryTagDAO;
private final CommaFeedConfiguration config; private final CommaFeedConfiguration config;
public FeedEntryStatusDAO(EntityManager entityManager, FeedEntryTagDAO feedEntryTagDAO, CommaFeedConfiguration config) { public FeedEntryStatusDAO(
super(entityManager, FeedEntryStatus.class); EntityManager entityManager,
this.feedEntryTagDAO = feedEntryTagDAO; FeedEntryTagDAO feedEntryTagDAO,
this.config = config; CommaFeedConfiguration config) {
} super(entityManager, FeedEntryStatus.class);
this.feedEntryTagDAO = feedEntryTagDAO;
this.config = config;
}
public FeedEntryStatus getStatus(User user, FeedSubscription sub, FeedEntry entry) { public FeedEntryStatus getStatus(User user, FeedSubscription sub, FeedEntry entry) {
List<FeedEntryStatus> statuses = query().selectFrom(STATUS).where(STATUS.entry.eq(entry), STATUS.subscription.eq(sub)).fetch(); List<FeedEntryStatus> statuses =
FeedEntryStatus status = statuses.stream().findFirst().orElse(null); query().selectFrom(STATUS)
return handleStatus(user, status, sub, entry); .where(STATUS.entry.eq(entry), STATUS.subscription.eq(sub))
} .fetch();
FeedEntryStatus status = statuses.stream().findFirst().orElse(null);
return handleStatus(user, status, sub, entry);
}
/** /** creates an artificial "unread" status if status is null */
* creates an artificial "unread" status if status is null private FeedEntryStatus handleStatus(
*/ User user, FeedEntryStatus status, FeedSubscription sub, FeedEntry entry) {
private FeedEntryStatus handleStatus(User user, FeedEntryStatus status, FeedSubscription sub, FeedEntry entry) { if (status == null) {
if (status == null) { Instant statusesInstantThreshold =
Instant statusesInstantThreshold = config.database().cleanup().statusesInstantThreshold(); config.database().cleanup().statusesInstantThreshold();
boolean read = statusesInstantThreshold != null && entry.getPublished().isBefore(statusesInstantThreshold); boolean read =
status = new FeedEntryStatus(user, sub, entry); statusesInstantThreshold != null
status.setRead(read); && entry.getPublished().isBefore(statusesInstantThreshold);
status.setMarkable(!read); status = new FeedEntryStatus(user, sub, entry);
} else { status.setRead(read);
status.setMarkable(true); status.setMarkable(!read);
} } else {
return status; status.setMarkable(true);
} }
return status;
}
private void fetchTags(User user, List<FeedEntryStatus> statuses) { private void fetchTags(User user, List<FeedEntryStatus> statuses) {
Map<Long, List<FeedEntryTag>> tagsByEntryIds = feedEntryTagDAO.findByEntries(user, Map<Long, List<FeedEntryTag>> tagsByEntryIds =
statuses.stream().map(FeedEntryStatus::getEntry).toList()); feedEntryTagDAO.findByEntries(
for (FeedEntryStatus status : statuses) { user, statuses.stream().map(FeedEntryStatus::getEntry).toList());
List<FeedEntryTag> tags = tagsByEntryIds.get(status.getEntry().getId()); for (FeedEntryStatus status : statuses) {
status.setTags(tags == null ? List.of() : tags); List<FeedEntryTag> tags = tagsByEntryIds.get(status.getEntry().getId());
} status.setTags(tags == null ? List.of() : tags);
} }
}
public List<FeedEntryStatus> findStarred(User user, Instant newerThan, int offset, int limit, ReadingOrder order, public List<FeedEntryStatus> findStarred(
boolean includeContent) { User user,
JPAQuery<FeedEntryStatus> query = query().selectFrom(STATUS).where(STATUS.user.eq(user), STATUS.starred.isTrue()); List<FeedEntryKeyword> keywords,
if (includeContent) { Instant newerThan,
query.join(STATUS.entry).fetchJoin(); int offset,
query.join(STATUS.entry.content).fetchJoin(); int limit,
} ReadingOrder order,
boolean includeContent) {
JPAQuery<FeedEntryStatus> query =
query().selectFrom(STATUS).where(STATUS.user.eq(user), STATUS.starred.isTrue());
if (includeContent || CollectionUtils.isNotEmpty(keywords)) {
query.join(STATUS.entry).fetchJoin();
query.join(STATUS.entry.content, CONTENT).fetchJoin();
}
if (newerThan != null) { if (CollectionUtils.isNotEmpty(keywords)) {
query.where(STATUS.entryInserted.gt(newerThan)); applyKeywordsFilter(query, keywords);
} }
if (order == ReadingOrder.ASC) { if (newerThan != null) {
query.orderBy(STATUS.entryPublished.asc(), STATUS.id.asc()); query.where(STATUS.entryInserted.gt(newerThan));
} else { }
query.orderBy(STATUS.entryPublished.desc(), STATUS.id.desc());
}
if (offset > -1) { if (order == ReadingOrder.ASC) {
query.offset(offset); query.orderBy(STATUS.entryPublished.asc(), STATUS.id.asc());
} } else {
query.orderBy(STATUS.entryPublished.desc(), STATUS.id.desc());
}
if (limit > -1) { if (offset > -1) {
query.limit(limit); query.offset(offset);
} }
setTimeout(query, config.database().queryTimeout()); if (limit > -1) {
query.limit(limit);
}
List<FeedEntryStatus> statuses = query.fetch(); setTimeout(query, config.database().queryTimeout());
statuses.forEach(s -> s.setMarkable(true));
if (includeContent) {
fetchTags(user, statuses);
}
return statuses; List<FeedEntryStatus> statuses = query.fetch();
} statuses.forEach(s -> s.setMarkable(true));
if (includeContent) {
fetchTags(user, statuses);
}
public List<FeedEntryStatus> findBySubscriptions(User user, List<FeedSubscription> subs, boolean unreadOnly, return statuses;
List<FeedEntryKeyword> keywords, Instant newerThan, int offset, int limit, ReadingOrder order, boolean includeContent, }
String tag, Long minEntryId, Long maxEntryId) {
Map<Long, List<FeedSubscription>> subsByFeedId = subs.stream().collect(Collectors.groupingBy(s -> s.getFeed().getId()));
JPAQuery<Tuple> query = query().select(ENTRY, STATUS).from(ENTRY); public List<FeedEntryStatus> findBySubscriptions(
query.leftJoin(ENTRY.statuses, STATUS).on(STATUS.subscription.in(subs)); User user,
query.where(ENTRY.feed.id.in(subsByFeedId.keySet())); List<FeedSubscription> subs,
boolean unreadOnly,
List<FeedEntryKeyword> keywords,
Instant newerThan,
int offset,
int limit,
ReadingOrder order,
boolean includeContent,
String tag,
Long minEntryId,
Long maxEntryId) {
Map<Long, List<FeedSubscription>> subsByFeedId =
subs.stream().collect(Collectors.groupingBy(s -> s.getFeed().getId()));
if (includeContent || CollectionUtils.isNotEmpty(keywords)) { JPAQuery<Tuple> query = query().select(ENTRY, STATUS).from(ENTRY);
query.join(ENTRY.content, CONTENT).fetchJoin(); query.leftJoin(ENTRY.statuses, STATUS).on(STATUS.subscription.in(subs));
} query.where(ENTRY.feed.id.in(subsByFeedId.keySet()));
if (CollectionUtils.isNotEmpty(keywords)) {
for (FeedEntryKeyword keyword : keywords) {
BooleanBuilder or = new BooleanBuilder();
or.or(CONTENT.content.containsIgnoreCase(keyword.keyword()));
or.or(CONTENT.title.containsIgnoreCase(keyword.keyword()));
if (keyword.mode() == Mode.EXCLUDE) {
or.not();
}
query.where(or);
}
}
if (unreadOnly && tag == null) { if (includeContent || CollectionUtils.isNotEmpty(keywords)) {
query.where(buildUnreadPredicate()); query.join(ENTRY.content, CONTENT).fetchJoin();
} }
if (tag != null) { if (CollectionUtils.isNotEmpty(keywords)) {
BooleanBuilder and = new BooleanBuilder(); applyKeywordsFilter(query, keywords);
and.and(TAG.user.id.eq(user.getId())); }
and.and(TAG.name.eq(tag));
query.join(ENTRY.tags, TAG).on(and);
}
if (newerThan != null) { if (unreadOnly && tag == null) {
query.where(ENTRY.inserted.goe(newerThan)); query.where(buildUnreadPredicate());
} }
if (minEntryId != null) { if (tag != null) {
query.where(ENTRY.id.gt(minEntryId)); BooleanBuilder and = new BooleanBuilder();
} and.and(TAG.user.id.eq(user.getId()));
and.and(TAG.name.eq(tag));
query.join(ENTRY.tags, TAG).on(and);
}
if (maxEntryId != null) { if (newerThan != null) {
query.where(ENTRY.id.lt(maxEntryId)); query.where(ENTRY.inserted.goe(newerThan));
} }
if (order != null) { if (minEntryId != null) {
if (order == ReadingOrder.ASC) { query.where(ENTRY.id.gt(minEntryId));
query.orderBy(ENTRY.published.asc(), ENTRY.id.asc()); }
} else {
query.orderBy(ENTRY.published.desc(), ENTRY.id.desc());
}
}
if (offset > -1) { if (maxEntryId != null) {
query.offset(offset); query.where(ENTRY.id.lt(maxEntryId));
} }
if (limit > -1) { if (order != null) {
query.limit(limit); if (order == ReadingOrder.ASC) {
} query.orderBy(ENTRY.published.asc(), ENTRY.id.asc());
} else {
query.orderBy(ENTRY.published.desc(), ENTRY.id.desc());
}
}
setTimeout(query, config.database().queryTimeout()); if (offset > -1) {
query.offset(offset);
}
List<FeedEntryStatus> statuses = new ArrayList<>(); if (limit > -1) {
List<Tuple> tuples = query.fetch(); query.limit(limit);
for (Tuple tuple : tuples) { }
FeedEntry e = tuple.get(ENTRY);
FeedEntryStatus s = tuple.get(STATUS);
for (FeedSubscription sub : subsByFeedId.get(e.getFeed().getId())) {
statuses.add(handleStatus(user, s, sub, e));
}
}
if (includeContent) { setTimeout(query, config.database().queryTimeout());
fetchTags(user, statuses);
}
return statuses; List<FeedEntryStatus> statuses = new ArrayList<>();
} List<Tuple> tuples = query.fetch();
for (Tuple tuple : tuples) {
FeedEntry e = tuple.get(ENTRY);
FeedEntryStatus s = tuple.get(STATUS);
for (FeedSubscription sub : subsByFeedId.get(e.getFeed().getId())) {
statuses.add(handleStatus(user, s, sub, e));
}
}
public UnreadCount getUnreadCount(FeedSubscription sub) { if (includeContent) {
JPAQuery<Tuple> query = query().select(ENTRY.count(), ENTRY.published.max()) fetchTags(user, statuses);
.from(ENTRY) }
.leftJoin(ENTRY.statuses, STATUS)
.on(STATUS.subscription.eq(sub))
.where(ENTRY.feed.eq(sub.getFeed()))
.where(buildUnreadPredicate());
Tuple tuple = query.fetchOne(); return statuses;
Long count = tuple.get(ENTRY.count()); }
Instant published = tuple.get(ENTRY.published.max());
return new UnreadCount(sub.getId(), count == null ? 0 : count, published);
}
private BooleanBuilder buildUnreadPredicate() { private void applyKeywordsFilter(JPAQuery<?> query, List<FeedEntryKeyword> keywords) {
BooleanBuilder or = new BooleanBuilder(); for (FeedEntryKeyword keyword : keywords) {
or.or(STATUS.read.isNull()); BooleanBuilder or = new BooleanBuilder();
or.or(STATUS.read.isFalse()); or.or(CONTENT.content.containsIgnoreCase(keyword.keyword()));
or.or(CONTENT.title.containsIgnoreCase(keyword.keyword()));
if (keyword.mode() == Mode.EXCLUDE) {
or.not();
}
query.where(or);
}
}
Instant statusesInstantThreshold = config.database().cleanup().statusesInstantThreshold(); public UnreadCount getUnreadCount(FeedSubscription sub) {
if (statusesInstantThreshold != null) { JPAQuery<Tuple> query =
return or.and(ENTRY.published.goe(statusesInstantThreshold)); query().select(ENTRY.count(), ENTRY.published.max())
} else { .from(ENTRY)
return or; .leftJoin(ENTRY.statuses, STATUS)
} .on(STATUS.subscription.eq(sub))
} .where(ENTRY.feed.eq(sub.getFeed()))
.where(buildUnreadPredicate());
public long deleteOldStatuses(Instant olderThan, int limit) { Tuple tuple = query.fetchOne();
List<Long> ids = query().select(STATUS.id) Long count = tuple.get(ENTRY.count());
.from(STATUS) Instant published = tuple.get(ENTRY.published.max());
.where(STATUS.entryInserted.lt(olderThan), STATUS.starred.isFalse()) return new UnreadCount(sub.getId(), count == null ? 0 : count, published);
.limit(limit) }
.fetch();
return deleteQuery(STATUS).where(STATUS.id.in(ids)).execute();
}
public long autoMarkAsRead(int limit) { private BooleanBuilder buildUnreadPredicate() {
Instant now = Instant.now(); BooleanBuilder or = new BooleanBuilder();
or.or(STATUS.read.isNull());
or.or(STATUS.read.isFalse());
BooleanBuilder where = new BooleanBuilder(); Instant statusesInstantThreshold = config.database().cleanup().statusesInstantThreshold();
where.and(SUBSCRIPTION.autoMarkAsReadAfterDays.isNotNull()); if (statusesInstantThreshold != null) {
where.and(SUBSCRIPTION.autoMarkAsReadAfterDays.gt(0)); return or.and(ENTRY.published.goe(statusesInstantThreshold));
} else {
return or;
}
}
NumberExpression<Integer> daysDiff = Expressions.numberTemplate(Integer.class, "TIMESTAMPDIFF(DAY, {0}, {1})", ENTRY.published, public long deleteOldStatuses(Instant olderThan, int limit) {
now); List<Long> ids =
where.and(daysDiff.goe(SUBSCRIPTION.autoMarkAsReadAfterDays)); query().select(STATUS.id)
.from(STATUS)
.where(STATUS.entryInserted.lt(olderThan), STATUS.starred.isFalse())
.limit(limit)
.fetch();
return deleteQuery(STATUS).where(STATUS.id.in(ids)).execute();
}
where.and(buildUnreadPredicate()); public long autoMarkAsRead(int limit) {
Instant now = Instant.now();
List<Tuple> tuples = query().select(ENTRY, STATUS, SUBSCRIPTION) BooleanBuilder where = new BooleanBuilder();
.from(ENTRY) where.and(SUBSCRIPTION.autoMarkAsReadAfterDays.isNotNull());
.join(ENTRY.feed, FEED) where.and(SUBSCRIPTION.autoMarkAsReadAfterDays.gt(0));
.join(SUBSCRIPTION)
.on(SUBSCRIPTION.feed.eq(FEED))
.leftJoin(ENTRY.statuses, STATUS)
.on(STATUS.subscription.eq(SUBSCRIPTION))
.where(where)
.limit(limit)
.fetch();
long updated = 0; NumberExpression<Integer> daysDiff =
Expressions.numberTemplate(
Integer.class, "TIMESTAMPDIFF(DAY, {0}, {1})", ENTRY.published, now);
where.and(daysDiff.goe(SUBSCRIPTION.autoMarkAsReadAfterDays));
// Update existing statuses where.and(buildUnreadPredicate());
List<Long> statusIdsToUpdate = tuples.stream()
.map(t -> t.get(STATUS))
.filter(s -> s != null && s.getId() != null)
.map(FeedEntryStatus::getId)
.distinct()
.toList();
if (!statusIdsToUpdate.isEmpty()) { List<Tuple> tuples =
updated += updateQuery(STATUS).where(STATUS.id.in(statusIdsToUpdate)).set(STATUS.read, true).execute(); query().select(ENTRY, STATUS, SUBSCRIPTION)
} .from(ENTRY)
.join(ENTRY.feed, FEED)
.join(SUBSCRIPTION)
.on(SUBSCRIPTION.feed.eq(FEED))
.leftJoin(ENTRY.statuses, STATUS)
.on(STATUS.subscription.eq(SUBSCRIPTION))
.where(where)
.limit(limit)
.fetch();
// Insert new statuses for entries without existing status long updated = 0;
for (Tuple tuple : tuples) {
FeedEntryStatus status = tuple.get(STATUS);
if (status == null || status.getId() == null) {
FeedEntry entry = tuple.get(ENTRY);
FeedSubscription sub = tuple.get(SUBSCRIPTION);
FeedEntryStatus newStatus = new FeedEntryStatus(sub.getUser(), sub, entry);
newStatus.setRead(true);
persist(newStatus);
updated++;
}
}
return updated; // Update existing statuses
} List<Long> statusIdsToUpdate =
tuples.stream()
.map(t -> t.get(STATUS))
.filter(s -> s != null && s.getId() != null)
.map(FeedEntryStatus::getId)
.distinct()
.toList();
if (!statusIdsToUpdate.isEmpty()) {
updated +=
updateQuery(STATUS)
.where(STATUS.id.in(statusIdsToUpdate))
.set(STATUS.read, true)
.execute();
}
// Insert new statuses for entries without existing status
for (Tuple tuple : tuples) {
FeedEntryStatus status = tuple.get(STATUS);
if (status == null || status.getId() == null) {
FeedEntry entry = tuple.get(ENTRY);
FeedSubscription sub = tuple.get(SUBSCRIPTION);
FeedEntryStatus newStatus = new FeedEntryStatus(sub.getUser(), sub, entry);
newStatus.setRead(true);
persist(newStatus);
updated++;
}
}
return updated;
}
} }

View File

@@ -1,39 +1,40 @@
package com.commafeed.backend.dao; package com.commafeed.backend.dao;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import jakarta.inject.Singleton;
import jakarta.persistence.EntityManager;
import com.commafeed.backend.model.FeedEntry; import com.commafeed.backend.model.FeedEntry;
import com.commafeed.backend.model.FeedEntryTag; import com.commafeed.backend.model.FeedEntryTag;
import com.commafeed.backend.model.QFeedEntryTag; import com.commafeed.backend.model.QFeedEntryTag;
import com.commafeed.backend.model.User; import com.commafeed.backend.model.User;
import jakarta.inject.Singleton;
import jakarta.persistence.EntityManager;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Singleton @Singleton
public class FeedEntryTagDAO extends GenericDAO<FeedEntryTag> { public class FeedEntryTagDAO extends GenericDAO<FeedEntryTag> {
private static final QFeedEntryTag TAG = QFeedEntryTag.feedEntryTag; private static final QFeedEntryTag TAG = QFeedEntryTag.feedEntryTag;
public FeedEntryTagDAO(EntityManager entityManager) { public FeedEntryTagDAO(EntityManager entityManager) {
super(entityManager, FeedEntryTag.class); super(entityManager, FeedEntryTag.class);
} }
public List<String> findByUser(User user) { public List<String> findByUser(User user) {
return query().selectDistinct(TAG.name).from(TAG).where(TAG.user.eq(user)).fetch(); return query().selectDistinct(TAG.name).from(TAG).where(TAG.user.eq(user)).fetch();
} }
public List<FeedEntryTag> findByEntry(User user, FeedEntry entry) { public List<FeedEntryTag> findByEntry(User user, FeedEntry entry) {
return query().selectFrom(TAG).where(TAG.user.eq(user), TAG.entry.eq(entry)).fetch(); return query().selectFrom(TAG).where(TAG.user.eq(user), TAG.entry.eq(entry)).fetch();
} }
public Map<Long, List<FeedEntryTag>> findByEntries(User user, List<FeedEntry> entries) { public Map<Long, List<FeedEntryTag>> findByEntries(User user, List<FeedEntry> entries) {
return query().selectFrom(TAG) return query()
.where(TAG.user.eq(user), TAG.entry.in(entries)) .selectFrom(TAG)
.fetch() .where(TAG.user.eq(user), TAG.entry.in(entries))
.stream() .fetch()
.collect(Collectors.groupingBy(t -> t.getEntry().getId())); .stream()
} .collect(Collectors.groupingBy(t -> t.getEntry().getId()));
}
} }

View File

@@ -1,9 +1,13 @@
package com.commafeed.backend.dao; package com.commafeed.backend.dao;
import java.util.List; import com.commafeed.backend.model.AbstractModel;
import java.util.Set; import com.commafeed.backend.model.Feed;
import java.util.function.Consumer; import com.commafeed.backend.model.FeedCategory;
import java.util.stream.Collectors; import com.commafeed.backend.model.FeedSubscription;
import com.commafeed.backend.model.Models;
import com.commafeed.backend.model.QFeedSubscription;
import com.commafeed.backend.model.User;
import com.querydsl.jpa.JPQLQuery;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
import jakarta.persistence.EntityManager; import jakarta.persistence.EntityManager;
@@ -15,117 +19,128 @@ import org.hibernate.event.spi.PostCommitInsertEventListener;
import org.hibernate.event.spi.PostInsertEvent; import org.hibernate.event.spi.PostInsertEvent;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import com.commafeed.backend.model.AbstractModel; import java.util.List;
import com.commafeed.backend.model.Feed; import java.util.Set;
import com.commafeed.backend.model.FeedCategory; import java.util.function.Consumer;
import com.commafeed.backend.model.FeedSubscription; import java.util.stream.Collectors;
import com.commafeed.backend.model.Models;
import com.commafeed.backend.model.QFeedSubscription;
import com.commafeed.backend.model.User;
import com.querydsl.jpa.JPQLQuery;
@Singleton @Singleton
public class FeedSubscriptionDAO extends GenericDAO<FeedSubscription> { public class FeedSubscriptionDAO extends GenericDAO<FeedSubscription> {
private static final QFeedSubscription SUBSCRIPTION = QFeedSubscription.feedSubscription; private static final QFeedSubscription SUBSCRIPTION = QFeedSubscription.feedSubscription;
private final EntityManager entityManager; private final EntityManager entityManager;
public FeedSubscriptionDAO(EntityManager entityManager) { public FeedSubscriptionDAO(EntityManager entityManager) {
super(entityManager, FeedSubscription.class); super(entityManager, FeedSubscription.class);
this.entityManager = entityManager; this.entityManager = entityManager;
} }
public void onPostCommitInsert(Consumer<FeedSubscription> consumer) { public void onPostCommitInsert(Consumer<FeedSubscription> consumer) {
entityManager.unwrap(SharedSessionContractImplementor.class) entityManager
.getFactory() .unwrap(SharedSessionContractImplementor.class)
.getServiceRegistry() .getFactory()
.getService(EventListenerRegistry.class) .getServiceRegistry()
.getEventListenerGroup(EventType.POST_COMMIT_INSERT) .getService(EventListenerRegistry.class)
.appendListener(new PostCommitInsertEventListener() { .getEventListenerGroup(EventType.POST_COMMIT_INSERT)
@Override .appendListener(
public void onPostInsert(PostInsertEvent event) { new PostCommitInsertEventListener() {
if (event.getEntity() instanceof FeedSubscription s) { @Override
consumer.accept(s); public void onPostInsert(PostInsertEvent event) {
} if (event.getEntity() instanceof FeedSubscription s) {
} consumer.accept(s);
}
}
@Override @Override
public boolean requiresPostCommitHandling(EntityPersister persister) { public boolean requiresPostCommitHandling(EntityPersister persister) {
return true; return true;
} }
@Override @Override
public void onPostInsertCommitFailed(PostInsertEvent event) { public void onPostInsertCommitFailed(PostInsertEvent event) {
// do nothing // do nothing
} }
}); });
} }
public FeedSubscription findById(User user, Long id) { public FeedSubscription findById(User user, Long id) {
List<FeedSubscription> subs = query().selectFrom(SUBSCRIPTION) List<FeedSubscription> subs =
.where(SUBSCRIPTION.user.eq(user), SUBSCRIPTION.id.eq(id)) query().selectFrom(SUBSCRIPTION)
.leftJoin(SUBSCRIPTION.feed) .where(SUBSCRIPTION.user.eq(user), SUBSCRIPTION.id.eq(id))
.fetchJoin() .leftJoin(SUBSCRIPTION.feed)
.leftJoin(SUBSCRIPTION.category) .fetchJoin()
.fetchJoin() .leftJoin(SUBSCRIPTION.category)
.fetch(); .fetchJoin()
FeedSubscription sub = subs.stream().findFirst().orElse(null); .fetch();
return initRelations(sub); FeedSubscription sub = subs.stream().findFirst().orElse(null);
} return initRelations(sub);
}
public List<FeedSubscription> findByFeed(Feed feed) { public List<FeedSubscription> findByFeed(Feed feed) {
return query().selectFrom(SUBSCRIPTION).where(SUBSCRIPTION.feed.eq(feed)).fetch(); return query().selectFrom(SUBSCRIPTION).where(SUBSCRIPTION.feed.eq(feed)).fetch();
} }
public FeedSubscription findByFeed(User user, Feed feed) { public FeedSubscription findByFeed(User user, Feed feed) {
List<FeedSubscription> subs = query().selectFrom(SUBSCRIPTION) List<FeedSubscription> subs =
.where(SUBSCRIPTION.user.eq(user), SUBSCRIPTION.feed.eq(feed)) query().selectFrom(SUBSCRIPTION)
.fetch(); .where(SUBSCRIPTION.user.eq(user), SUBSCRIPTION.feed.eq(feed))
FeedSubscription sub = subs.stream().findFirst().orElse(null); .fetch();
return initRelations(sub); FeedSubscription sub = subs.stream().findFirst().orElse(null);
} return initRelations(sub);
}
public List<FeedSubscription> findAll(User user) { public List<FeedSubscription> findAll(User user) {
List<FeedSubscription> subs = query().selectFrom(SUBSCRIPTION) List<FeedSubscription> subs =
.where(SUBSCRIPTION.user.eq(user)) query().selectFrom(SUBSCRIPTION)
.leftJoin(SUBSCRIPTION.feed) .where(SUBSCRIPTION.user.eq(user))
.fetchJoin() .leftJoin(SUBSCRIPTION.feed)
.leftJoin(SUBSCRIPTION.category) .fetchJoin()
.fetchJoin() .leftJoin(SUBSCRIPTION.category)
.fetch(); .fetchJoin()
return initRelations(subs); .fetch();
} return initRelations(subs);
}
public Long count(User user) { public Long count(User user) {
return query().select(SUBSCRIPTION.count()).from(SUBSCRIPTION).where(SUBSCRIPTION.user.eq(user)).fetchOne(); return query().select(SUBSCRIPTION.count())
} .from(SUBSCRIPTION)
.where(SUBSCRIPTION.user.eq(user))
.fetchOne();
}
public List<FeedSubscription> findByCategory(User user, FeedCategory category) { public List<FeedSubscription> findByCategory(User user, FeedCategory category) {
JPQLQuery<FeedSubscription> query = query().selectFrom(SUBSCRIPTION).where(SUBSCRIPTION.user.eq(user)); JPQLQuery<FeedSubscription> query =
if (category == null) { query().selectFrom(SUBSCRIPTION).where(SUBSCRIPTION.user.eq(user));
query.where(SUBSCRIPTION.category.isNull()); if (category == null) {
} else { query.where(SUBSCRIPTION.category.isNull());
query.where(SUBSCRIPTION.category.eq(category)); } else {
} query.where(SUBSCRIPTION.category.eq(category));
return initRelations(query.fetch()); }
} return initRelations(query.fetch());
}
public List<FeedSubscription> findByCategories(User user, List<FeedCategory> categories) { public List<FeedSubscription> findByCategories(User user, List<FeedCategory> categories) {
Set<Long> categoryIds = categories.stream().map(AbstractModel::getId).collect(Collectors.toSet()); Set<Long> categoryIds =
return findAll(user).stream().filter(s -> s.getCategory() != null && categoryIds.contains(s.getCategory().getId())).toList(); categories.stream().map(AbstractModel::getId).collect(Collectors.toSet());
} return findAll(user).stream()
.filter(
s ->
s.getCategory() != null
&& categoryIds.contains(s.getCategory().getId()))
.toList();
}
private List<FeedSubscription> initRelations(List<FeedSubscription> list) { private List<FeedSubscription> initRelations(List<FeedSubscription> list) {
list.forEach(this::initRelations); list.forEach(this::initRelations);
return list; return list;
} }
private FeedSubscription initRelations(FeedSubscription sub) { private FeedSubscription initRelations(FeedSubscription sub) {
if (sub != null) { if (sub != null) {
Models.initialize(sub.getFeed()); Models.initialize(sub.getFeed());
Models.initialize(sub.getCategory()); Models.initialize(sub.getCategory());
} }
return sub; return sub;
} }
} }

View File

@@ -1,12 +1,5 @@
package com.commafeed.backend.dao; package com.commafeed.backend.dao;
import java.time.Duration;
import java.util.Collection;
import jakarta.persistence.EntityManager;
import org.hibernate.jpa.SpecHints;
import com.commafeed.backend.model.AbstractModel; import com.commafeed.backend.model.AbstractModel;
import com.querydsl.core.types.EntityPath; import com.querydsl.core.types.EntityPath;
import com.querydsl.jpa.impl.JPADeleteClause; import com.querydsl.jpa.impl.JPADeleteClause;
@@ -14,53 +7,59 @@ import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory; import com.querydsl.jpa.impl.JPAQueryFactory;
import com.querydsl.jpa.impl.JPAUpdateClause; import com.querydsl.jpa.impl.JPAUpdateClause;
import jakarta.persistence.EntityManager;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.hibernate.jpa.SpecHints;
import java.time.Duration;
import java.util.Collection;
@RequiredArgsConstructor @RequiredArgsConstructor
public abstract class GenericDAO<T extends AbstractModel> { public abstract class GenericDAO<T extends AbstractModel> {
private final EntityManager entityManager; private final EntityManager entityManager;
private final Class<T> entityClass; private final Class<T> entityClass;
protected JPAQueryFactory query() { protected JPAQueryFactory query() {
return new JPAQueryFactory(entityManager); return new JPAQueryFactory(entityManager);
} }
protected JPAUpdateClause updateQuery(EntityPath<T> entityPath) { protected JPAUpdateClause updateQuery(EntityPath<T> entityPath) {
return new JPAUpdateClause(entityManager, entityPath); return new JPAUpdateClause(entityManager, entityPath);
} }
protected JPADeleteClause deleteQuery(EntityPath<T> entityPath) { protected JPADeleteClause deleteQuery(EntityPath<T> entityPath) {
return new JPADeleteClause(entityManager, entityPath); return new JPADeleteClause(entityManager, entityPath);
} }
public void persist(T model) { public void persist(T model) {
entityManager.persist(model); entityManager.persist(model);
} }
public T merge(T model) { public T merge(T model) {
return entityManager.merge(model); return entityManager.merge(model);
} }
public T findById(Long id) { public T findById(Long id) {
return entityManager.find(entityClass, id); return entityManager.find(entityClass, id);
} }
public void delete(T object) { public void delete(T object) {
if (object != null) { if (object != null) {
entityManager.remove(object); entityManager.remove(object);
} }
} }
public int delete(Collection<T> objects) { public int delete(Collection<T> objects) {
objects.forEach(this::delete); objects.forEach(this::delete);
return objects.size(); return objects.size();
} }
protected void setTimeout(JPAQuery<?> query, Duration timeout) {
if (!timeout.isZero()) {
query.setHint(SpecHints.HINT_SPEC_QUERY_TIMEOUT, Math.toIntExact(timeout.toMillis()));
}
}
protected void setTimeout(JPAQuery<?> query, Duration timeout) {
if (!timeout.isZero()) {
query.setHint(SpecHints.HINT_SPEC_QUERY_TIMEOUT, Math.toIntExact(timeout.toMillis()));
}
}
} }

View File

@@ -10,9 +10,12 @@ import lombok.experimental.UtilityClass;
@UtilityClass @UtilityClass
public class Predicates { public class Predicates {
private static final QFeedEntryStatus STATUS = QFeedEntryStatus.feedEntryStatus; private static final QFeedEntryStatus STATUS = QFeedEntryStatus.feedEntryStatus;
public static BooleanExpression isNotStarred(QFeedEntry entry) { public static BooleanExpression isNotStarred(QFeedEntry entry) {
return JPAExpressions.selectOne().from(STATUS).where(STATUS.entry.eq(entry).and(STATUS.starred.isTrue())).notExists(); return JPAExpressions.selectOne()
} .from(STATUS)
.where(STATUS.entry.eq(entry).and(STATUS.starred.isTrue()))
.notExists();
}
} }

View File

@@ -1,19 +1,19 @@
package com.commafeed.backend.dao; package com.commafeed.backend.dao;
import java.util.concurrent.Callable; import io.quarkus.narayana.jta.QuarkusTransaction;
import jakarta.inject.Singleton; import jakarta.inject.Singleton;
import io.quarkus.narayana.jta.QuarkusTransaction; import java.util.concurrent.Callable;
@Singleton @Singleton
public class UnitOfWork { public class UnitOfWork {
public void run(Runnable runnable) { public void run(Runnable runnable) {
QuarkusTransaction.joiningExisting().run(runnable); QuarkusTransaction.joiningExisting().run(runnable);
} }
public <T> T call(Callable<T> callable) { public <T> T call(Callable<T> callable) {
return QuarkusTransaction.joiningExisting().call(callable); return QuarkusTransaction.joiningExisting().call(callable);
} }
} }

View File

@@ -1,33 +1,33 @@
package com.commafeed.backend.dao; package com.commafeed.backend.dao;
import jakarta.inject.Singleton;
import jakarta.persistence.EntityManager;
import com.commafeed.backend.model.QUser; import com.commafeed.backend.model.QUser;
import com.commafeed.backend.model.User; import com.commafeed.backend.model.User;
import jakarta.inject.Singleton;
import jakarta.persistence.EntityManager;
@Singleton @Singleton
public class UserDAO extends GenericDAO<User> { public class UserDAO extends GenericDAO<User> {
private static final QUser USER = QUser.user; private static final QUser USER = QUser.user;
public UserDAO(EntityManager entityManager) { public UserDAO(EntityManager entityManager) {
super(entityManager, User.class); super(entityManager, User.class);
} }
public User findByName(String name) { public User findByName(String name) {
return query().selectFrom(USER).where(USER.name.equalsIgnoreCase(name)).fetchOne(); return query().selectFrom(USER).where(USER.name.equalsIgnoreCase(name)).fetchOne();
} }
public User findByApiKey(String key) { public User findByApiKey(String key) {
return query().selectFrom(USER).where(USER.apiKey.equalsIgnoreCase(key)).fetchOne(); return query().selectFrom(USER).where(USER.apiKey.equalsIgnoreCase(key)).fetchOne();
} }
public User findByEmail(String email) { public User findByEmail(String email) {
return query().selectFrom(USER).where(USER.email.equalsIgnoreCase(email)).fetchOne(); return query().selectFrom(USER).where(USER.email.equalsIgnoreCase(email)).fetchOne();
} }
public long count() { public long count() {
return query().select(USER.count()).from(USER).fetchOne(); return query().select(USER.count()).from(USER).fetchOne();
} }
} }

View File

@@ -1,39 +1,39 @@
package com.commafeed.backend.dao; package com.commafeed.backend.dao;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import jakarta.inject.Singleton;
import jakarta.persistence.EntityManager;
import com.commafeed.backend.model.QUserRole; import com.commafeed.backend.model.QUserRole;
import com.commafeed.backend.model.User; import com.commafeed.backend.model.User;
import com.commafeed.backend.model.UserRole; import com.commafeed.backend.model.UserRole;
import com.commafeed.backend.model.UserRole.Role; import com.commafeed.backend.model.UserRole.Role;
import jakarta.inject.Singleton;
import jakarta.persistence.EntityManager;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@Singleton @Singleton
public class UserRoleDAO extends GenericDAO<UserRole> { public class UserRoleDAO extends GenericDAO<UserRole> {
private static final QUserRole ROLE = QUserRole.userRole; private static final QUserRole ROLE = QUserRole.userRole;
public UserRoleDAO(EntityManager entityManager) { public UserRoleDAO(EntityManager entityManager) {
super(entityManager, UserRole.class); super(entityManager, UserRole.class);
} }
public List<UserRole> findAll() { public List<UserRole> findAll() {
return query().selectFrom(ROLE).leftJoin(ROLE.user).fetchJoin().distinct().fetch(); return query().selectFrom(ROLE).leftJoin(ROLE.user).fetchJoin().distinct().fetch();
} }
public List<UserRole> findAll(User user) { public List<UserRole> findAll(User user) {
return query().selectFrom(ROLE).where(ROLE.user.eq(user)).distinct().fetch(); return query().selectFrom(ROLE).where(ROLE.user.eq(user)).distinct().fetch();
} }
public Set<Role> findRoles(User user) { public Set<Role> findRoles(User user) {
return findAll(user).stream().map(UserRole::getRole).collect(Collectors.toSet()); return findAll(user).stream().map(UserRole::getRole).collect(Collectors.toSet());
} }
public long countAdmins() { public long countAdmins() {
return query().select(ROLE.count()).from(ROLE).where(ROLE.role.eq(Role.ADMIN)).fetchOne(); return query().select(ROLE.count()).from(ROLE).where(ROLE.role.eq(Role.ADMIN)).fetchOne();
} }
} }

View File

@@ -1,22 +1,22 @@
package com.commafeed.backend.dao; package com.commafeed.backend.dao;
import jakarta.inject.Singleton;
import jakarta.persistence.EntityManager;
import com.commafeed.backend.model.QUserSettings; import com.commafeed.backend.model.QUserSettings;
import com.commafeed.backend.model.User; import com.commafeed.backend.model.User;
import com.commafeed.backend.model.UserSettings; import com.commafeed.backend.model.UserSettings;
import jakarta.inject.Singleton;
import jakarta.persistence.EntityManager;
@Singleton @Singleton
public class UserSettingsDAO extends GenericDAO<UserSettings> { public class UserSettingsDAO extends GenericDAO<UserSettings> {
private static final QUserSettings SETTINGS = QUserSettings.userSettings; private static final QUserSettings SETTINGS = QUserSettings.userSettings;
public UserSettingsDAO(EntityManager entityManager) { public UserSettingsDAO(EntityManager entityManager) {
super(entityManager, UserSettings.class); super(entityManager, UserSettings.class);
} }
public UserSettings findByUser(User user) { public UserSettings findByUser(User user) {
return query().selectFrom(SETTINGS).where(SETTINGS.user.eq(user)).fetchFirst(); return query().selectFrom(SETTINGS).where(SETTINGS.user.eq(user)).fetchFirst();
} }
} }

View File

@@ -1,49 +0,0 @@
package com.commafeed.backend.favicon;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import com.commafeed.backend.model.Feed;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public abstract class AbstractFaviconFetcher {
private static final List<String> ICON_MIMETYPE_BLACKLIST = Arrays.asList("application/xml", "text/html");
private static final long MIN_ICON_LENGTH = 100;
private static final long MAX_ICON_LENGTH = 100000;
public abstract Favicon fetch(Feed feed);
protected boolean isValidIconResponse(byte[] content, String contentType) {
if (content == null) {
return false;
}
long length = content.length;
if (StringUtils.isNotBlank(contentType)) {
contentType = contentType.split(";")[0];
}
if (ICON_MIMETYPE_BLACKLIST.contains(contentType)) {
log.debug("Content-Type {} is blacklisted", contentType);
return false;
}
if (length < MIN_ICON_LENGTH) {
log.debug("Length {} below MIN_ICON_LENGTH {}", length, MIN_ICON_LENGTH);
return false;
}
if (length > MAX_ICON_LENGTH) {
log.debug("Length {} greater than MAX_ICON_LENGTH {}", length, MAX_ICON_LENGTH);
return false;
}
return true;
}
}

View File

@@ -1,130 +0,0 @@
package com.commafeed.backend.favicon;
import jakarta.annotation.Priority;
import jakarta.inject.Singleton;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import com.commafeed.backend.HttpGetter;
import com.commafeed.backend.HttpGetter.HttpResult;
import com.commafeed.backend.Urls;
import com.commafeed.backend.model.Feed;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
/**
* Inspired/Ported from https://github.com/potatolondon/getfavicon
*
*/
@Slf4j
@RequiredArgsConstructor
@Singleton
@Priority(Integer.MIN_VALUE)
public class DefaultFaviconFetcher extends AbstractFaviconFetcher {
private final HttpGetter getter;
@Override
public Favicon fetch(Feed feed) {
Favicon icon = fetch(feed.getLink());
if (icon == null) {
icon = fetch(feed.getUrl());
}
return icon;
}
private Favicon fetch(String url) {
if (url == null) {
log.debug("url is null");
return null;
}
int doubleSlash = url.indexOf("//");
if (doubleSlash == -1) {
doubleSlash = 0;
} else {
doubleSlash += 2;
}
int firstSlash = url.indexOf('/', doubleSlash);
if (firstSlash != -1) {
url = url.substring(0, firstSlash);
}
Favicon icon = getIconAtRoot(url);
if (icon == null) {
icon = getIconInPage(url);
}
return icon;
}
private Favicon getIconAtRoot(String url) {
byte[] bytes = null;
String contentType = null;
try {
url = Urls.removeTrailingSlash(url) + "/favicon.ico";
log.debug("getting root icon at {}", url);
HttpResult result = getter.get(url);
bytes = result.content();
contentType = result.contentType();
} catch (Exception e) {
log.debug("Failed to retrieve iconAtRoot for url {}: ", url, e);
}
if (!isValidIconResponse(bytes, contentType)) {
return null;
}
return new Favicon(bytes, contentType);
}
private Favicon getIconInPage(String url) {
Document doc;
try {
HttpResult result = getter.get(url);
doc = Jsoup.parse(new String(result.content()), url);
} catch (Exception e) {
log.debug("Failed to retrieve page to find icon", e);
return null;
}
Elements icons = doc.select("link[rel~=(?i)^(shortcut|icon|shortcut icon)$]");
if (icons.isEmpty()) {
log.debug("No icon found in page {}", url);
return null;
}
String href = icons.getFirst().attr("abs:href");
if (StringUtils.isBlank(href)) {
log.debug("No icon found in page");
return null;
}
log.debug("Found unconfirmed iconInPage at {}", href);
byte[] bytes;
String contentType;
try {
HttpResult result = getter.get(href);
bytes = result.content();
contentType = result.contentType();
} catch (Exception e) {
log.debug("Failed to retrieve icon found in page {}", href, e);
return null;
}
if (!isValidIconResponse(bytes, contentType)) {
log.debug("Invalid icon found for {}", href);
return null;
}
return new Favicon(bytes, contentType);
}
}

View File

@@ -1,73 +1,71 @@
package com.commafeed.backend.favicon; package com.commafeed.backend.favicon;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import jakarta.inject.Singleton;
import org.apache.hc.core5.http.NameValuePair;
import org.apache.hc.core5.net.URIBuilder;
import com.commafeed.backend.HttpGetter; import com.commafeed.backend.HttpGetter;
import com.commafeed.backend.HttpGetter.HttpResult; import com.commafeed.backend.HttpGetter.HttpResult;
import com.commafeed.backend.model.Feed; import com.commafeed.backend.model.Feed;
import jakarta.annotation.Priority;
import jakarta.inject.Singleton;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.hc.core5.http.NameValuePair;
import org.apache.hc.core5.net.URIBuilder;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
@Slf4j @Slf4j
@RequiredArgsConstructor @RequiredArgsConstructor
@Singleton @Singleton
public class FacebookFaviconFetcher extends AbstractFaviconFetcher { @Priority(3)
public class FacebookFaviconFetcher implements FaviconFetcher {
private final HttpGetter getter; private final HttpGetter getter;
@Override @Override
public Favicon fetch(Feed feed) { public Favicon fetch(Feed feed) {
String url = feed.getUrl(); String url = feed.getUrl();
if (!url.toLowerCase().contains("www.facebook.com")) {
return null;
}
if (!url.toLowerCase().contains("www.facebook.com")) { String userName = extractUserName(url);
return null; if (userName == null) {
} return null;
}
String userName = extractUserName(url); String iconUrl =
if (userName == null) { String.format(
return null; "https://graph.facebook.com/%s/picture?type=square&height=16", userName);
}
String iconUrl = String.format("https://graph.facebook.com/%s/picture?type=square&height=16", userName); try {
log.debug("Getting Facebook user's icon, {}", url);
byte[] bytes = null; HttpResult iconResult = getter.get(iconUrl);
String contentType = null; return new Favicon(iconResult.content(), iconResult.contentType());
} catch (Exception e) {
log.debug("Failed to retrieve Facebook icon", e);
return null;
}
}
try { private String extractUserName(String url) {
log.debug("Getting Facebook user's icon, {}", url); URI uri;
try {
HttpResult iconResult = getter.get(iconUrl); uri = new URI(url);
bytes = iconResult.content(); } catch (URISyntaxException e) {
contentType = iconResult.contentType(); log.debug("could not parse url", e);
} catch (Exception e) { return null;
log.debug("Failed to retrieve Facebook icon", e); }
}
if (!isValidIconResponse(bytes, contentType)) {
return null;
}
return new Favicon(bytes, contentType);
}
private String extractUserName(String url) {
URI uri;
try {
uri = new URI(url);
} catch (URISyntaxException e) {
log.debug("could not parse url", e);
return null;
}
List<NameValuePair> params = new URIBuilder(uri).getQueryParams();
return params.stream().filter(p -> "id".equals(p.getName())).map(NameValuePair::getValue).findFirst().orElse(null);
}
List<NameValuePair> params = new URIBuilder(uri).getQueryParams();
return params.stream()
.filter(p -> "id".equals(p.getName()))
.map(NameValuePair::getValue)
.findFirst()
.orElse(null);
}
} }

View File

@@ -7,18 +7,19 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
public record Favicon(byte[] icon, MediaType mediaType) { public record Favicon(byte[] icon, MediaType mediaType) {
private static final MediaType DEFAULT_MEDIA_TYPE = MediaType.valueOf("image/x-icon"); private static final MediaType DEFAULT_MEDIA_TYPE = MediaType.valueOf("image/x-icon");
public Favicon(byte[] icon, String contentType) { public Favicon(byte[] icon, String contentType) {
this(icon, parseMediaType(contentType)); this(icon, parseMediaType(contentType));
} }
private static MediaType parseMediaType(String contentType) { private static MediaType parseMediaType(String contentType) {
try { try {
return MediaType.valueOf(contentType); return MediaType.valueOf(contentType);
} catch (Exception e) { } catch (Exception e) {
log.debug("invalid content type '{}' received, returning default value", contentType, e); log.debug(
return DEFAULT_MEDIA_TYPE; "invalid content type '{}' received, returning default value", contentType, e);
} return DEFAULT_MEDIA_TYPE;
} }
} }
}

View File

@@ -0,0 +1,8 @@
package com.commafeed.backend.favicon;
import com.commafeed.backend.model.Feed;
public interface FaviconFetcher {
Favicon fetch(Feed feed);
}

View File

@@ -0,0 +1,37 @@
package com.commafeed.backend.favicon;
import com.commafeed.backend.HttpGetter;
import com.commafeed.backend.HttpGetter.HttpResult;
import com.commafeed.backend.model.Feed;
import jakarta.annotation.Priority;
import jakarta.inject.Singleton;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
/** Fetch favicon from the url declared in the feed. */
@Slf4j
@RequiredArgsConstructor
@Singleton
@Priority(2)
public class FeedFaviconFetcher implements FaviconFetcher {
private final HttpGetter getter;
@Override
public Favicon fetch(Feed feed) {
String url = feed.getIconUrl();
if (url == null) {
return null;
}
try {
HttpResult result = getter.get(url);
return new Favicon(result.content(), result.contentType());
} catch (Exception e) {
log.debug("Failed to retrieve icon declared in the feed {}", url, e);
return null;
}
}
}

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