mirror of
https://github.com/Athou/commafeed.git
synced 2026-03-21 21:37:29 +00:00
Compare commits
236 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
141a863079 | ||
|
|
6fa8d4be34 | ||
|
|
984e8a44d5 | ||
|
|
bdb296bce2 | ||
|
|
955a9084c3 | ||
|
|
70f486b0eb | ||
|
|
0bc383c6a8 | ||
|
|
0bb2b36585 | ||
|
|
9e3a24753a | ||
|
|
f2c400799e | ||
|
|
25a8c8a7e3 | ||
|
|
8f95d89fc6 | ||
|
|
39b0cdb9d5 | ||
|
|
42e06b848e | ||
|
|
7c3a13b1c4 | ||
|
|
151248fce2 | ||
|
|
6e8d6fe063 | ||
|
|
ca2da5e631 | ||
|
|
6cd3b70201 | ||
|
|
2dcfba75b5 | ||
|
|
44a51b03d3 | ||
|
|
6ee9e9831e | ||
|
|
68c717cee8 | ||
|
|
b15fc02c34 | ||
|
|
033ebfb497 | ||
|
|
4cceaa7650 | ||
|
|
5df47f1396 | ||
|
|
903f35c01b | ||
|
|
6a34f94277 | ||
|
|
dcc143eb7d | ||
|
|
fb47bf27e8 | ||
|
|
dcf969ff2e | ||
|
|
32c1318355 | ||
|
|
8ca6b89da4 | ||
|
|
b46c3a15f3 | ||
|
|
cbc5e014f7 | ||
|
|
8925b248e4 | ||
|
|
cc6aa2bbc5 | ||
|
|
1989aaf8b4 | ||
|
|
c90c91b748 | ||
|
|
bca23db213 | ||
|
|
c9a92d2043 | ||
|
|
c48e06fa46 | ||
|
|
5529eced91 | ||
|
|
2a0d935471 | ||
|
|
6c68fda572 | ||
|
|
861c1fc3dc | ||
|
|
5971bb4255 | ||
|
|
76ba360631 | ||
|
|
89d3ff3c90 | ||
|
|
34024a913d | ||
|
|
a858380121 | ||
|
|
e1dc870005 | ||
|
|
2fc1cac869 | ||
|
|
f627ff4958 | ||
|
|
5ff8e51948 | ||
|
|
538f25c6bb | ||
|
|
65100ba279 | ||
|
|
79fd470bbf | ||
|
|
866d74665b | ||
|
|
29da74f038 | ||
|
|
3c8ac35a46 | ||
|
|
afe957ba59 | ||
|
|
7e50e99351 | ||
|
|
62ce462cc8 | ||
|
|
108cb06f43 | ||
|
|
95a38675bc | ||
|
|
714681bc50 | ||
|
|
0f8d91d997 | ||
|
|
562297a82f | ||
|
|
b108bf06e5 | ||
|
|
3c819066fd | ||
|
|
5f30cb7e2e | ||
|
|
5a95b95801 | ||
|
|
eb573fdc8b | ||
|
|
238ea54e98 | ||
|
|
e4dfc47fb8 | ||
|
|
a1491c779a | ||
|
|
dabd7552be | ||
|
|
0a4c56af1f | ||
|
|
c3dae5b92c | ||
|
|
2c3105b526 | ||
|
|
20f5081ac8 | ||
|
|
3091eb9d14 | ||
|
|
5bdda42239 | ||
|
|
7eda8b7662 | ||
|
|
fc94ce5d2b | ||
|
|
e5d7161ab7 | ||
|
|
f725cb7fa4 | ||
|
|
830e689fe8 | ||
|
|
2832e8c638 | ||
|
|
d711cbab49 | ||
|
|
2e8fd737af | ||
|
|
a080ede15b | ||
|
|
ab3d41508f | ||
|
|
1ab4a5e925 | ||
|
|
543ce08be6 | ||
|
|
21829056ba | ||
|
|
1af59c87d0 | ||
|
|
799e6c082c | ||
|
|
09635cf0fd | ||
|
|
1dfbd30471 | ||
|
|
48e0a77d1f | ||
|
|
7ae8594c00 | ||
|
|
19663b0f38 | ||
|
|
4bcb9adb83 | ||
|
|
f7505298d7 | ||
|
|
df722ffa8b | ||
|
|
2a852fe08d | ||
|
|
540f796200 | ||
|
|
b726ac84fe | ||
|
|
61ac2bb6a3 | ||
|
|
5d702b3992 | ||
|
|
3bf4a004d4 | ||
|
|
7ac5876d2d | ||
|
|
0f18c612af | ||
|
|
03f4a3c478 | ||
|
|
7069343cf4 | ||
|
|
7fae79f2c5 | ||
|
|
66b714ed39 | ||
|
|
d371ebe354 | ||
|
|
9093d0d5e5 | ||
|
|
1139df0637 | ||
|
|
c1810de316 | ||
|
|
863ced57f8 | ||
|
|
2147aeb4ae | ||
|
|
a810b4fc9a | ||
|
|
abcbb61b4c | ||
|
|
83332223ef | ||
|
|
fd8d981ea0 | ||
|
|
03e3ade09d | ||
|
|
68305f2e00 | ||
|
|
b7d6b06242 | ||
|
|
9098050c5a | ||
|
|
0147ec0a6a | ||
|
|
c6b71605d0 | ||
|
|
64009c82e9 | ||
|
|
5b24cb370f | ||
|
|
2d261cd97b | ||
|
|
9455d91b3d | ||
|
|
cb645c56b4 | ||
|
|
1a6b91dee5 | ||
|
|
8d2edad488 | ||
|
|
522e26b1fa | ||
|
|
259b22c255 | ||
|
|
b61cf82b46 | ||
|
|
4f06f7424c | ||
|
|
d2d65437f8 | ||
|
|
3ae0f7558e | ||
|
|
604801686d | ||
|
|
554d4190ff | ||
|
|
1d71390349 | ||
|
|
fe24c6d682 | ||
|
|
4359d91a23 | ||
|
|
ae42eac7fd | ||
|
|
37a8888a32 | ||
|
|
2d7e065d39 | ||
|
|
35cf640691 | ||
|
|
b308fbe0ad | ||
|
|
d5e2b51b6d | ||
|
|
9b7844542d | ||
|
|
9f6fac0d58 | ||
|
|
f6011dc3f2 | ||
|
|
fdb7fa21f6 | ||
|
|
29bbe41e51 | ||
|
|
004ada8204 | ||
|
|
9a2894944c | ||
|
|
dfcff5029b | ||
|
|
853fc600dd | ||
|
|
a546b21755 | ||
|
|
e40c4e3779 | ||
|
|
60cbf6cff3 | ||
|
|
6d3f4b98d7 | ||
|
|
4812a2b401 | ||
|
|
5f99376d58 | ||
|
|
3e76c142c3 | ||
|
|
28f23a73af | ||
|
|
68b94fed8e | ||
|
|
657b02727c | ||
|
|
7d7a10073c | ||
|
|
9d5f0c791c | ||
|
|
212493e4ff | ||
|
|
9fc8e9c6d7 | ||
|
|
f69ddb71a0 | ||
|
|
290beec0c5 | ||
|
|
dcb2f6f8cd | ||
|
|
d200845906 | ||
|
|
a52e02695d | ||
|
|
febd7c3063 | ||
|
|
d5ae0b99f0 | ||
|
|
8b10c608fc | ||
|
|
0d49b91cc6 | ||
|
|
2af4b83e09 | ||
|
|
cde3ca3d9e | ||
|
|
429798190a | ||
|
|
583db4c70f | ||
|
|
3ec35eec91 | ||
|
|
65bfbfc7fd | ||
|
|
1b93701df2 | ||
|
|
d6debc55f5 | ||
|
|
87fd9ae686 | ||
|
|
3225a3b337 | ||
|
|
4eb98a6c31 | ||
|
|
38a6e2fc98 | ||
|
|
c171cf1487 | ||
|
|
b64a0f1d55 | ||
|
|
3ab124b2db | ||
|
|
d710f3995f | ||
|
|
f53c209082 | ||
|
|
9997be3462 | ||
|
|
c3b06e375c | ||
|
|
1476c5a932 | ||
|
|
8e1c9b9703 | ||
|
|
27c89f7cc7 | ||
|
|
9210198766 | ||
|
|
ce6fa0bf8f | ||
|
|
cd6629b424 | ||
|
|
f25a62ad71 | ||
|
|
cec3c872b6 | ||
|
|
e666e71281 | ||
|
|
3d0c303d41 | ||
|
|
d70a97cf77 | ||
|
|
c67c433258 | ||
|
|
0da6bd5ab6 | ||
|
|
e5cdb1580e | ||
|
|
2c10292073 | ||
|
|
30036a456e | ||
|
|
6349ae9e2b | ||
|
|
8d746669c3 | ||
|
|
0081abc9a7 | ||
|
|
a2f9ac05fe | ||
|
|
6c1f24bad7 | ||
|
|
77cd01e91f | ||
|
|
5487aac81d | ||
|
|
8a6257dc63 | ||
|
|
57227f9544 |
30
.github/workflows/ci.yml
vendored
30
.github/workflows/ci.yml
vendored
@@ -7,7 +7,7 @@ on:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
JAVA_VERSION: 21
|
||||
JAVA_VERSION: 25
|
||||
DOCKER_BUILD_SUMMARY: false
|
||||
|
||||
jobs:
|
||||
@@ -23,13 +23,13 @@ jobs:
|
||||
steps:
|
||||
# Checkout
|
||||
- name: Checkout
|
||||
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# Setup
|
||||
- name: Set up GraalVM
|
||||
uses: graalvm/setup-graalvm@eec48106e0bf45f2976c2ff0c3e22395cced8243 # v1
|
||||
uses: graalvm/setup-graalvm@54b4f5a65c1a84b2fdfdc2078fe43df32819e4b1 # v1
|
||||
with:
|
||||
java-version: ${{ env.JAVA_VERSION }}
|
||||
distribution: "graalvm"
|
||||
@@ -48,33 +48,33 @@ jobs:
|
||||
run: mkdir -p target/pages/documentation/custom-css
|
||||
|
||||
- name: Convert readme file to html
|
||||
uses: jaywcjlove/markdown-to-html-cli@d2c8ffd676de1801e2586904bc540a938e4bc480 # v5.0.3
|
||||
uses: jaywcjlove/markdown-to-html-cli@cff9330af4ca8048b197a76d9eb1db189c2a7cee # v5.0.4
|
||||
with:
|
||||
source: README.md
|
||||
output: target/pages/index.html
|
||||
|
||||
- name: Convert config documentation to html
|
||||
uses: jaywcjlove/markdown-to-html-cli@d2c8ffd676de1801e2586904bc540a938e4bc480 # v5.0.3
|
||||
uses: jaywcjlove/markdown-to-html-cli@cff9330af4ca8048b197a76d9eb1db189c2a7cee # v5.0.4
|
||||
with:
|
||||
source: commafeed-server/target/quarkus-generated-doc/config/commafeed-server.md
|
||||
output: target/pages/documentation/index.html
|
||||
|
||||
- name: Convert custom css documentation to html
|
||||
uses: jaywcjlove/markdown-to-html-cli@d2c8ffd676de1801e2586904bc540a938e4bc480 # v5.0.3
|
||||
uses: jaywcjlove/markdown-to-html-cli@cff9330af4ca8048b197a76d9eb1db189c2a7cee # v5.0.4
|
||||
with:
|
||||
source: documentation/CUSTOMCSS.md
|
||||
output: target/pages/documentation/custom-css/index.html
|
||||
|
||||
# Upload artifacts
|
||||
- name: Upload cross-platform app
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||
if: matrix.os == 'ubuntu-latest' # we only need to upload the cross-platform artifact once per database
|
||||
with:
|
||||
name: commafeed-${{ matrix.database }}-jvm
|
||||
path: commafeed-server/target/commafeed-*.zip
|
||||
|
||||
- name: Upload native executable
|
||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||
with:
|
||||
name: commafeed-${{ matrix.database }}-${{ runner.os }}-${{ runner.arch }}
|
||||
path: commafeed-server/target/commafeed-*-runner*
|
||||
@@ -98,7 +98,7 @@ jobs:
|
||||
steps:
|
||||
# Checkout
|
||||
- name: Checkout
|
||||
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -107,14 +107,14 @@ jobs:
|
||||
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3
|
||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
|
||||
|
||||
- name: Install required packages
|
||||
run: sudo apt-get install -y rename unzip
|
||||
|
||||
# Prepare artifacts
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
|
||||
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
|
||||
with:
|
||||
pattern: commafeed-${{ matrix.database }}-*
|
||||
path: ./artifacts
|
||||
@@ -135,7 +135,7 @@ jobs:
|
||||
|
||||
# Docker
|
||||
- name: Login to Container Registry
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
|
||||
if: ${{ env.DOCKERHUB_USERNAME != '' }}
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
@@ -215,12 +215,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6
|
||||
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
|
||||
with:
|
||||
pattern: commafeed-*
|
||||
path: ./artifacts
|
||||
@@ -249,7 +249,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
||||
2
.mvn/wrapper/maven-wrapper.properties
vendored
2
.mvn/wrapper/maven-wrapper.properties
vendored
@@ -1,3 +1,3 @@
|
||||
wrapperVersion=3.3.4
|
||||
distributionType=only-script
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.12/apache-maven-3.9.12-bin.zip
|
||||
|
||||
27
CHANGELOG.md
27
CHANGELOG.md
@@ -1,5 +1,32 @@
|
||||
# Changelog
|
||||
|
||||
## [6.2.0]
|
||||
|
||||
- Starred entries are no longer deleted after a certain amount of time, they are now kept indefinitely. The new `commafeed.database.cleanup.keep-starred-entries` setting can be disabled to restore the previous behavior if you want to keep deleting starred entries during normal entries cleanup (#1581)
|
||||
|
||||
## [6.1.1]
|
||||
|
||||
- Fix old starred entries not loading if they were marked as read (#2031)
|
||||
|
||||
## [6.1.0]
|
||||
|
||||
- When clicking on the password reset link, a random password is no longer generated automatically. The user is now redirected to a page where they can set their own password (#2023)
|
||||
- Use browser preferred language instead of English when using CommaFeed for the first time (#2018)
|
||||
- The profile menu is now closed when scrolling the page (#2019)
|
||||
- The "disable pull to refresh" feature is now disabled by default (#2030)
|
||||
|
||||
## [6.0.0]
|
||||
|
||||
- When booting CommaFeed for the first time, the default "admin" account is no longer created automatically. A setup wizard will guide you through the creation of an admin account
|
||||
- Default password complexity requirements have been lowered for local network deployments, where strict password rules are often unnecessary. The `commafeed.users.strict-password-policy` setting has been replaced by `commafeed.users.minimum-password-length` with a default value of `4` (#1916)
|
||||
- Email addresses are no longer required when creating users and when they update their profile. The `commafeed.users.email-address-required` setting has been added to restore the previous behavior (#1914)
|
||||
- Java 25+ is now required to build and run CommaFeed
|
||||
|
||||
## [5.12.1]
|
||||
|
||||
- The favicon is now crispier (#1978)
|
||||
- The ReadKit iOS app now works via the Fever API (#1602)
|
||||
|
||||
## [5.12.0]
|
||||
|
||||
- Added a setting to disable the "disable pull to refresh" feature because it messes with some browsers (#1168)
|
||||
|
||||
14
README.md
14
README.md
@@ -26,11 +26,18 @@ Google Reader inspired self-hosted RSS reader, based on Quarkus and React/TypeSc
|
||||
- MySQL
|
||||
- MariaDB
|
||||
|
||||
## Deployment
|
||||
## Usage
|
||||
|
||||
### Public instance
|
||||
|
||||
A free public instance is available at https://www.commafeed.com.
|
||||
|
||||
It has no ads, no tracking, and your data is never exploited or sold to third parties. The service is funded entirely through donations.
|
||||
However, this public instance does have a few limitations compared to self-hosted setups, outlined [here](https://github.com/Athou/commafeed/discussions/1567).
|
||||
|
||||
### Docker
|
||||
|
||||
Docker is the easiest way to get started with CommaFeed.
|
||||
Docker is the easiest way to get started with self-hosted CommaFeed.
|
||||
|
||||
Docker images are built automatically and are available at https://hub.docker.com/r/athou/commafeed
|
||||
|
||||
@@ -103,7 +110,7 @@ There are multiple ways to configure CommaFeed:
|
||||
- Environment variables (keys in UPPER_CASE)
|
||||
- a `.env` file in the working directory (keys in UPPER_CASE)
|
||||
|
||||
The properties file is recommended because CommaFeed will be able to warn about invalid properties and typos.
|
||||
When in doubt, the properties file is recommended because CommaFeed will be able to warn about invalid properties and typos.
|
||||
|
||||
All [CommaFeed settings](https://athou.github.io/commafeed/documentation) are optional and have sensible default values.
|
||||
|
||||
@@ -113,7 +120,6 @@ meaning that you will have to log back in after each restart of the application.
|
||||
All other Quarkus settings can be found [here](https://quarkus.io/guides/all-config).
|
||||
|
||||
When started, the server will listen on http://localhost:8082.
|
||||
The default user is `admin` and the default password is `admin`.
|
||||
|
||||
### Updates
|
||||
|
||||
|
||||
3
commafeed-client/.gitignore
vendored
3
commafeed-client/.gitignore
vendored
@@ -23,9 +23,6 @@ dist-ssr
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
# rollup-plugin-visualizer
|
||||
/stats.html
|
||||
|
||||
# vite
|
||||
vite.config.ts.timestamp-*.mjs
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"$schema": "https://biomejs.dev/schemas/2.3.6/schema.json",
|
||||
"$schema": "https://biomejs.dev/schemas/2.3.14/schema.json",
|
||||
"formatter": {
|
||||
"indentStyle": "space",
|
||||
"indentWidth": 4,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="favicon.svg" />
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
||||
<link rel="manifest" href="manifest.json" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
|
||||
2427
commafeed-client/package-lock.json
generated
2427
commafeed-client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -17,66 +17,65 @@
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@fontsource/open-sans": "^5.2.7",
|
||||
"@lingui/core": "^5.6.0",
|
||||
"@lingui/react": "^5.6.0",
|
||||
"@mantine/core": "^8.3.8",
|
||||
"@mantine/form": "^8.3.8",
|
||||
"@mantine/hooks": "^8.3.8",
|
||||
"@mantine/modals": "^8.3.8",
|
||||
"@mantine/notifications": "^8.3.8",
|
||||
"@mantine/spotlight": "^8.3.8",
|
||||
"@lingui/core": "^5.9.0",
|
||||
"@lingui/react": "^5.9.0",
|
||||
"@mantine/core": "^8.3.14",
|
||||
"@mantine/form": "^8.3.14",
|
||||
"@mantine/hooks": "^8.3.14",
|
||||
"@mantine/modals": "^8.3.14",
|
||||
"@mantine/notifications": "^8.3.14",
|
||||
"@mantine/spotlight": "^8.3.14",
|
||||
"@monaco-editor/react": "^4.7.0",
|
||||
"@reduxjs/toolkit": "^2.10.1",
|
||||
"axios": "^1.13.2",
|
||||
"@reduxjs/toolkit": "^2.11.2",
|
||||
"axios": "^1.13.4",
|
||||
"dayjs": "^1.11.19",
|
||||
"escape-string-regexp": "^5.0.0",
|
||||
"interweave": "^13.1.1",
|
||||
"monaco-editor": "^0.54.0",
|
||||
"monaco-editor": "^0.55.1",
|
||||
"mousetrap": "^1.6.5",
|
||||
"react": "^19.2.0",
|
||||
"react": "^19.2.4",
|
||||
"react-async-hook": "^4.0.0",
|
||||
"react-contexify": "^6.0.0",
|
||||
"react-dom": "^19.2.0",
|
||||
"react-dom": "^19.2.4",
|
||||
"react-draggable": "^4.5.0",
|
||||
"react-icons": "^5.5.0",
|
||||
"react-infinite-scroller": "^1.2.6",
|
||||
"react-redux": "^9.2.0",
|
||||
"react-router-dom": "^7.9.6",
|
||||
"react-router-dom": "^7.13.0",
|
||||
"react-swipeable": "^7.0.2",
|
||||
"style-to-object": "^1.0.14",
|
||||
"throttle-debounce": "^5.0.2",
|
||||
"tinycon": "^0.6.8",
|
||||
"tss-react": "^4.9.19",
|
||||
"tss-react": "^4.9.20",
|
||||
"websocket-heartbeat-js": "^1.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^2.3.6",
|
||||
"@lingui/babel-plugin-lingui-macro": "^5.6.0",
|
||||
"@lingui/cli": "^5.6.0",
|
||||
"@lingui/vite-plugin": "^5.6.0",
|
||||
"@biomejs/biome": "^2.3.14",
|
||||
"@lingui/babel-plugin-lingui-macro": "^5.9.0",
|
||||
"@lingui/cli": "^5.9.0",
|
||||
"@lingui/vite-plugin": "^5.9.0",
|
||||
"@testing-library/jest-dom": "^6.9.1",
|
||||
"@testing-library/react": "^16.3.0",
|
||||
"@testing-library/react": "^16.3.2",
|
||||
"@testing-library/user-event": "^14.6.1",
|
||||
"@types/mousetrap": "^1.6.15",
|
||||
"@types/react": "^19.2.6",
|
||||
"@types/react": "^19.2.13",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@types/react-infinite-scroller": "^1.2.5",
|
||||
"@types/throttle-debounce": "^5.0.2",
|
||||
"@types/tinycon": "^0.6.7",
|
||||
"@vitejs/plugin-react": "^5.1.1",
|
||||
"@vitejs/plugin-react": "^5.1.3",
|
||||
"babel-plugin-react-compiler": "1.0.0",
|
||||
"jsdom": "^27.2.0",
|
||||
"rollup-plugin-visualizer": "^6.0.5",
|
||||
"jsdom": "^28.0.0",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^7.2.2",
|
||||
"vite-plugin-checker": "^0.11.0",
|
||||
"vite-tsconfig-paths": "^5.1.4",
|
||||
"vitest": "^4.0.10",
|
||||
"yaml": "^2.8.1"
|
||||
"vite": "^7.3.1",
|
||||
"vite-plugin-checker": "^0.12.0",
|
||||
"vite-tsconfig-paths": "^6.0.5",
|
||||
"vitest": "^4.0.18",
|
||||
"yaml": "^2.8.2"
|
||||
},
|
||||
"overrides": {
|
||||
"react-infinite-scroller": {
|
||||
"react": "^19.2.0"
|
||||
"react": "^19.2.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,19 +6,16 @@
|
||||
<parent>
|
||||
<groupId>com.commafeed</groupId>
|
||||
<artifactId>commafeed</artifactId>
|
||||
<version>5.12.0</version>
|
||||
<version>6.2.0</version>
|
||||
</parent>
|
||||
<artifactId>commafeed-client</artifactId>
|
||||
<name>CommaFeed Client</name>
|
||||
|
||||
<properties>
|
||||
<sonar.sources>package.json,src</sonar.sources>
|
||||
<sonar.coverage.exclusions>**/*</sonar.coverage.exclusions>
|
||||
|
||||
<!-- renovate: datasource=node-version depName=node -->
|
||||
<node.version>v24.11.1</node.version>
|
||||
<node.version>v24.13.0</node.version>
|
||||
<!-- renovate: datasource=npm depName=npm -->
|
||||
<npm.version>11.6.3</npm.version>
|
||||
<npm.version>11.9.0</npm.version>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
@@ -26,7 +23,7 @@
|
||||
<plugin>
|
||||
<groupId>com.github.eirslett</groupId>
|
||||
<artifactId>frontend-maven-plugin</artifactId>
|
||||
<version>1.15.4</version>
|
||||
<version>2.0.0</version>
|
||||
<?m2e ignore?>
|
||||
<executions>
|
||||
<execution>
|
||||
@@ -75,7 +72,7 @@
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.3.1</version>
|
||||
<version>3.4.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy web interface to resources</id>
|
||||
|
||||
62
commafeed-client/public/favicon.svg
Normal file
62
commafeed-client/public/favicon.svg
Normal file
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
height="393.84613"
|
||||
width="393.84613"
|
||||
viewBox="0 0 5.0480766 5.0480766"
|
||||
version="1.1"
|
||||
id="svg3"
|
||||
sodipodi:docname="favicon.svg"
|
||||
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs3" />
|
||||
<sodipodi:namedview
|
||||
id="namedview3"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="1.21875"
|
||||
inkscape:cx="207.17949"
|
||||
inkscape:cy="187.07692"
|
||||
inkscape:window-width="1440"
|
||||
inkscape:window-height="855"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg3" />
|
||||
<rect
|
||||
fill="#f88a14"
|
||||
rx="0.53846151"
|
||||
ry="0.53846151"
|
||||
height="5.0480766"
|
||||
width="5.0480766"
|
||||
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>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
@@ -9,6 +9,7 @@ import { HashRouter, Navigate, Route, Routes, useNavigate } from "react-router-d
|
||||
import Tinycon from "tinycon"
|
||||
import { Constants } from "@/app/constants"
|
||||
import { redirectTo } from "@/app/redirect/slice"
|
||||
import { redirectToInitialSetup } from "@/app/redirect/thunks"
|
||||
import { reloadServerInfos } from "@/app/server/thunks"
|
||||
import { useAppDispatch, useAppSelector } from "@/app/store"
|
||||
import { categoryUnreadCount } from "@/app/utils"
|
||||
@@ -30,8 +31,10 @@ import { FeedEntriesPage } from "@/pages/app/FeedEntriesPage"
|
||||
import Layout from "@/pages/app/Layout"
|
||||
import { SettingsPage } from "@/pages/app/SettingsPage"
|
||||
import { TagDetailsPage } from "@/pages/app/TagDetailsPage"
|
||||
import { InitialSetupPage } from "@/pages/auth/InitialSetupPage"
|
||||
import { LoginPage } from "@/pages/auth/LoginPage"
|
||||
import { PasswordRecoveryPage } from "@/pages/auth/PasswordRecoveryPage"
|
||||
import { PasswordResetPage } from "@/pages/auth/PasswordResetPage"
|
||||
import { RegistrationPage } from "@/pages/auth/RegistrationPage"
|
||||
import { WelcomePage } from "@/pages/WelcomePage"
|
||||
|
||||
@@ -82,9 +85,11 @@ function AppRoutes() {
|
||||
<Routes>
|
||||
<Route path="/" element={<Navigate to={`/app/category/${Constants.categories.all.id}`} replace />} />
|
||||
<Route path="welcome" element={<WelcomePage />} />
|
||||
<Route path="setup" element={<InitialSetupPage />} />
|
||||
<Route path="login" element={<LoginPage />} />
|
||||
<Route path="register" element={<RegistrationPage />} />
|
||||
<Route path="passwordRecovery" element={<PasswordRecoveryPage />} />
|
||||
<Route path="passwordReset" element={<PasswordResetPage />} />
|
||||
<Route path="app" element={<Layout header={<Header />} sidebar={<Tree />} sidebarVisible={sidebarVisible} />}>
|
||||
<Route path="category">
|
||||
<Route path=":id" element={<FeedEntriesPage sourceType="category" />} />
|
||||
@@ -112,6 +117,18 @@ function AppRoutes() {
|
||||
)
|
||||
}
|
||||
|
||||
function InitialSetupHandler() {
|
||||
const serverInfos = useAppSelector(state => state.server.serverInfos)
|
||||
const dispatch = useAppDispatch()
|
||||
useEffect(() => {
|
||||
if (serverInfos?.initialSetupRequired) {
|
||||
dispatch(redirectToInitialSetup())
|
||||
}
|
||||
}, [serverInfos, dispatch])
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
function RedirectHandler() {
|
||||
const target = useAppSelector(state => state.redirect.to)
|
||||
const dispatch = useAppDispatch()
|
||||
@@ -178,6 +195,8 @@ function CustomJsHandler() {
|
||||
document.body.appendChild(script)
|
||||
|
||||
setScriptLoaded(true)
|
||||
|
||||
return () => script.remove()
|
||||
}, [scriptLoaded, loading])
|
||||
|
||||
return null
|
||||
@@ -190,6 +209,8 @@ function CustomCssHandler() {
|
||||
link.type = "text/css"
|
||||
link.href = "custom_css.css"
|
||||
document.head.appendChild(link)
|
||||
|
||||
return () => link.remove()
|
||||
}, [])
|
||||
|
||||
return null
|
||||
@@ -216,6 +237,7 @@ export function App() {
|
||||
<DisablePullToRefresh enabled={disablePullToRefresh} />
|
||||
|
||||
<HashRouter>
|
||||
<InitialSetupHandler />
|
||||
<RedirectHandler />
|
||||
<AppRoutes />
|
||||
</HashRouter>
|
||||
|
||||
@@ -12,10 +12,12 @@ import type {
|
||||
FeedModificationRequest,
|
||||
GetEntriesPaginatedRequest,
|
||||
IDRequest,
|
||||
InitialSetupRequest,
|
||||
LoginRequest,
|
||||
MarkRequest,
|
||||
Metrics,
|
||||
MultipleMarkRequest,
|
||||
PasswordResetConfirmationRequest,
|
||||
PasswordResetRequest,
|
||||
ProfileModificationRequest,
|
||||
RegistrationRequest,
|
||||
@@ -32,16 +34,17 @@ const axiosInstance = axios.create({ baseURL: "./rest", withCredentials: true })
|
||||
axiosInstance.interceptors.response.use(
|
||||
response => response,
|
||||
error => {
|
||||
if (isAuthenticationError(error)) {
|
||||
if (isAuthenticationError(error) && window.location.hash !== "#/login") {
|
||||
const data = error.response?.data
|
||||
window.location.hash = data?.allowRegistrations ? "/welcome" : "/login"
|
||||
window.location.reload()
|
||||
}
|
||||
throw error
|
||||
}
|
||||
)
|
||||
|
||||
function isAuthenticationError(error: unknown): error is AxiosError<AuthenticationError> {
|
||||
return axios.isAxiosError(error) && !!error.response && [401, 403].includes(error.response.status)
|
||||
return axios.isAxiosError(error) && error.response?.status === 401
|
||||
}
|
||||
|
||||
export const client = {
|
||||
@@ -93,7 +96,9 @@ export const client = {
|
||||
})
|
||||
},
|
||||
register: async (req: RegistrationRequest) => await axiosInstance.post("user/register", req),
|
||||
initialSetup: async (req: InitialSetupRequest) => await axiosInstance.post("user/initialSetup", req),
|
||||
passwordReset: async (req: PasswordResetRequest) => await axiosInstance.post("user/passwordReset", req),
|
||||
passwordResetCallback: async (req: PasswordResetConfirmationRequest) => await axiosInstance.post("user/passwordResetCallback", req),
|
||||
getSettings: async () => await axiosInstance.get<Settings>("user/settings"),
|
||||
saveSettings: async (settings: Settings) => await axiosInstance.post("user/settings", settings),
|
||||
getProfile: async () => await axiosInstance.get<UserModel>("user/profile"),
|
||||
|
||||
@@ -40,7 +40,9 @@ export const loadMoreEntries = createAppAsyncThunk("entries/loadMore", async (_,
|
||||
const state = thunkApi.getState()
|
||||
const { source } = state.entries
|
||||
const offset =
|
||||
state.user.settings?.readingMode === "all" ? state.entries.entries.length : state.entries.entries.filter(e => !e.read).length
|
||||
state.user.settings?.readingMode === "all" || (source.type === "category" && source.id === "starred")
|
||||
? state.entries.entries.length
|
||||
: state.entries.entries.filter(e => !e.read).length
|
||||
const endpoint = getEndpoint(state.entries.source.type)
|
||||
const result = await endpoint(buildGetEntriesPaginatedRequest(state, source, offset))
|
||||
return result.data
|
||||
|
||||
@@ -6,6 +6,8 @@ export const redirectToLogin = createAppAsyncThunk("redirect/login", (_, thunkAp
|
||||
|
||||
export const redirectToRegistration = createAppAsyncThunk("redirect/register", (_, thunkApi) => thunkApi.dispatch(redirectTo("/register")))
|
||||
|
||||
export const redirectToInitialSetup = createAppAsyncThunk("redirect/initialSetup", (_, thunkApi) => thunkApi.dispatch(redirectTo("/setup")))
|
||||
|
||||
export const redirectToApiDocumentation = createAppAsyncThunk("redirect/api", () => {
|
||||
window.location.href = "api-documentation/"
|
||||
})
|
||||
|
||||
@@ -196,6 +196,12 @@ export interface PasswordResetRequest {
|
||||
email: string
|
||||
}
|
||||
|
||||
export interface PasswordResetConfirmationRequest {
|
||||
email: string
|
||||
token: string
|
||||
password: string
|
||||
}
|
||||
|
||||
export interface ProfileModificationRequest {
|
||||
currentPassword: string
|
||||
email: string
|
||||
@@ -209,17 +215,26 @@ export interface RegistrationRequest {
|
||||
email: string
|
||||
}
|
||||
|
||||
export interface InitialSetupRequest {
|
||||
name: string
|
||||
password: string
|
||||
email?: string
|
||||
}
|
||||
|
||||
export interface ServerInfo {
|
||||
announcement?: string
|
||||
version: string
|
||||
gitCommit: string
|
||||
allowRegistrations: boolean
|
||||
emailAddressRequired: boolean
|
||||
smtpEnabled: boolean
|
||||
demoAccountEnabled: boolean
|
||||
websocketEnabled: boolean
|
||||
websocketPingInterval: number
|
||||
treeReloadInterval: number
|
||||
forceRefreshCooldownDuration: number
|
||||
initialSetupRequired: boolean
|
||||
minimumPasswordLength: number
|
||||
}
|
||||
|
||||
export interface SharingSettings {
|
||||
@@ -234,7 +249,7 @@ export interface SharingSettings {
|
||||
}
|
||||
|
||||
export interface Settings {
|
||||
language: string
|
||||
language?: string
|
||||
readingMode: ReadingMode
|
||||
readingOrder: ReadingOrder
|
||||
showRead: boolean
|
||||
|
||||
@@ -145,6 +145,7 @@ export function FeedEntry(props: Readonly<FeedEntryProps>) {
|
||||
component="article"
|
||||
id={Constants.dom.entryId(props.entry)}
|
||||
data-id={props.entry.id}
|
||||
data-feed-id={props.entry.feedId}
|
||||
withBorder
|
||||
radius={borderRadius}
|
||||
className={cx(classes.paper, {
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
} from "@mantine/core"
|
||||
import { showNotification } from "@mantine/notifications"
|
||||
import dayjs from "dayjs"
|
||||
import { type ReactNode, useState } from "react"
|
||||
import { type ReactNode, useEffect, useState } from "react"
|
||||
import {
|
||||
TbChartLine,
|
||||
TbHeartFilled,
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
TbUsers,
|
||||
TbWorldDownload,
|
||||
} from "react-icons/tb"
|
||||
import { throttle } from "throttle-debounce"
|
||||
import { client } from "@/app/client"
|
||||
import { redirectToAbout, redirectToAdminUsers, redirectToDonate, redirectToMetrics, redirectToSettings } from "@/app/redirect/thunks"
|
||||
import { useAppDispatch, useAppSelector } from "@/app/store"
|
||||
@@ -96,6 +97,14 @@ const viewModeData: ViewModeControlItem[] = [
|
||||
|
||||
export function ProfileMenu(props: Readonly<ProfileMenuProps>) {
|
||||
const [opened, setOpened] = useState(false)
|
||||
|
||||
// close profile menu on scroll
|
||||
useEffect(() => {
|
||||
const listener = throttle(100, () => setOpened(false))
|
||||
window.addEventListener("scroll", listener)
|
||||
return () => window.removeEventListener("scroll", listener)
|
||||
}, [])
|
||||
|
||||
const now = useNow()
|
||||
const profile = useAppSelector(state => state.user.profile)
|
||||
const admin = useAppSelector(state => state.user.profile?.admin)
|
||||
|
||||
@@ -143,6 +143,47 @@ export function DisplaySettings() {
|
||||
onChange={async e => await dispatch(changeMobileFooter(e.currentTarget.checked))}
|
||||
/>
|
||||
|
||||
<Divider label={<Trans>Scrolling</Trans>} labelPosition="center" />
|
||||
|
||||
<Switch
|
||||
label={<Trans>Disable "Pull to refresh" browser behavior</Trans>}
|
||||
description={<Trans>This setting can cause scrolling issues on some browsers (e.g. Safari)</Trans>}
|
||||
checked={disablePullToRefresh}
|
||||
onChange={async e => await dispatch(changeDisablePullToRefresh(e.currentTarget.checked))}
|
||||
/>
|
||||
|
||||
<Radio.Group
|
||||
label={<Trans>Scroll selected entry to the top of the page</Trans>}
|
||||
value={scrollMode}
|
||||
onChange={async value => await dispatch(changeScrollMode(value as ScrollMode))}
|
||||
>
|
||||
<Group mt="xs">
|
||||
{Object.entries(scrollModeOptions).map(e => (
|
||||
<Radio key={e[0]} value={e[0]} label={e[1]} />
|
||||
))}
|
||||
</Group>
|
||||
</Radio.Group>
|
||||
|
||||
<NumberInput
|
||||
label={<Trans>Entries to keep above the selected entry when scrolling</Trans>}
|
||||
description={<Trans>Only applies to compact, cozy and detailed modes</Trans>}
|
||||
min={0}
|
||||
value={entriesToKeepOnTop}
|
||||
onChange={async value => await dispatch(changeEntriesToKeepOnTopWhenScrolling(+value))}
|
||||
/>
|
||||
|
||||
<Switch
|
||||
label={<Trans>Scroll smoothly when navigating between entries</Trans>}
|
||||
checked={scrollSpeed ? scrollSpeed > 0 : false}
|
||||
onChange={async e => await dispatch(changeScrollSpeed(e.currentTarget.checked))}
|
||||
/>
|
||||
|
||||
<Switch
|
||||
label={<Trans>In expanded view, scrolling through entries mark them as read</Trans>}
|
||||
checked={scrollMarks}
|
||||
onChange={async e => await dispatch(changeScrollMarks(e.currentTarget.checked))}
|
||||
/>
|
||||
|
||||
<Divider label={<Trans>Browser tab</Trans>} labelPosition="center" />
|
||||
|
||||
<Switch
|
||||
@@ -179,46 +220,6 @@ export function DisplaySettings() {
|
||||
onChange={async e => await dispatch(changeCustomContextMenu(e.currentTarget.checked))}
|
||||
/>
|
||||
|
||||
<Divider label={<Trans>Scrolling</Trans>} labelPosition="center" />
|
||||
|
||||
<Radio.Group
|
||||
label={<Trans>Scroll selected entry to the top of the page</Trans>}
|
||||
value={scrollMode}
|
||||
onChange={async value => await dispatch(changeScrollMode(value as ScrollMode))}
|
||||
>
|
||||
<Group mt="xs">
|
||||
{Object.entries(scrollModeOptions).map(e => (
|
||||
<Radio key={e[0]} value={e[0]} label={e[1]} />
|
||||
))}
|
||||
</Group>
|
||||
</Radio.Group>
|
||||
|
||||
<NumberInput
|
||||
label={<Trans>Entries to keep above the selected entry when scrolling</Trans>}
|
||||
description={<Trans>Only applies to compact, cozy and detailed modes</Trans>}
|
||||
min={0}
|
||||
value={entriesToKeepOnTop}
|
||||
onChange={async value => await dispatch(changeEntriesToKeepOnTopWhenScrolling(+value))}
|
||||
/>
|
||||
|
||||
<Switch
|
||||
label={<Trans>Scroll smoothly when navigating between entries</Trans>}
|
||||
checked={scrollSpeed ? scrollSpeed > 0 : false}
|
||||
onChange={async e => await dispatch(changeScrollSpeed(e.currentTarget.checked))}
|
||||
/>
|
||||
|
||||
<Switch
|
||||
label={<Trans>In expanded view, scrolling through entries mark them as read</Trans>}
|
||||
checked={scrollMarks}
|
||||
onChange={async e => await dispatch(changeScrollMarks(e.currentTarget.checked))}
|
||||
/>
|
||||
|
||||
<Switch
|
||||
label={<Trans>Disable "Pull to refresh" browser behavior</Trans>}
|
||||
checked={disablePullToRefresh}
|
||||
onChange={async e => await dispatch(changeDisablePullToRefresh(e.currentTarget.checked))}
|
||||
/>
|
||||
|
||||
<Divider label={<Trans>Sharing sites</Trans>} labelPosition="center" />
|
||||
|
||||
<SimpleGrid cols={2}>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { msg } from "@lingui/core/macro"
|
||||
import { useLingui } from "@lingui/react"
|
||||
import { Trans } from "@lingui/react/macro"
|
||||
import { Anchor, Box, Button, Checkbox, Divider, Group, Input, PasswordInput, Stack, Text, TextInput } from "@mantine/core"
|
||||
@@ -13,6 +12,7 @@ import { useAppDispatch, useAppSelector } from "@/app/store"
|
||||
import type { ProfileModificationRequest } from "@/app/types"
|
||||
import { reloadProfile } from "@/app/user/thunks"
|
||||
import { Alert } from "@/components/Alert"
|
||||
import { useValidationRules } from "@/hooks/useValidationRules"
|
||||
|
||||
interface FormData extends ProfileModificationRequest {
|
||||
newPasswordConfirmation?: string
|
||||
@@ -20,13 +20,17 @@ interface FormData extends ProfileModificationRequest {
|
||||
|
||||
export function ProfileSettings() {
|
||||
const profile = useAppSelector(state => state.user.profile)
|
||||
const serverInfos = useAppSelector(state => state.server.serverInfos)
|
||||
const dispatch = useAppDispatch()
|
||||
const { _ } = useLingui()
|
||||
const validationRules = useValidationRules()
|
||||
|
||||
const form = useForm<FormData>({
|
||||
validate: {
|
||||
newPasswordConfirmation: (value, values) => (value !== values.newPassword ? _(msg`Passwords do not match`) : null),
|
||||
newPassword: validationRules.password,
|
||||
newPasswordConfirmation: (value, values) => validationRules.passwordConfirmation(value, values.newPassword),
|
||||
},
|
||||
validateInputOnChange: true,
|
||||
})
|
||||
const { setValues } = form
|
||||
|
||||
@@ -134,7 +138,12 @@ export function ProfileSettings() {
|
||||
required
|
||||
{...form.getInputProps("currentPassword")}
|
||||
/>
|
||||
<TextInput type="email" label={<Trans>E-mail</Trans>} {...form.getInputProps("email")} required />
|
||||
<TextInput
|
||||
type="email"
|
||||
label={<Trans>E-mail</Trans>}
|
||||
{...form.getInputProps("email")}
|
||||
required={serverInfos?.emailAddressRequired}
|
||||
/>
|
||||
<PasswordInput
|
||||
label={<Trans>New password</Trans>}
|
||||
description={<Trans>Changing password will generate a new API key</Trans>}
|
||||
|
||||
17
commafeed-client/src/hooks/useValidationRules.ts
Normal file
17
commafeed-client/src/hooks/useValidationRules.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { msg } from "@lingui/core/macro"
|
||||
import { useLingui } from "@lingui/react"
|
||||
import { useAppSelector } from "@/app/store"
|
||||
|
||||
export function useValidationRules() {
|
||||
const minimumPasswordLength = useAppSelector(state => state.server.serverInfos?.minimumPasswordLength)
|
||||
const { _ } = useLingui()
|
||||
|
||||
return {
|
||||
password: (value: string | undefined) =>
|
||||
value && minimumPasswordLength && value.length < minimumPasswordLength
|
||||
? _(msg`Password must be at least ${minimumPasswordLength} characters`)
|
||||
: null,
|
||||
passwordConfirmation: (newPasswordConfirmation: string | undefined, newPassword: string | undefined) =>
|
||||
newPasswordConfirmation && newPasswordConfirmation !== newPassword ? _(msg`Passwords do not match`) : null,
|
||||
}
|
||||
}
|
||||
@@ -60,6 +60,11 @@ msgstr "إضافة مستخدم"
|
||||
msgid "Admin"
|
||||
msgstr "إداري"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "العودة"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "العودة لتسجيل الدخول"
|
||||
|
||||
@@ -137,12 +143,12 @@ msgstr "العودة لتسجيل الدخول"
|
||||
msgid "Blue"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
@@ -221,10 +227,19 @@ msgstr "تأكيد"
|
||||
msgid "Confirm password"
|
||||
msgstr "تأكيد كلمة المرور"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "دافئ"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr "السيطرة"
|
||||
@@ -309,6 +324,8 @@ msgstr "اسحب الرابط إلى شريط الإشارات"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -476,6 +493,14 @@ msgstr "في العرض الموسع ، التمرير عبر الإدخالات
|
||||
msgid "Indigo"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr ""
|
||||
msgid "New password"
|
||||
msgstr "كلمة مرور جديدة"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "الأحدث أولاً"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "الفئة الأصل"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "الفئة الأصل"
|
||||
msgid "Password"
|
||||
msgstr "كلمة المرور"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "استعادة كلمة المرور"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "كلمات المرور غير متطابقة"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "تحديث"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "تم إغلاق التسجيلات في مثيل CommaFeed هذا"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr ""
|
||||
@@ -1000,6 +1041,10 @@ msgstr "الموضوع"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "تبديل قراءة حالة الإدخال الحالي"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "تحذير"
|
||||
msgid "Website"
|
||||
msgstr "موقع الكتروني"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr ""
|
||||
@@ -1067,3 +1116,7 @@ msgstr "ليس لديك أي اشتراكات حتى الآن. "
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
@@ -60,6 +60,11 @@ msgstr "Afegeix usuari"
|
||||
msgid "Admin"
|
||||
msgstr "Administrador"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "Enrere"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "Torna a iniciar sessió"
|
||||
|
||||
@@ -137,14 +143,14 @@ msgstr "Torna a iniciar sessió"
|
||||
msgid "Blue"
|
||||
msgstr "Blau"
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr "Extensió del navegador"
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr "Extensió del navegador necessària per a Chrome"
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
msgstr "Extensió del navegador"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Browser tab"
|
||||
msgstr "Pestanya del navegador"
|
||||
@@ -221,10 +227,19 @@ msgstr "Confirma"
|
||||
msgid "Confirm password"
|
||||
msgstr "Confirmeu la contrasenya"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "Acollidor"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr "Ctrl"
|
||||
@@ -285,7 +300,7 @@ msgstr "Detallat"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Disable \"Pull to refresh\" browser behavior"
|
||||
msgstr ""
|
||||
msgstr "Desactiva el comportament \"Arrossega per actualitzar\"\\ del navegador"
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
@@ -309,6 +324,8 @@ msgstr "Arrossegueu l'enllaç a la barra d'adreces d'interès"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -434,7 +451,7 @@ msgstr "Vés a la documentació de l'API."
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Goodies"
|
||||
msgstr "Bones"
|
||||
msgstr "Extres"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Grape"
|
||||
@@ -476,6 +493,14 @@ msgstr "En la vista ampliada, en desplaçar-se per les entrades, es marquen com
|
||||
msgid "Indigo"
|
||||
msgstr "Indi"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr "Mai"
|
||||
msgid "New password"
|
||||
msgstr "Contrasenya nova"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "El més nou primer"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "Categoria pare"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "Categoria pare"
|
||||
msgid "Password"
|
||||
msgstr "Contrasenya"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "Recuperació de contrasenya"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Les contrasenyes no coincideixen"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "Actualitzar"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "Els registres estan tancats en aquesta instància de CommaFeed"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr "API REST"
|
||||
@@ -1000,6 +1041,10 @@ msgstr "Tema"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr "Aquesta és la vostra clau de l'API. Es pot utilitzar per a algunes operacions de l'API de només lectura i permet accedir a l'API Fever. Utilitzeu el formulari de la part inferior de la pàgina per generar una nova clau d'API."
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr "Aquesta configuració pot causar problemes de desplaçament en alguns navegadors (per exemple, Safari)"
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "Canvia l'estat de lectura de l'entrada actual"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "Avís"
|
||||
msgid "Website"
|
||||
msgstr "Lloc web"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Groc"
|
||||
@@ -1067,3 +1116,7 @@ msgstr "Encara no teniu cap subscripció. "
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr "Els vostres feeds s'han posat a la cua per actualitzar-los."
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
@@ -60,6 +60,11 @@ msgstr "Přidat uživatele"
|
||||
msgid "Admin"
|
||||
msgstr "Správce"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "Zpět"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "Zpět k přihlášení"
|
||||
|
||||
@@ -137,12 +143,12 @@ msgstr "Zpět k přihlášení"
|
||||
msgid "Blue"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
@@ -221,10 +227,19 @@ msgstr "Potvrdit"
|
||||
msgid "Confirm password"
|
||||
msgstr "Potvrďte heslo"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "Útulný"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr ""
|
||||
@@ -309,6 +324,8 @@ msgstr "Přetáhněte odkaz na lištu záložek"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -476,6 +493,14 @@ msgstr "V rozšířeném zobrazení je procházením označíte jako přečtené
|
||||
msgid "Indigo"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr ""
|
||||
msgid "New password"
|
||||
msgstr "Nové heslo"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "Nejnovější jako první"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "Rodičovská kategorie"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "Rodičovská kategorie"
|
||||
msgid "Password"
|
||||
msgstr "Heslo"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "Obnovení hesla"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Hesla se neshodují"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "Obnovit"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "V této instanci CommaFeed jsou registrace uzavřeny"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr ""
|
||||
@@ -1000,6 +1041,10 @@ msgstr "Téma"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "Přepne stav čtení aktuálního záznamu"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "Varování"
|
||||
msgid "Website"
|
||||
msgstr "Webové stránky"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr ""
|
||||
@@ -1067,3 +1116,7 @@ msgstr "Zatím nemáte žádné předplatné. "
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
@@ -60,6 +60,11 @@ msgstr "Ychwanegu defnyddiwr"
|
||||
msgid "Admin"
|
||||
msgstr "Gweinyddol"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "Yn ôl"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "Yn ôl i fewngofnodi"
|
||||
|
||||
@@ -137,12 +143,12 @@ msgstr "Yn ôl i fewngofnodi"
|
||||
msgid "Blue"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
@@ -221,10 +227,19 @@ msgstr "Cadarnhau"
|
||||
msgid "Confirm password"
|
||||
msgstr "Cadarnhau'r cyfrinair"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "clyd"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr ""
|
||||
@@ -309,6 +324,8 @@ msgstr "Llusgwch y ddolen i'r bar nod tudalen"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -476,6 +493,14 @@ msgstr "Mewn gwedd estynedig, mae sgrolio trwy gofnodion yn nodi eu bod wedi'u d
|
||||
msgid "Indigo"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr ""
|
||||
msgid "New password"
|
||||
msgstr "Cyfrinair newydd"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "Y diweddaraf yn gyntaf"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "Categori Rhiant"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "Categori Rhiant"
|
||||
msgid "Password"
|
||||
msgstr "cyfrinair"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "Adfer Cyfrinair"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Nid yw cyfrineiriau yn cyfateb"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "Adnewyddu"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "Mae cofrestriadau ar gau ar yr achos CommaFeed hwn"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr ""
|
||||
@@ -1000,6 +1041,10 @@ msgstr "Thema"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "Toglo statws darllen y cofnod cyfredol"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "Rhybudd"
|
||||
msgid "Website"
|
||||
msgstr "Gwefan"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr ""
|
||||
@@ -1067,3 +1116,7 @@ msgstr "Nid oes gennych unrhyw danysgrifiadau eto. "
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
@@ -60,6 +60,11 @@ msgstr "Tilføj bruger"
|
||||
msgid "Admin"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "Tilbage"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "Tilbage for at logge ind"
|
||||
|
||||
@@ -137,12 +143,12 @@ msgstr "Tilbage for at logge ind"
|
||||
msgid "Blue"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
@@ -221,10 +227,19 @@ msgstr "Bekræft"
|
||||
msgid "Confirm password"
|
||||
msgstr "Bekræft adgangskode"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "Hyggeligt"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr ""
|
||||
@@ -309,6 +324,8 @@ msgstr "Træk linket til bogmærkelinjen"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -476,6 +493,14 @@ msgstr "I udvidet visning markerer du dem som læst, når du ruller gennem poste
|
||||
msgid "Indigo"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr ""
|
||||
msgid "New password"
|
||||
msgstr "Ny adgangskode"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "Nyeste først"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "Forældrekategori"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "Forældrekategori"
|
||||
msgid "Password"
|
||||
msgstr "Adgangskode"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "Gendannelse af adgangskode"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Adgangskoder stemmer ikke overens"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "Opdater"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "Registreringer er lukket på denne CommaFeed-instans"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr ""
|
||||
@@ -1000,6 +1041,10 @@ msgstr "Tema"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "Skift læsestatus for den aktuelle post"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "Advarsel"
|
||||
msgid "Website"
|
||||
msgstr "Hjemmeside"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr ""
|
||||
@@ -1067,3 +1116,7 @@ msgstr "Du har ingen abonnementer endnu. "
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
@@ -60,6 +60,11 @@ msgstr "Benutzer hinzufügen"
|
||||
msgid "Admin"
|
||||
msgstr "Verwaltung"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "Zurück"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "Zurück zum Login"
|
||||
|
||||
@@ -137,14 +143,14 @@ msgstr "Zurück zum Login"
|
||||
msgid "Blue"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr "Browser-Erweiterung"
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr "Browser-Erweiterung für Chrome benötigt"
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
msgstr "Browser-Erweiterung"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Browser tab"
|
||||
msgstr ""
|
||||
@@ -221,10 +227,19 @@ msgstr "Bestätigen"
|
||||
msgid "Confirm password"
|
||||
msgstr "Passwort bestätigen"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "Gemütlich"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr "Strg"
|
||||
@@ -309,6 +324,8 @@ msgstr "Link in Lesezeichenleiste ziehen"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -476,6 +493,14 @@ msgstr "In der erweiterten Ansicht werden Einträge beim Scrollen als gelesen ma
|
||||
msgid "Indigo"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr "Niemals"
|
||||
msgid "New password"
|
||||
msgstr "Neues Passwort"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "Neueste zuerst"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "Übergeordnete Kategorie"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "Übergeordnete Kategorie"
|
||||
msgid "Password"
|
||||
msgstr "Passwort"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "Passwortwiederherstellung"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Passwörter stimmen nicht überein"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "Aktualisieren"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "Registrierungen sind für diese CommaFeed-Instanz geschlossen"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr "REST-API"
|
||||
@@ -1000,6 +1041,10 @@ msgstr "Thema"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr "Dies ist Ihr API-Schlüssel. Er kann für einige schreibgeschützte API-Vorgänge verwendet werden und ermöglicht den Zugriff auf die Fever-API. Verwenden Sie das Formular unten auf der Seite, um einen neuen API-Schlüssel zu generieren"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "Lesestatus des aktuellen Eintrags umschalten"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "Warnung"
|
||||
msgid "Website"
|
||||
msgstr "Webseite"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr ""
|
||||
@@ -1067,3 +1116,7 @@ msgstr "Sie haben noch keine Abonnements."
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr "Ihr Feed wurde für die Aktualisierung eingereiht."
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
@@ -60,6 +60,11 @@ msgstr "Add user"
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr "Admin user name"
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "Back"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "Back to log in"
|
||||
|
||||
@@ -137,14 +143,14 @@ msgstr "Back to log in"
|
||||
msgid "Blue"
|
||||
msgstr "Blue"
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr "Browser extension"
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr "Browser extension required for Chrome"
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
msgstr "Browser extention"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Browser tab"
|
||||
msgstr "Browser tab"
|
||||
@@ -221,10 +227,19 @@ msgstr "Confirm"
|
||||
msgid "Confirm password"
|
||||
msgstr "Confirm password"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr "Confirm Password"
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "Cozy"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr "Create Admin Account"
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr "Ctrl"
|
||||
@@ -309,6 +324,8 @@ msgstr "Drag link to bookmark bar"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -476,6 +493,14 @@ msgstr "In expanded view, scrolling through entries mark them as read"
|
||||
msgid "Indigo"
|
||||
msgstr "Indigo"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr "Initial Setup"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr "Invalid password reset link. Please request a new one."
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr "Never"
|
||||
msgid "New password"
|
||||
msgstr "New password"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr "New Password"
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "Newest first"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "Parent Category"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "Parent Category"
|
||||
msgid "Password"
|
||||
msgstr "Password"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr "Password must be at least {minimumPasswordLength} characters"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "Password Recovery"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Passwords do not match"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "Refresh"
|
||||
msgid "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
|
||||
msgid "Reset Password"
|
||||
msgstr "Reset Password"
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr "REST API"
|
||||
@@ -1000,6 +1041,10 @@ msgstr "Theme"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "Toggle read status of current entry"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "Warning"
|
||||
msgid "Website"
|
||||
msgstr "Website"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Yellow"
|
||||
@@ -1067,3 +1116,7 @@ msgstr "You don't have any subscriptions yet. Why not try adding one by clicking
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr "Your feeds have been queued for refresh."
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr "Your password has been changed. You can now log in with your new password."
|
||||
|
||||
@@ -61,6 +61,11 @@ msgstr "Añadir usuario"
|
||||
msgid "Admin"
|
||||
msgstr "Administrador"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -131,6 +136,7 @@ msgid "Back"
|
||||
msgstr "Atrás"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "Volver a iniciar sesión"
|
||||
|
||||
@@ -138,14 +144,14 @@ msgstr "Volver a iniciar sesión"
|
||||
msgid "Blue"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr "Extensión del navegador"
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr "Se requiere extensión de navegador para Chrome"
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
msgstr "Extensión del navegador"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Browser tab"
|
||||
msgstr "Pestaña del navegador"
|
||||
@@ -222,10 +228,19 @@ msgstr "Confirmar"
|
||||
msgid "Confirm password"
|
||||
msgstr "Confirmar contraseña"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "Acogedor"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr "Ctrl"
|
||||
@@ -310,6 +325,8 @@ msgstr "Arrastra el enlace a la barra de marcadores"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -477,6 +494,14 @@ msgstr "En la vista ampliada, al desplazarse por las entradas marcarlas como le
|
||||
msgid "Indigo"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -620,6 +645,11 @@ msgstr "Nunca"
|
||||
msgid "New password"
|
||||
msgstr "Nueva contraseña"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "Las más recientes primero"
|
||||
@@ -748,6 +778,8 @@ msgid "Parent Category"
|
||||
msgstr "Categoría principal"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -755,11 +787,15 @@ msgstr "Categoría principal"
|
||||
msgid "Password"
|
||||
msgstr "Contraseña"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "Recuperación de contraseña"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Las contraseñas no coinciden"
|
||||
|
||||
@@ -801,6 +837,11 @@ msgstr "Actualizar"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "Los registros están cerrados en esta instancia de CommaFeed"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr "API REST"
|
||||
@@ -1001,6 +1042,10 @@ msgstr "Tema"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr "Esta es su clave API. Se puede utilizar para algunas operaciones API de solo lectura y otorga acceso a Fever API. Utilice el formulario en la parte inferior de la página para generar una nueva clave API"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "Alternar estado de lectura de la entrada actual"
|
||||
@@ -1057,6 +1102,10 @@ msgstr "Advertencia"
|
||||
msgid "Website"
|
||||
msgstr "Sitio web"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr ""
|
||||
@@ -1068,3 +1117,7 @@ msgstr "Aún no tienes ninguna suscripción. ¿Por qué no intentas agregar una
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr "Tus feeds se han puesto en cola para actualizarse."
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
@@ -60,6 +60,11 @@ msgstr "افزودن کاربر"
|
||||
msgid "Admin"
|
||||
msgstr "مدیر"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "برگشت"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "بازگشت برای ورود به سیستم"
|
||||
|
||||
@@ -137,12 +143,12 @@ msgstr "بازگشت برای ورود به سیستم"
|
||||
msgid "Blue"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
@@ -221,10 +227,19 @@ msgstr "تأیید کنید"
|
||||
msgid "Confirm password"
|
||||
msgstr "رمز عبور را تأیید کنید"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "دنج"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr ""
|
||||
@@ -309,6 +324,8 @@ msgstr "پیوند را به نوار نشانک بکشید"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -476,6 +493,14 @@ msgstr "در نمای بازشده، پیمایش در ورودیها، آن
|
||||
msgid "Indigo"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr ""
|
||||
msgid "New password"
|
||||
msgstr "رمز عبور جدید"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "ابتدا جدیدترین"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "دسته والد"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "دسته والد"
|
||||
msgid "Password"
|
||||
msgstr "رمز عبور"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "بازیابی رمز عبور"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "گذرواژه ها مطابقت ندارند"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "تازه کردن"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "ثبت نام در این نمونه CommaFeed بسته شده است"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr ""
|
||||
@@ -1000,6 +1041,10 @@ msgstr "تم"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "وضعیت خواندن ورودی فعلی را تغییر دهید"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "هشدار"
|
||||
msgid "Website"
|
||||
msgstr "وب سایت"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr ""
|
||||
@@ -1067,3 +1116,7 @@ msgstr "شما هنوز هیچ اشتراکی ندارید. "
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
@@ -60,6 +60,11 @@ msgstr "Lisää käyttäjä"
|
||||
msgid "Admin"
|
||||
msgstr "Järjestelmänvalvoja"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "Takaisin"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "Takaisin sisäänkirjautumiseen"
|
||||
|
||||
@@ -137,12 +143,12 @@ msgstr "Takaisin sisäänkirjautumiseen"
|
||||
msgid "Blue"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
@@ -221,10 +227,19 @@ msgstr "Vahvista"
|
||||
msgid "Confirm password"
|
||||
msgstr "Vahvista salasana"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "Viihtyisä"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr ""
|
||||
@@ -309,6 +324,8 @@ msgstr "Vedä linkki kirjanmerkkipalkkiin"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -476,6 +493,14 @@ msgstr "Merkitse ne luetuiksi laajennetussa näkymässä vierittämällä merkin
|
||||
msgid "Indigo"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr ""
|
||||
msgid "New password"
|
||||
msgstr "Uusi salasana"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "Uusin ensin"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "Pääluokka"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "Pääluokka"
|
||||
msgid "Password"
|
||||
msgstr "Salasana"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "Salasanan palautus"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Salasanat eivät täsmää"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "Päivitä"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "Tämän CommaFeed-esiintymän rekisteröinnit on suljettu"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr ""
|
||||
@@ -1000,6 +1041,10 @@ msgstr "Teema"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "Vaihda nykyisen merkinnän lukutila"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "Varoitus"
|
||||
msgid "Website"
|
||||
msgstr "Verkkosivusto"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr ""
|
||||
@@ -1067,3 +1116,7 @@ msgstr "Sinulla ei ole vielä tilauksia. "
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
@@ -60,6 +60,11 @@ msgstr "Ajouter un utilisateur"
|
||||
msgid "Admin"
|
||||
msgstr "Administrateur"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr "Nom de l'administrateur"
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "Retour"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "Retour à la connexion"
|
||||
|
||||
@@ -137,14 +143,14 @@ msgstr "Retour à la connexion"
|
||||
msgid "Blue"
|
||||
msgstr "Bleu"
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr "Extension navigateur"
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr "L'extension navigateur est nécessaire sur Chrome"
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
msgstr "Extension navigateur"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Browser tab"
|
||||
msgstr "Onglet navigateur"
|
||||
@@ -221,10 +227,19 @@ msgstr "Confirmer"
|
||||
msgid "Confirm password"
|
||||
msgstr "Confirmer le mot de passe"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr "Confirmer le mot de passe"
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "Cozy"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr "Créer un compte adminstrateur"
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr "Ctrl"
|
||||
@@ -285,7 +300,7 @@ msgstr "Vue détaillée"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Disable \"Pull to refresh\" browser behavior"
|
||||
msgstr ""
|
||||
msgstr "Désactiver la fonction \"tirer pour rafraîchir\" du navigateur"
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
@@ -309,6 +324,8 @@ msgstr "Déplacez le lien vers la barre de favoris"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -476,6 +493,14 @@ msgstr "En mode de lecture étendu, marquer les éléments comme lus lorsque la
|
||||
msgid "Indigo"
|
||||
msgstr "Indigo"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr "Configuration initiale"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr "Lien de réinitialisation de mot de passse invalide. Recommencez la procédure."
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr "Jamais"
|
||||
msgid "New password"
|
||||
msgstr "Nouveau mot de passe"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr "Nouveau mot de passe"
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "Plus récent en premier"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "Catégorie parente"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "Catégorie parente"
|
||||
msgid "Password"
|
||||
msgstr "Mot de passe"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr "Le mot de passe doit mesurer au moins {minimumPasswordLength} caractères"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "Récupération de mot de passe"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Les mots de passe ne correspondent pas"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "Rafraîchir"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "Les inscriptions sont fermées sur cette instance de CommaFeed"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr "Réinitialiser le mot de passe"
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr "API REST"
|
||||
@@ -1000,6 +1041,10 @@ msgstr "Thème"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr "Ceci est votre clef API. Elle peut être utilisée pour certaines opérations en lecture seule et donne accès à l'API Fever. Utilisez le formulaire en bas de la page pour générer une nouvelle clef API"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr "Cette fonctinnalité peut causer des problèmes de défilement sur certains navigateurs (Safari, par exemple)"
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "Marquer l'entrée actuelle comme lue/non lue"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "Attention"
|
||||
msgid "Website"
|
||||
msgstr "Site web"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "Bienvenue ! Il semble que ce soit le premier démarrage de Commafeed. Avant tout, vous devez créer un compte administrateur."
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Jaune"
|
||||
@@ -1067,3 +1116,7 @@ msgstr "Vous n'avez pas encore d'abonnements. Pourquoi ne pas essayer d'en ajout
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr "Vos flux sont en cours de rafraîchissement"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr "Votre mot de passe a été modifié. Vous pouvez vous connecter avec votre nouveau mot de passe."
|
||||
|
||||
@@ -9,7 +9,7 @@ msgstr ""
|
||||
"Language: gl\n"
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-10-10 07:30+0200\n"
|
||||
"PO-Revision-Date: 2026-02-04 05:30+0200\n"
|
||||
"Last-Translator: José M. <correoxm@disroot.org>\n"
|
||||
"Language-Team: gl\n"
|
||||
"Plural-Forms: \n"
|
||||
@@ -61,6 +61,11 @@ msgstr "Engadir persoa usuaria"
|
||||
msgid "Admin"
|
||||
msgstr "Administración"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr "Identificador de admin"
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -92,7 +97,7 @@ msgstr "Anuncio"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
msgid "API key"
|
||||
msgstr "Chave API"
|
||||
msgstr "Clave API"
|
||||
|
||||
#: src/pages/app/CategoryDetailsPage.tsx
|
||||
msgid "Are you sure you want to delete category <0>{categoryName}</0>?"
|
||||
@@ -108,7 +113,7 @@ msgstr "Tes certeza de querer eliminar a túa conta? Non é posible desfacer a e
|
||||
|
||||
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
||||
msgid "Are you sure you want to mark all entries of <0>{sourceLabel}</0> as read?"
|
||||
msgstr "es certeza de querer marcar todos os artigos de <0>{sourceLabel}</0> como lidos?"
|
||||
msgstr "Tes certeza de querer marcar todos os artigos de <0>{sourceLabel}</0> como lidos?"
|
||||
|
||||
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
||||
msgid "Are you sure you want to mark entries older than {threshold} days of <0>{sourceLabel}</0> as read?"
|
||||
@@ -131,6 +136,7 @@ msgid "Back"
|
||||
msgstr "Volver"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "Volver para iniciar sesión"
|
||||
|
||||
@@ -138,14 +144,14 @@ msgstr "Volver para iniciar sesión"
|
||||
msgid "Blue"
|
||||
msgstr "Azul"
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr "Complemento do navegador"
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr "Complemento para o navegador requerido para Chrome"
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
msgstr "Complemento do navegador"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Browser tab"
|
||||
msgstr "Pestana do navegador"
|
||||
@@ -222,10 +228,19 @@ msgstr "Confirmar"
|
||||
msgid "Confirm password"
|
||||
msgstr "Confirmar contrasinal"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr "Confirmar contrasinal"
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "Acolledor"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr "Crear conta Admin"
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr "Ctrl"
|
||||
@@ -286,7 +301,7 @@ msgstr "Detallado"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Disable \"Pull to refresh\" browser behavior"
|
||||
msgstr ""
|
||||
msgstr "Desactivar comportamento \"Tira para actualizar\" no navegador"
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
@@ -310,6 +325,8 @@ msgstr "Arrastra a ligazón á barra de marcadores"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -477,6 +494,14 @@ msgstr "Na vista ampliada, ao desprazarse polas entradas márcaas como lidas"
|
||||
msgid "Indigo"
|
||||
msgstr "Índigo"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr "Configuración inicial"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr "A ligazón de restablecemento non é válida. Solicita unha nova."
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -620,6 +645,11 @@ msgstr "Nunca"
|
||||
msgid "New password"
|
||||
msgstr "Novo contrasinal"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr "Novo contrasinal"
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "Primeiro o máis recente"
|
||||
@@ -748,6 +778,8 @@ msgid "Parent Category"
|
||||
msgstr "Categoría superior"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -755,11 +787,15 @@ msgstr "Categoría superior"
|
||||
msgid "Password"
|
||||
msgstr "Contrasinal"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr "O contrasinal ten que ter {minimumPasswordLength} caracteres polo menos"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "Recuperación do contrasinal"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Os contrasinais non coinciden"
|
||||
|
||||
@@ -801,6 +837,11 @@ msgstr "Actualizar"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "Non se admiten novas contas nesta instancia de CommaFeed"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr "Restablecer contrasinal"
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr "API REST"
|
||||
@@ -1001,6 +1042,10 @@ msgstr "Decorado"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr "Esta é a túa clave da API. Pode usarse para algunhas operacións da API de só-lectura e concede acceso á API Fever. Usa o formulario da parte inferior da páxina para crear unha nova clave da API"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr "Este axuste pode causar problemas nalgúns navegadores (ex. Safari) ao desprazarse"
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "Cambiar o estado de lectura da entrada actual"
|
||||
@@ -1057,6 +1102,10 @@ msgstr "Aviso"
|
||||
msgid "Website"
|
||||
msgstr "Páxina web"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "Benvida! Semella que é a primeira vez que executas CommaFeed. Para comezar, crea unha conta de administración."
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Amarelo"
|
||||
@@ -1068,3 +1117,7 @@ msgstr "Aínda non tes ningunha subscrición. Por que non engades unha premendo
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr "As túas canles están na cola para ser actualizadas."
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr "O teu contrasinal cambiou. Xa podes acceder coas novas credenciais."
|
||||
|
||||
@@ -60,6 +60,11 @@ msgstr "Felhasználó hozzáadása"
|
||||
msgid "Admin"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "Vissza"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "Vissza a bejelentkezéshez"
|
||||
|
||||
@@ -137,12 +143,12 @@ msgstr "Vissza a bejelentkezéshez"
|
||||
msgid "Blue"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
@@ -221,10 +227,19 @@ msgstr "Erősítse meg"
|
||||
msgid "Confirm password"
|
||||
msgstr "Erősítse meg a jelszót"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "Hangulatos"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr ""
|
||||
@@ -309,6 +324,8 @@ msgstr "Húzza a hivatkozást a könyvjelzősávra"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -476,6 +493,14 @@ msgstr "Kibontott nézetben a bejegyzések görgetése olvasottként jelöli meg
|
||||
msgid "Indigo"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr ""
|
||||
msgid "New password"
|
||||
msgstr "Új jelszó"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "A legújabbak először"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "Szülő kategória"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "Szülő kategória"
|
||||
msgid "Password"
|
||||
msgstr "Jelszó"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "Jelszó helyreállítás"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "A jelszavak nem egyeznek"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "Frissítés"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
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
|
||||
msgid "Reset Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr ""
|
||||
@@ -1000,6 +1041,10 @@ msgstr "Téma"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "Az aktuális bejegyzés olvasási állapotának váltása"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "Figyelem"
|
||||
msgid "Website"
|
||||
msgstr "Webhely"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr ""
|
||||
@@ -1067,3 +1116,7 @@ msgstr "Még nincs előfizetése. "
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
@@ -60,6 +60,11 @@ msgstr "Tambahkan pengguna"
|
||||
msgid "Admin"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "Kembali"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "Kembali untuk masuk"
|
||||
|
||||
@@ -137,12 +143,12 @@ msgstr "Kembali untuk masuk"
|
||||
msgid "Blue"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
@@ -221,10 +227,19 @@ msgstr "Konfirmasi"
|
||||
msgid "Confirm password"
|
||||
msgstr "Konfirmasi kata sandi"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "Nyaman"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr ""
|
||||
@@ -309,6 +324,8 @@ msgstr "Seret tautan ke bilah bookmark"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -476,6 +493,14 @@ msgstr "Dalam tampilan yang diperluas, menggulir entri menandainya sebagai telah
|
||||
msgid "Indigo"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr ""
|
||||
msgid "New password"
|
||||
msgstr "Kata sandi baru"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "Terbaru dulu"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "Kategori Induk"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "Kategori Induk"
|
||||
msgid "Password"
|
||||
msgstr "Kata Sandi"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "Pemulihan Kata Sandi"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Kata sandi tidak cocok"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "Segarkan"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "Pendaftaran ditutup pada instans CommaFeed ini"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr ""
|
||||
@@ -1000,6 +1041,10 @@ msgstr "Tema"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "Beralih status baca entri saat ini"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "Peringatan"
|
||||
msgid "Website"
|
||||
msgstr "Situs Web"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr ""
|
||||
@@ -1067,3 +1116,7 @@ msgstr "Anda belum memiliki langganan. "
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
@@ -60,6 +60,11 @@ msgstr "Aggiungi utente"
|
||||
msgid "Admin"
|
||||
msgstr "Ammin"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "Indietro"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "Torna per accedere"
|
||||
|
||||
@@ -137,12 +143,12 @@ msgstr "Torna per accedere"
|
||||
msgid "Blue"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
@@ -221,10 +227,19 @@ msgstr "Conferma"
|
||||
msgid "Confirm password"
|
||||
msgstr "Conferma password"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "Accogliente"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr "ctrl"
|
||||
@@ -309,6 +324,8 @@ msgstr "Trascina il collegamento sulla barra dei preferiti"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -476,6 +493,14 @@ msgstr "Nella vista espansa, scorrendo le voci contrassegnale come lette"
|
||||
msgid "Indigo"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr ""
|
||||
msgid "New password"
|
||||
msgstr "Nuova password"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "Il più recente prima"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "Categoria padre"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "Categoria padre"
|
||||
msgid "Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "Recupero password"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Le password non corrispondono"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "Aggiorna"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "Le registrazioni sono chiuse su questa istanza CommaFeed"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr "API REST"
|
||||
@@ -1000,6 +1041,10 @@ msgstr "Tema"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "Commuta lo stato di lettura della voce corrente"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "Avviso"
|
||||
msgid "Website"
|
||||
msgstr "Sito web"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr ""
|
||||
@@ -1067,3 +1116,7 @@ msgstr "Non hai ancora abbonamenti. "
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
@@ -60,6 +60,11 @@ msgstr "ユーザー追加"
|
||||
msgid "Admin"
|
||||
msgstr "管理者"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "戻る"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "ログインに戻る"
|
||||
|
||||
@@ -137,14 +143,14 @@ msgstr "ログインに戻る"
|
||||
msgid "Blue"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr "ブラウザー拡張"
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr "Chromeのブラウザー拡張が必要です"
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
msgstr "ブラウザー拡張"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Browser tab"
|
||||
msgstr "ブラウザータブ"
|
||||
@@ -221,10 +227,19 @@ msgstr "確認"
|
||||
msgid "Confirm password"
|
||||
msgstr "パスワード確認"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "Cozy"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr "Ctrl"
|
||||
@@ -309,6 +324,8 @@ msgstr "リンクをブックマークバーにドラッグ"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -476,6 +493,14 @@ msgstr "展開ビューでエントリーをスクロールすると、それら
|
||||
msgid "Indigo"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr "しない"
|
||||
msgid "New password"
|
||||
msgstr "新しいパスワード"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "最新順"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "親カテゴリ"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "親カテゴリ"
|
||||
msgid "Password"
|
||||
msgstr "パスワード"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "パスワード回復"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "パスワードが一致しません"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "リフレッシュ"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "このCommaFeedインスタンスの登録は終了しています"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr "REST API"
|
||||
@@ -1000,6 +1041,10 @@ msgstr "テーマ"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr "これはあなたのAPIキーです。いくつかの読み取り専用API操作に使用できます。これにより、Fever APIへのアクセスが可能になります。ページの下部のフォームを使用して新しいAPIキーを生成します。"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "現在のエントリーの読み取りステータスを切り替えます"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "警告"
|
||||
msgid "Website"
|
||||
msgstr "ウェブサイト"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr ""
|
||||
@@ -1067,3 +1116,7 @@ msgstr "まだサブスクリプションがありません。上部の + 記号
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr "フィードの更新がキューに登録されました。"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
@@ -60,6 +60,11 @@ msgstr "사용자 추가"
|
||||
msgid "Admin"
|
||||
msgstr "관리자"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "뒤로"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "로그인으로 돌아가기"
|
||||
|
||||
@@ -137,12 +143,12 @@ msgstr "로그인으로 돌아가기"
|
||||
msgid "Blue"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
@@ -221,10 +227,19 @@ msgstr "확인"
|
||||
msgid "Confirm password"
|
||||
msgstr "비밀번호 확인"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "코지"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr "컨트롤"
|
||||
@@ -309,6 +324,8 @@ msgstr "링크를 북마크바로 드래그"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -476,6 +493,14 @@ msgstr "확장 보기에서 항목을 스크롤하면 읽은 것으로 표시됩
|
||||
msgid "Indigo"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr ""
|
||||
msgid "New password"
|
||||
msgstr "새 비밀번호"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "최신순"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "부모 카테고리"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "부모 카테고리"
|
||||
msgid "Password"
|
||||
msgstr "비밀번호"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "비밀번호 복구"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "비밀번호가 일치하지 않습니다"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "새로 고침"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "이 CommaFeed 인스턴스에 대한 등록이 마감되었습니다."
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr ""
|
||||
@@ -1000,6 +1041,10 @@ msgstr "테마"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "현재 항목의 읽기 상태 전환"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "경고"
|
||||
msgid "Website"
|
||||
msgstr "웹사이트"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr ""
|
||||
@@ -1067,3 +1116,7 @@ msgstr "아직 구독이 없습니다. "
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
@@ -60,6 +60,11 @@ msgstr "Tambah pengguna"
|
||||
msgid "Admin"
|
||||
msgstr "Pentadbir"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "Kembali"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "Kembali untuk log masuk"
|
||||
|
||||
@@ -137,12 +143,12 @@ msgstr "Kembali untuk log masuk"
|
||||
msgid "Blue"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
@@ -221,10 +227,19 @@ msgstr "Sahkan"
|
||||
msgid "Confirm password"
|
||||
msgstr "Sahkan kata laluan"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "Nyaman"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr ""
|
||||
@@ -309,6 +324,8 @@ msgstr "Seret pautan ke bar penanda halaman"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -476,6 +493,14 @@ msgstr "Dalam paparan yang diperluas, menatal melalui entri menandakannya sebaga
|
||||
msgid "Indigo"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr ""
|
||||
msgid "New password"
|
||||
msgstr "Kata laluan baharu"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "Terbaharu dahulu"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "Kategori Induk"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "Kategori Induk"
|
||||
msgid "Password"
|
||||
msgstr "Kata Laluan"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "Pemulihan Kata Laluan"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Kata laluan tidak sepadan"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "Muat semula"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "Pendaftaran ditutup pada contoh CommaFeed ini"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr "REHAT API"
|
||||
@@ -1000,6 +1041,10 @@ msgstr "Tema"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "Togol status bacaan entri semasa"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "Amaran"
|
||||
msgid "Website"
|
||||
msgstr "Laman web"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr ""
|
||||
@@ -1067,3 +1116,7 @@ msgstr "Anda belum mempunyai sebarang langganan lagi. "
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
@@ -60,6 +60,11 @@ msgstr "Legg til bruker"
|
||||
msgid "Admin"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "Tilbake"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "Tilbake for å logge inn"
|
||||
|
||||
@@ -137,12 +143,12 @@ msgstr "Tilbake for å logge inn"
|
||||
msgid "Blue"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
@@ -221,10 +227,19 @@ msgstr "Bekreft"
|
||||
msgid "Confirm password"
|
||||
msgstr "Bekreft passord"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "Koselig"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr ""
|
||||
@@ -309,6 +324,8 @@ msgstr "Dra lenken til bokmerkelinjen"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -476,6 +493,14 @@ msgstr "I utvidet visning merker du dem som lest ved å rulle gjennom oppføring
|
||||
msgid "Indigo"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr ""
|
||||
msgid "New password"
|
||||
msgstr "Nytt passord"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "Nyeste først"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "Overordnet kategori"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "Overordnet kategori"
|
||||
msgid "Password"
|
||||
msgstr "Passord"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "Passordgjenoppretting"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Passordene samsvarer ikke"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "Oppdater"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "Registreringer er stengt på denne CommaFeed-forekomsten"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr ""
|
||||
@@ -1000,6 +1041,10 @@ msgstr "Tema"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "Veksle lesestatus for gjeldende oppføring"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "Advarsel"
|
||||
msgid "Website"
|
||||
msgstr "Nettsted"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr ""
|
||||
@@ -1067,3 +1116,7 @@ msgstr "Du har ingen abonnementer ennå. "
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
@@ -60,6 +60,11 @@ msgstr "Gebruiker toevoegen"
|
||||
msgid "Admin"
|
||||
msgstr "Beheerder"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "Terug"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "Terug naar inloggen"
|
||||
|
||||
@@ -137,12 +143,12 @@ msgstr "Terug naar inloggen"
|
||||
msgid "Blue"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
@@ -221,10 +227,19 @@ msgstr "Bevestigen"
|
||||
msgid "Confirm password"
|
||||
msgstr "Bevestig wachtwoord"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "Gezellig"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr ""
|
||||
@@ -309,6 +324,8 @@ msgstr "Link naar bladwijzerbalk slepen"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -476,6 +493,14 @@ msgstr "In de uitgevouwen weergave markeert het scrollen door items ze als gelez
|
||||
msgid "Indigo"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr ""
|
||||
msgid "New password"
|
||||
msgstr "Nieuw wachtwoord"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "Nieuwste eerst"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "Oudercategorie"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "Oudercategorie"
|
||||
msgid "Password"
|
||||
msgstr "Wachtwoord"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "Wachtwoordherstel"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Wachtwoorden komen niet overeen"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "Vernieuwen"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "Registraties zijn gesloten op deze CommaFeed-instantie"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr "REST-API"
|
||||
@@ -1000,6 +1041,10 @@ msgstr "Thema"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "Toggle leesstatus van huidige invoer"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "Waarschuwing"
|
||||
msgid "Website"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr ""
|
||||
@@ -1067,3 +1116,7 @@ msgstr "Je hebt nog geen abonnementen. "
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
@@ -60,6 +60,11 @@ msgstr "Legg til bruker"
|
||||
msgid "Admin"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "Tilbake"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "Tilbake for å logge inn"
|
||||
|
||||
@@ -137,12 +143,12 @@ msgstr "Tilbake for å logge inn"
|
||||
msgid "Blue"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
@@ -221,10 +227,19 @@ msgstr "Bekreft"
|
||||
msgid "Confirm password"
|
||||
msgstr "Bekreft passord"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "Koselig"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr ""
|
||||
@@ -309,6 +324,8 @@ msgstr "Dra lenken til bokmerkelinjen"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -476,6 +493,14 @@ msgstr "I utvidet visning merker du dem som lest ved å rulle gjennom oppføring
|
||||
msgid "Indigo"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr ""
|
||||
msgid "New password"
|
||||
msgstr "Nytt passord"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "Nyeste først"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "Overordnet kategori"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "Overordnet kategori"
|
||||
msgid "Password"
|
||||
msgstr "Passord"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "Passordgjenoppretting"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Passordene samsvarer ikke"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "Oppdater"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "Registreringer er stengt på denne CommaFeed-forekomsten"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr ""
|
||||
@@ -1000,6 +1041,10 @@ msgstr "Tema"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "Veksle lesestatus for gjeldende oppføring"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "Advarsel"
|
||||
msgid "Website"
|
||||
msgstr "Nettsted"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr ""
|
||||
@@ -1067,3 +1116,7 @@ msgstr "Du har ingen abonnementer ennå. "
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
@@ -60,6 +60,11 @@ msgstr "Dodaj użytkownika"
|
||||
msgid "Admin"
|
||||
msgstr "Administracja"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "Powrót"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "Powrót do logowania"
|
||||
|
||||
@@ -137,12 +143,12 @@ msgstr "Powrót do logowania"
|
||||
msgid "Blue"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
@@ -221,10 +227,19 @@ msgstr "Potwierdź"
|
||||
msgid "Confirm password"
|
||||
msgstr "Potwierdź hasło"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "Przytulny"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr ""
|
||||
@@ -309,6 +324,8 @@ msgstr "Przeciągnij link do paska zakładek"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -476,6 +493,14 @@ msgstr "W widoku rozszerzonym przewijanie wpisów oznacza je jako przeczytane"
|
||||
msgid "Indigo"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr ""
|
||||
msgid "New password"
|
||||
msgstr "Nowe hasło"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "Najnowsze jako pierwsze"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "Kategoria nadrzędna"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "Kategoria nadrzędna"
|
||||
msgid "Password"
|
||||
msgstr "Hasło"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "Odzyskiwanie hasła"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Hasła nie pasują"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "Odśwież"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "Rejestracje są zamknięte w tej instancji CommaFeed"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr ""
|
||||
@@ -1000,6 +1041,10 @@ msgstr "Motyw"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "Przełącz stan odczytu bieżącego wpisu"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "Ostrzeżenie"
|
||||
msgid "Website"
|
||||
msgstr "Strona internetowa"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr ""
|
||||
@@ -1067,3 +1116,7 @@ msgstr "Nie masz jeszcze żadnych subskrypcji. "
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
@@ -60,6 +60,11 @@ msgstr "Adicionar usuário"
|
||||
msgid "Admin"
|
||||
msgstr "Administrador"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "Voltar"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "Voltar para logar"
|
||||
|
||||
@@ -137,14 +143,14 @@ msgstr "Voltar para logar"
|
||||
msgid "Blue"
|
||||
msgstr "Azul"
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr "Extensão do navegador"
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr "Extensão para o Chrome necessária"
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
msgstr "Extensão do navegador"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Browser tab"
|
||||
msgstr "Aba do navegador"
|
||||
@@ -221,10 +227,19 @@ msgstr "Confirmar"
|
||||
msgid "Confirm password"
|
||||
msgstr "Confirmar senha"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "Aconchegante"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr "Ctrl"
|
||||
@@ -309,6 +324,8 @@ msgstr "Arraste o link para a barra de favoritos"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -476,6 +493,14 @@ msgstr "Na visualização expandida, rolar pelas entradas marca-as como lidas"
|
||||
msgid "Indigo"
|
||||
msgstr "Índigo"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr "Nunca"
|
||||
msgid "New password"
|
||||
msgstr "Nova senha"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "Mais novo primeiro"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "Categoria Pai"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "Categoria Pai"
|
||||
msgid "Password"
|
||||
msgstr "Senha"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "Recuperação de Senha"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Senhas não coincidem"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "Atualizar"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "Os registros estão fechados nesta instância do CommaFeed"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr "API REST"
|
||||
@@ -1000,6 +1041,10 @@ msgstr "Tema"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr "Esta é sua chave de API. Ela pode ser usada para algumas operações somente leitura da API e concede acesso à API do Fever. Use o formulário abaixo para gerar uma nova chave de API"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "Alternar o status de leitura da entrada atual"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "Aviso"
|
||||
msgid "Website"
|
||||
msgstr "Site"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "Amarelo"
|
||||
@@ -1067,3 +1116,7 @@ msgstr "Você ainda não tem nenhuma assinatura. "
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr "Seus feed foram enfileirados para atualização"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
@@ -60,6 +60,11 @@ msgstr "Добавить пользователя"
|
||||
msgid "Admin"
|
||||
msgstr "Админ"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "Назад"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "Вернуться к входу"
|
||||
|
||||
@@ -137,14 +143,14 @@ msgstr "Вернуться к входу"
|
||||
msgid "Blue"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr "Расширение для браузера"
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr "Для браузера Chrome требуется расширение"
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
msgstr "Расширение для браузера"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Browser tab"
|
||||
msgstr ""
|
||||
@@ -221,10 +227,19 @@ msgstr "Подтвердить"
|
||||
msgid "Confirm password"
|
||||
msgstr "Подтвердить пароль"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "Уютно"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr "Ctrl"
|
||||
@@ -309,6 +324,8 @@ msgstr "Перетащите ссылку на панель закладок"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -476,6 +493,14 @@ msgstr "В развернутом виде прокрутка записей п
|
||||
msgid "Indigo"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr "Никогда"
|
||||
msgid "New password"
|
||||
msgstr "Новый пароль"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "Сначала новые"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "Родительская категория"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "Родительская категория"
|
||||
msgid "Password"
|
||||
msgstr "Пароль"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "Восстановление пароля"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Пароли не совпадают"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "Обновить"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "Регистрация закрыта для этого экземпляра CommaFeed."
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr "REST API"
|
||||
@@ -1000,6 +1041,10 @@ msgstr "Тема"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr "Это ваш ключ API. Он может использоваться для некоторых операций API только для чтения и предоставляет доступ к API Fever. Чтобы сгенерировать новый ключ API, воспользуйтесь формой в нижней части страницы"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "Переключить статус чтения текущей записи"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "Предупреждение"
|
||||
msgid "Website"
|
||||
msgstr "Веб-сайт"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr ""
|
||||
@@ -1067,3 +1116,7 @@ msgstr "У вас еще нет подписок. Почему бы не поп
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr "Ваши каналы были поставлены в очередь на обновление."
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
@@ -60,6 +60,11 @@ msgstr "Pridať užívateľa"
|
||||
msgid "Admin"
|
||||
msgstr "Správca"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "Späť"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "Späť na prihlásenie"
|
||||
|
||||
@@ -137,12 +143,12 @@ msgstr "Späť na prihlásenie"
|
||||
msgid "Blue"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
@@ -221,10 +227,19 @@ msgstr "Potvrdiť"
|
||||
msgid "Confirm password"
|
||||
msgstr "Potvrďte heslo"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "Útulný"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr ""
|
||||
@@ -309,6 +324,8 @@ msgstr "Presuňte odkaz na lištu so záložkami"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -476,6 +493,14 @@ msgstr "V rozšírenom zobrazení ich rolovanie cez položky označí ako preč
|
||||
msgid "Indigo"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr ""
|
||||
msgid "New password"
|
||||
msgstr "Nové heslo"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "Najnovšie ako prvé"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "Rodičovská kategória"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "Rodičovská kategória"
|
||||
msgid "Password"
|
||||
msgstr "Heslo"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "Obnovenie hesla"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Heslá sa nezhodujú"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "Obnoviť"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "V tejto inštancii CommaFeed sú registrácie uzavreté"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr ""
|
||||
@@ -1000,6 +1041,10 @@ msgstr "Téma"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "Prepne stav čítania aktuálneho záznamu"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "Varovanie"
|
||||
msgid "Website"
|
||||
msgstr "Webová stránka"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr ""
|
||||
@@ -1067,3 +1116,7 @@ msgstr "Zatiaľ nemáte žiadne odbery. "
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
@@ -60,6 +60,11 @@ msgstr "Lägg till användare"
|
||||
msgid "Admin"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "Tillbaka"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "Tillbaka för att logga in"
|
||||
|
||||
@@ -137,12 +143,12 @@ msgstr "Tillbaka för att logga in"
|
||||
msgid "Blue"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
@@ -221,10 +227,19 @@ msgstr "Bekräfta"
|
||||
msgid "Confirm password"
|
||||
msgstr "Bekräfta lösenord"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "Mysigt"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr ""
|
||||
@@ -309,6 +324,8 @@ msgstr "Dra länken till bokmärkesfältet"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -476,6 +493,14 @@ msgstr "I utökad vy, rullning genom poster markerar dem som lästa"
|
||||
msgid "Indigo"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr ""
|
||||
msgid "New password"
|
||||
msgstr "Nytt lösenord"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "Nyast först"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "Föräldrakategori"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "Föräldrakategori"
|
||||
msgid "Password"
|
||||
msgstr "Lösenord"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "Lösenordsåterställning"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Lösenorden matchar inte"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "Uppdatera"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "Registreringar är stängda på denna CommaFeed-instans"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr ""
|
||||
@@ -1000,6 +1041,10 @@ msgstr "Tema"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "Växla lässtatus för aktuell post"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "Varning"
|
||||
msgid "Website"
|
||||
msgstr "Webbplats"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr ""
|
||||
@@ -1067,3 +1116,7 @@ msgstr "Du har inga prenumerationer än. "
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
@@ -60,6 +60,11 @@ msgstr "Kullanıcı ekle"
|
||||
msgid "Admin"
|
||||
msgstr "Yönetici"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "Geri"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "Giriş yapmak için geri dön"
|
||||
|
||||
@@ -137,14 +143,14 @@ msgstr "Giriş yapmak için geri dön"
|
||||
msgid "Blue"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr "Tarayıcı eklentisi"
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
msgstr "Tarayıcı eklentisi"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Browser tab"
|
||||
msgstr ""
|
||||
@@ -221,10 +227,19 @@ msgstr "Onayla"
|
||||
msgid "Confirm password"
|
||||
msgstr "Şifreyi onayla"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "Rahat"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr "Ctrl"
|
||||
@@ -309,6 +324,8 @@ msgstr "Bağlantıyı yer işareti çubuğuna sürükleyin"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -476,6 +493,14 @@ msgstr "Genişletilmiş görünümde, girişler arasında gezinmek onları okund
|
||||
msgid "Indigo"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr ""
|
||||
msgid "New password"
|
||||
msgstr "Yeni şifre"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "Önce en yenisi"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "Üst Kategori"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "Üst Kategori"
|
||||
msgid "Password"
|
||||
msgstr "Şifre"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "Parola Kurtarma"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Parolalar eşleşmiyor"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "Yenile"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "Bu CommaFeed örneğinde kayıtlar kapalı"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr "REST API"
|
||||
@@ -1000,6 +1041,10 @@ msgstr "Tema"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr ""
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "Geçerli girişin okuma durumunu değiştir"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "Uyarı"
|
||||
msgid "Website"
|
||||
msgstr "Web sitesi"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr ""
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr ""
|
||||
@@ -1067,3 +1116,7 @@ msgstr "Henüz aboneliğiniz yok. Sayfanın üstündeki + işaretiyle feed ekley
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr "Feed'leriniz yenileme için sıraya alındı."
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr ""
|
||||
|
||||
@@ -60,6 +60,11 @@ msgstr "添加用户"
|
||||
msgid "Admin"
|
||||
msgstr "管理员"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Admin user name"
|
||||
msgstr "管理员用户名"
|
||||
|
||||
#: src/components/content/add/CategorySelect.tsx
|
||||
#: src/components/header/Header.tsx
|
||||
#: src/components/sidebar/Tree.tsx
|
||||
@@ -130,6 +135,7 @@ msgid "Back"
|
||||
msgstr "返回"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Back to log in"
|
||||
msgstr "返回登录"
|
||||
|
||||
@@ -137,12 +143,12 @@ msgstr "返回登录"
|
||||
msgid "Blue"
|
||||
msgstr "蓝"
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extension"
|
||||
msgstr "浏览器扩展"
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Browser extention"
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Browser extension required for Chrome"
|
||||
msgstr "浏览器扩展"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
@@ -221,10 +227,19 @@ msgstr "确认"
|
||||
msgid "Confirm password"
|
||||
msgstr "确认密码"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Confirm Password"
|
||||
msgstr "确认密码"
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Cozy"
|
||||
msgstr "宽松"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Create Admin Account"
|
||||
msgstr "创建管理员帐号"
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Ctrl"
|
||||
msgstr "Ctrl"
|
||||
@@ -285,7 +300,7 @@ msgstr "详细"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Disable \"Pull to refresh\" browser behavior"
|
||||
msgstr ""
|
||||
msgstr "禁用浏览器的“下拉刷新”功能"
|
||||
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
@@ -309,6 +324,8 @@ msgstr "拖动链接到书签栏"
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/pages/admin/AdminUsersPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "E-mail"
|
||||
@@ -476,6 +493,14 @@ msgstr "在展开视图中,滚动条目将它们标记为已读"
|
||||
msgid "Indigo"
|
||||
msgstr "靛蓝"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Initial Setup"
|
||||
msgstr "初始化设置"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Invalid password reset link. Please request a new one."
|
||||
msgstr "密码重置链接无效,请重新申请。"
|
||||
|
||||
#: src/components/content/FeedEntryContextMenu.tsx
|
||||
#: src/components/content/FeedEntryFooter.tsx
|
||||
msgid "Keep unread"
|
||||
@@ -619,6 +644,11 @@ msgstr "从不"
|
||||
msgid "New password"
|
||||
msgstr "新密码"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "New Password"
|
||||
msgstr "新密码"
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "Newest first"
|
||||
msgstr "最新的优先"
|
||||
@@ -747,6 +777,8 @@ msgid "Parent Category"
|
||||
msgstr "父类别"
|
||||
|
||||
#: src/components/admin/UserEdit.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/LoginPage.tsx
|
||||
#: src/pages/auth/RegistrationPage.tsx
|
||||
@@ -754,11 +786,15 @@ msgstr "父类别"
|
||||
msgid "Password"
|
||||
msgstr "密码"
|
||||
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||
msgstr "密码最少需要 {minimumPasswordLength} 个字符"
|
||||
|
||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||
msgid "Password Recovery"
|
||||
msgstr "密码恢复"
|
||||
|
||||
#: src/components/settings/ProfileSettings.tsx
|
||||
#: src/hooks/useValidationRules.ts
|
||||
msgid "Passwords do not match"
|
||||
msgstr "密码不匹配"
|
||||
|
||||
@@ -800,6 +836,11 @@ msgstr "刷新"
|
||||
msgid "Registrations are closed on this CommaFeed instance"
|
||||
msgstr "此 CommaFeed 实例上的注册已关闭"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Reset Password"
|
||||
msgstr "重置密码"
|
||||
|
||||
#: src/pages/app/AboutPage.tsx
|
||||
msgid "REST API"
|
||||
msgstr "REST API"
|
||||
@@ -1000,6 +1041,10 @@ msgstr "主题"
|
||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||
msgstr "这是您的API 密钥,它可以被用于Fever API的只读操作及访问授权。使用页面底部的表单生成一个新的API密钥。"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||
msgstr "此设置在部分浏览器(例如 Safari)中可能导致滚动问题"
|
||||
|
||||
#: src/components/KeyboardShortcutsHelp.tsx
|
||||
msgid "Toggle read status of current entry"
|
||||
msgstr "切换当前条目的阅读状态"
|
||||
@@ -1056,6 +1101,10 @@ msgstr "警告"
|
||||
msgid "Website"
|
||||
msgstr "网站"
|
||||
|
||||
#: src/pages/auth/InitialSetupPage.tsx
|
||||
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||
msgstr "欢迎!当前页仅当您第一次使用CommaFeed时出现,请创建一个管理员帐号以开始使用。"
|
||||
|
||||
#: src/components/settings/DisplaySettings.tsx
|
||||
msgid "Yellow"
|
||||
msgstr "黄"
|
||||
@@ -1067,3 +1116,7 @@ msgstr "您还没有任何订阅。"
|
||||
#: src/components/header/ProfileMenu.tsx
|
||||
msgid "Your feeds have been queued for refresh."
|
||||
msgstr "您的订阅已经进入刷新队列。"
|
||||
|
||||
#: src/pages/auth/PasswordResetPage.tsx
|
||||
msgid "Your password has been changed. You can now log in with your new password."
|
||||
msgstr "您的密码已更改。您现在可以使用新密码登录。"
|
||||
|
||||
@@ -107,7 +107,7 @@ export function AboutPage() {
|
||||
<List>
|
||||
<List.Item>
|
||||
<Anchor href={Constants.browserExtensionUrl} target="_blank" rel="noreferrer">
|
||||
<Trans>Browser extention</Trans>
|
||||
<Trans>Browser extension</Trans>
|
||||
</Anchor>
|
||||
</List.Item>
|
||||
<List.Item>
|
||||
|
||||
95
commafeed-client/src/pages/auth/InitialSetupPage.tsx
Normal file
95
commafeed-client/src/pages/auth/InitialSetupPage.tsx
Normal file
@@ -0,0 +1,95 @@
|
||||
import { msg } from "@lingui/core/macro"
|
||||
import { useLingui } from "@lingui/react"
|
||||
import { Trans } from "@lingui/react/macro"
|
||||
import { Box, Button, Container, Paper, PasswordInput, Stack, TextInput, Title } from "@mantine/core"
|
||||
import { useForm } from "@mantine/form"
|
||||
import { useAsyncCallback } from "react-async-hook"
|
||||
import { client, errorToStrings } from "@/app/client"
|
||||
import { redirectToRootCategory } from "@/app/redirect/thunks"
|
||||
import { useAppDispatch } from "@/app/store"
|
||||
import type { InitialSetupRequest } from "@/app/types"
|
||||
import { Alert } from "@/components/Alert"
|
||||
import { useValidationRules } from "@/hooks/useValidationRules"
|
||||
import { PageTitle } from "@/pages/PageTitle"
|
||||
|
||||
export function InitialSetupPage() {
|
||||
const dispatch = useAppDispatch()
|
||||
const { _ } = useLingui()
|
||||
const validationRules = useValidationRules()
|
||||
|
||||
const form = useForm<InitialSetupRequest>({
|
||||
initialValues: {
|
||||
name: "",
|
||||
password: "",
|
||||
email: "",
|
||||
},
|
||||
validate: {
|
||||
password: validationRules.password,
|
||||
},
|
||||
validateInputOnChange: true,
|
||||
})
|
||||
|
||||
const login = useAsyncCallback(client.user.login, {
|
||||
onSuccess: () => {
|
||||
dispatch(redirectToRootCategory())
|
||||
},
|
||||
})
|
||||
|
||||
const setup = useAsyncCallback(client.user.initialSetup, {
|
||||
onSuccess: () => {
|
||||
login.execute(form.values)
|
||||
},
|
||||
})
|
||||
|
||||
return (
|
||||
<Container size="xs">
|
||||
<PageTitle />
|
||||
<Paper>
|
||||
<Title order={2} mb="md">
|
||||
<Trans>Initial Setup</Trans>
|
||||
</Title>
|
||||
<Box mb="md">
|
||||
<Trans>
|
||||
Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get
|
||||
started.
|
||||
</Trans>
|
||||
</Box>
|
||||
{setup.error && (
|
||||
<Box mb="md">
|
||||
<Alert messages={errorToStrings(setup.error)} />
|
||||
</Box>
|
||||
)}
|
||||
<form onSubmit={form.onSubmit(setup.execute)}>
|
||||
<Stack>
|
||||
<TextInput
|
||||
label={<Trans>Admin user name</Trans>}
|
||||
placeholder={_(msg`Admin user name`)}
|
||||
{...form.getInputProps("name")}
|
||||
size="md"
|
||||
required
|
||||
autoCapitalize="off"
|
||||
/>
|
||||
<PasswordInput
|
||||
label={<Trans>Password</Trans>}
|
||||
placeholder={_(msg`Password`)}
|
||||
{...form.getInputProps("password")}
|
||||
size="md"
|
||||
required
|
||||
/>
|
||||
<TextInput
|
||||
type="email"
|
||||
label={<Trans>E-mail</Trans>}
|
||||
placeholder={_(msg`E-mail`)}
|
||||
{...form.getInputProps("email")}
|
||||
size="md"
|
||||
/>
|
||||
|
||||
<Button type="submit" loading={setup.loading}>
|
||||
<Trans>Create Admin Account</Trans>
|
||||
</Button>
|
||||
</Stack>
|
||||
</form>
|
||||
</Paper>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
119
commafeed-client/src/pages/auth/PasswordResetPage.tsx
Normal file
119
commafeed-client/src/pages/auth/PasswordResetPage.tsx
Normal file
@@ -0,0 +1,119 @@
|
||||
import { msg } from "@lingui/core/macro"
|
||||
import { useLingui } from "@lingui/react"
|
||||
import { Trans } from "@lingui/react/macro"
|
||||
import { Anchor, Box, Button, Center, Container, Group, Paper, PasswordInput, Stack, Title } from "@mantine/core"
|
||||
import { useForm } from "@mantine/form"
|
||||
import { useState } from "react"
|
||||
import { useAsyncCallback } from "react-async-hook"
|
||||
import { Link, useSearchParams } from "react-router-dom"
|
||||
import { client, errorToStrings } from "@/app/client"
|
||||
import { Alert } from "@/components/Alert"
|
||||
import { useValidationRules } from "@/hooks/useValidationRules"
|
||||
import { PageTitle } from "@/pages/PageTitle"
|
||||
|
||||
interface PasswordResetFormValues {
|
||||
password: string
|
||||
passwordConfirmation: string
|
||||
}
|
||||
|
||||
export function PasswordResetPage() {
|
||||
const [message, setMessage] = useState("")
|
||||
const [searchParams] = useSearchParams()
|
||||
const { _ } = useLingui()
|
||||
const validationRules = useValidationRules()
|
||||
|
||||
const email = searchParams.get("email") ?? ""
|
||||
const token = searchParams.get("token") ?? ""
|
||||
|
||||
const form = useForm<PasswordResetFormValues>({
|
||||
initialValues: {
|
||||
password: "",
|
||||
passwordConfirmation: "",
|
||||
},
|
||||
validate: {
|
||||
password: validationRules.password,
|
||||
passwordConfirmation: (value, values) => validationRules.passwordConfirmation(value, values.password),
|
||||
},
|
||||
validateInputOnChange: true,
|
||||
})
|
||||
|
||||
const resetPassword = useAsyncCallback(client.user.passwordResetCallback, {
|
||||
onSuccess: () => {
|
||||
setMessage(_(msg`Your password has been changed. You can now log in with your new password.`))
|
||||
form.reset()
|
||||
},
|
||||
})
|
||||
|
||||
const isMissingParams = !email || !token
|
||||
|
||||
return (
|
||||
<Container size="xs">
|
||||
<PageTitle />
|
||||
<Paper>
|
||||
<Title order={2} mb="md">
|
||||
<Trans>Reset Password</Trans>
|
||||
</Title>
|
||||
|
||||
{resetPassword.error && (
|
||||
<Box mb="md">
|
||||
<Alert messages={errorToStrings(resetPassword.error)} />
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{isMissingParams && (
|
||||
<Box mb="md">
|
||||
<Alert messages={[_(msg`Invalid password reset link. Please request a new one.`)]} />
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{message && (
|
||||
<Box mb="md">
|
||||
<Alert level="success" messages={[message]} />
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{!isMissingParams && !message && (
|
||||
<form
|
||||
onSubmit={form.onSubmit(values => {
|
||||
resetPassword.execute({
|
||||
email,
|
||||
token,
|
||||
password: values.password,
|
||||
})
|
||||
})}
|
||||
>
|
||||
<Stack>
|
||||
<PasswordInput
|
||||
label={<Trans>New Password</Trans>}
|
||||
placeholder={_(msg`New Password`)}
|
||||
{...form.getInputProps("password")}
|
||||
size="md"
|
||||
required
|
||||
/>
|
||||
|
||||
<PasswordInput
|
||||
label={<Trans>Confirm Password</Trans>}
|
||||
placeholder={_(msg`Confirm Password`)}
|
||||
{...form.getInputProps("passwordConfirmation")}
|
||||
size="md"
|
||||
required
|
||||
/>
|
||||
|
||||
<Button type="submit" loading={resetPassword.loading}>
|
||||
<Trans>Reset Password</Trans>
|
||||
</Button>
|
||||
</Stack>
|
||||
</form>
|
||||
)}
|
||||
|
||||
<Center mt="md">
|
||||
<Group>
|
||||
<Anchor component={Link} to="/login">
|
||||
<Trans>Back to log in</Trans>
|
||||
</Anchor>
|
||||
</Group>
|
||||
</Center>
|
||||
</Paper>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
@@ -10,12 +10,14 @@ import { redirectToRootCategory } from "@/app/redirect/thunks"
|
||||
import { useAppDispatch, useAppSelector } from "@/app/store"
|
||||
import type { RegistrationRequest } from "@/app/types"
|
||||
import { Alert } from "@/components/Alert"
|
||||
import { useValidationRules } from "@/hooks/useValidationRules"
|
||||
import { PageTitle } from "@/pages/PageTitle"
|
||||
|
||||
export function RegistrationPage() {
|
||||
const serverInfos = useAppSelector(state => state.server.serverInfos)
|
||||
const dispatch = useAppDispatch()
|
||||
const { _ } = useLingui()
|
||||
const validationRules = useValidationRules()
|
||||
|
||||
const form = useForm<RegistrationRequest>({
|
||||
initialValues: {
|
||||
@@ -23,6 +25,10 @@ export function RegistrationPage() {
|
||||
password: "",
|
||||
email: "",
|
||||
},
|
||||
validate: {
|
||||
password: validationRules.password,
|
||||
},
|
||||
validateInputOnChange: true,
|
||||
})
|
||||
|
||||
const login = useAsyncCallback(client.user.login, {
|
||||
@@ -72,7 +78,7 @@ export function RegistrationPage() {
|
||||
placeholder={_(msg`E-mail address`)}
|
||||
{...form.getInputProps("email")}
|
||||
size="md"
|
||||
required
|
||||
required={serverInfos.emailAddressRequired}
|
||||
/>
|
||||
<PasswordInput
|
||||
label={<Trans>Password</Trans>}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { lingui } from "@lingui/vite-plugin"
|
||||
import react from "@vitejs/plugin-react"
|
||||
import { visualizer } from "rollup-plugin-visualizer"
|
||||
import { defineConfig } from "vite"
|
||||
import checker from "vite-plugin-checker"
|
||||
import tsconfigPaths from "vite-tsconfig-paths"
|
||||
@@ -21,7 +20,6 @@ export default defineConfig(() => ({
|
||||
}),
|
||||
lingui(),
|
||||
tsconfigPaths(),
|
||||
visualizer(),
|
||||
checker({
|
||||
typescript: true,
|
||||
biome: {
|
||||
|
||||
@@ -6,13 +6,14 @@
|
||||
<parent>
|
||||
<groupId>com.commafeed</groupId>
|
||||
<artifactId>commafeed</artifactId>
|
||||
<version>5.12.0</version>
|
||||
<version>6.2.0</version>
|
||||
</parent>
|
||||
<artifactId>commafeed-server</artifactId>
|
||||
<name>CommaFeed Server</name>
|
||||
<packaging>quarkus</packaging>
|
||||
|
||||
<properties>
|
||||
<quarkus.version>3.29.4</quarkus.version>
|
||||
<quarkus.version>3.31.2</quarkus.version>
|
||||
<querydsl.version>7.1</querydsl.version>
|
||||
<rome.version>2.1.0</rome.version>
|
||||
|
||||
@@ -55,7 +56,7 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>properties-maven-plugin</artifactId>
|
||||
<version>1.2.1</version>
|
||||
<version>1.3.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
@@ -77,24 +78,14 @@
|
||||
<artifactId>quarkus-maven-plugin</artifactId>
|
||||
<version>${quarkus.version}</version>
|
||||
<extensions>true</extensions>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>build</goal>
|
||||
<goal>generate-code</goal>
|
||||
<goal>generate-code-tests</goal>
|
||||
<goal>native-image-agent</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<properties>
|
||||
<quarkus.package.output-name>commafeed-${project.version}</quarkus.package.output-name>
|
||||
<quarkus.package.runner-suffix>
|
||||
-${build.database}-${os.detected.name}-${os.detected.arch}-runner
|
||||
</quarkus.package.runner-suffix>
|
||||
</properties>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<properties>
|
||||
<quarkus.package.output-name>commafeed-${project.version}</quarkus.package.output-name>
|
||||
<quarkus.package.runner-suffix>
|
||||
-${build.database}-${os.detected.name}-${os.detected.arch}-runner
|
||||
</quarkus.package.runner-suffix>
|
||||
</properties>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>io.quarkus</groupId>
|
||||
@@ -117,7 +108,7 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>3.6.2</version>
|
||||
<version>3.6.3</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
@@ -145,7 +136,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.7.1</version>
|
||||
<version>3.8.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
@@ -167,6 +158,7 @@
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.5.4</version>
|
||||
<configuration>
|
||||
<argLine>@{argLine}</argLine>
|
||||
<systemPropertyVariables>
|
||||
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
|
||||
<quarkus.datasource.db-kind>${build.database}</quarkus.datasource.db-kind>
|
||||
@@ -186,6 +178,7 @@
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<argLine>@{argLine}</argLine>
|
||||
<systemPropertyVariables>
|
||||
<native.image.path>${project.build.directory}/${project.build.finalName}-runner
|
||||
</native.image.path>
|
||||
@@ -217,61 +210,6 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>0.8.14</version>
|
||||
<configuration>
|
||||
<!-- excluding SACParserCSS21TokenManager because it causes a "Method too large" exception -->
|
||||
<excludes>
|
||||
<exclude>com/steadystate/css/parser/SACParserCSS21TokenManager</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>unit-tests-agent</id>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<destFile>${project.build.directory}/jacoco-output/jacoco-unit-tests.exec</destFile>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>integration-tests-agent</id>
|
||||
<goals>
|
||||
<goal>prepare-agent-integration</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<destFile>${project.build.directory}/jacoco-output/jacoco-integration-tests.exec</destFile>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>merge</id>
|
||||
<phase>post-integration-test</phase>
|
||||
<goals>
|
||||
<goal>merge</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>${project.build.directory}/jacoco-output</directory>
|
||||
<includes>
|
||||
<include>*.exec</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>generate-code-coverage-report</id>
|
||||
<phase>post-integration-test</phase>
|
||||
<goals>
|
||||
<goal>report</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>io.github.git-commit-id</groupId>
|
||||
<artifactId>git-commit-id-maven-plugin</artifactId>
|
||||
@@ -299,7 +237,7 @@
|
||||
<dependency>
|
||||
<groupId>com.puppycrawl.tools</groupId>
|
||||
<artifactId>checkstyle</artifactId>
|
||||
<version>12.1.2</version>
|
||||
<version>13.2.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<executions>
|
||||
@@ -328,7 +266,7 @@
|
||||
<plugin>
|
||||
<groupId>com.diffplug.spotless</groupId>
|
||||
<artifactId>spotless-maven-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<version>3.2.1</version>
|
||||
<?m2e ignore?>
|
||||
<executions>
|
||||
<execution>
|
||||
@@ -357,7 +295,7 @@
|
||||
<dependency>
|
||||
<groupId>com.commafeed</groupId>
|
||||
<artifactId>commafeed-client</artifactId>
|
||||
<version>5.12.0</version>
|
||||
<version>6.2.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- compile-time processors -->
|
||||
@@ -425,7 +363,7 @@
|
||||
<dependency>
|
||||
<groupId>io.dropwizard.metrics</groupId>
|
||||
<artifactId>metrics-json</artifactId>
|
||||
<version>4.2.37</version>
|
||||
<version>4.2.38</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign.querydsl</groupId>
|
||||
@@ -492,12 +430,12 @@
|
||||
<dependency>
|
||||
<groupId>org.jsoup</groupId>
|
||||
<artifactId>jsoup</artifactId>
|
||||
<version>1.21.2</version>
|
||||
<version>1.22.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.ibm.icu</groupId>
|
||||
<artifactId>icu4j</artifactId>
|
||||
<version>78.1</version>
|
||||
<version>78.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.cssparser</groupId>
|
||||
@@ -512,35 +450,29 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents.client5</groupId>
|
||||
<artifactId>httpclient5</artifactId>
|
||||
<version>5.5.1</version>
|
||||
<version>5.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.hakky54</groupId>
|
||||
<artifactId>ayza-for-apache5</artifactId>
|
||||
<version>10.0.3</version>
|
||||
</dependency>
|
||||
<!-- add brotli support for httpclient5 -->
|
||||
<dependency>
|
||||
<groupId>org.brotli</groupId>
|
||||
<artifactId>dec</artifactId>
|
||||
<version>0.1.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.hakky54</groupId>
|
||||
<artifactId>ayza-for-apache5</artifactId>
|
||||
<version>10.0.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- test dependencies -->
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-junit5-mockito</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-jacoco</artifactId>
|
||||
<artifactId>quarkus-junit-mockito</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkiverse.playwright</groupId>
|
||||
<artifactId>quarkus-playwright</artifactId>
|
||||
<version>2.2.1</version>
|
||||
<version>2.3.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM ibm-semeru-runtimes:open-jdk-25.0.1_8-jre@sha256:015afe20b069a2e0a0e956117ad515f319a4a4e6a3dee5682f3428010fdfc151
|
||||
FROM ibm-semeru-runtimes:open-jdk-25.0.1_8-jre@sha256:e12d5f2461606d625e4d1e22dd0db89e4ae18f58a7f96332811554209ef9028a
|
||||
EXPOSE 8082
|
||||
|
||||
RUN mkdir -p /commafeed/data
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM debian:13.2@sha256:8f6a88feef3ed01a300dafb87f208977f39dccda1fd120e878129463f7fa3b8f
|
||||
FROM debian:13.3@sha256:2c91e484d93f0830a7e05a2b9d92a7b102be7cab562198b984a84fdbc7806d91
|
||||
ARG TARGETARCH
|
||||
|
||||
EXPOSE 8082
|
||||
|
||||
@@ -4,11 +4,11 @@ Official docker images for https://github.com/Athou/commafeed/
|
||||
|
||||
## Quickstart
|
||||
|
||||
Start CommaFeed with a H2 embedded database. Then login as `admin/admin` on http://localhost:8082/
|
||||
Start CommaFeed with a H2 embedded database. The app will be accessible on http://localhost:8082/
|
||||
|
||||
### docker
|
||||
|
||||
`docker run --name commafeed --detach --publish 8082:8082 --restart unless-stopped --volume /path/to/commafeed/db:/commafeed/data --memory 256M athou/commafeed:latest-h2`
|
||||
`docker run --name commafeed --detach --publish 8082:8082 --restart unless-stopped --volume /path/to/commafeed/data:/commafeed/data --memory 256M athou/commafeed:latest-h2`
|
||||
|
||||
### docker-compose
|
||||
|
||||
@@ -18,7 +18,7 @@ services:
|
||||
image: athou/commafeed:latest-h2
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- /path/to/commafeed/db:/commafeed/data
|
||||
- ./data:/commafeed/data
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
@@ -56,7 +56,7 @@ services:
|
||||
POSTGRES_PASSWORD: commafeed
|
||||
POSTGRES_DB: commafeed
|
||||
volumes:
|
||||
- /path/to/commafeed/db:/var/lib/postgresql/data
|
||||
- ./data:/var/lib/postgresql
|
||||
```
|
||||
|
||||
CommaFeed also supports:
|
||||
|
||||
@@ -4,7 +4,6 @@ import jakarta.enterprise.event.Observes;
|
||||
import jakarta.inject.Singleton;
|
||||
|
||||
import com.commafeed.backend.feed.FeedRefreshEngine;
|
||||
import com.commafeed.backend.service.db.DatabaseStartupService;
|
||||
import com.commafeed.backend.task.TaskScheduler;
|
||||
import com.commafeed.security.password.PasswordConstraintValidator;
|
||||
|
||||
@@ -16,15 +15,12 @@ import lombok.RequiredArgsConstructor;
|
||||
@RequiredArgsConstructor
|
||||
public class CommaFeedApplication {
|
||||
|
||||
private final DatabaseStartupService databaseStartupService;
|
||||
private final FeedRefreshEngine feedRefreshEngine;
|
||||
private final TaskScheduler taskScheduler;
|
||||
private final CommaFeedConfiguration config;
|
||||
|
||||
public void start(@Observes StartupEvent ev) {
|
||||
PasswordConstraintValidator.setStrict(config.users().strictPasswordPolicy());
|
||||
|
||||
databaseStartupService.populateInitialData();
|
||||
PasswordConstraintValidator.setMinimumPasswordLength(config.users().minimumPasswordLength());
|
||||
|
||||
feedRefreshEngine.start();
|
||||
taskScheduler.start();
|
||||
|
||||
@@ -312,6 +312,12 @@ public interface CommaFeedConfiguration {
|
||||
@WithDefault("100")
|
||||
int batchSize();
|
||||
|
||||
/**
|
||||
* Whether to keep starred entries when cleaning up old entries.
|
||||
*/
|
||||
@WithDefault("true")
|
||||
boolean keepStarredEntries();
|
||||
|
||||
default Instant statusesInstantThreshold() {
|
||||
return statusesMaxAge().toMillis() > 0 ? Instant.now().minus(statusesMaxAge()) : null;
|
||||
}
|
||||
@@ -326,10 +332,16 @@ public interface CommaFeedConfiguration {
|
||||
boolean allowRegistrations();
|
||||
|
||||
/**
|
||||
* Whether to enable strict password validation (1 uppercase char, 1 lowercase char, 1 digit, 1 special char).
|
||||
* Minimum password length for user accounts.
|
||||
*/
|
||||
@WithDefault("true")
|
||||
boolean strictPasswordPolicy();
|
||||
@WithDefault("4")
|
||||
int minimumPasswordLength();
|
||||
|
||||
/**
|
||||
* Whether an email address is required when creating a user account.
|
||||
*/
|
||||
@WithDefault("false")
|
||||
boolean emailAddressRequired();
|
||||
|
||||
/**
|
||||
* Whether to create a demo account the first time the app starts.
|
||||
|
||||
@@ -4,6 +4,5 @@ import lombok.experimental.UtilityClass;
|
||||
|
||||
@UtilityClass
|
||||
public class CommaFeedConstants {
|
||||
public static final String USERNAME_ADMIN = "admin";
|
||||
public static final String USERNAME_DEMO = "demo";
|
||||
}
|
||||
|
||||
@@ -2,12 +2,16 @@ 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 io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
import io.quarkus.security.AuthenticationFailedException;
|
||||
import io.quarkus.security.UnauthorizedException;
|
||||
@@ -18,17 +22,18 @@ import lombok.RequiredArgsConstructor;
|
||||
@Priority(1)
|
||||
public class ExceptionMappers {
|
||||
|
||||
private final CookieService cookieService;
|
||||
private final CommaFeedConfiguration config;
|
||||
|
||||
@ServerExceptionMapper(UnauthorizedException.class)
|
||||
public RestResponse<UnauthorizedResponse> unauthorized(UnauthorizedException e) {
|
||||
return RestResponse.status(RestResponse.Status.UNAUTHORIZED,
|
||||
new UnauthorizedResponse(e.getMessage(), config.users().allowRegistrations()));
|
||||
return RestResponse.status(Status.UNAUTHORIZED, new UnauthorizedResponse(e.getMessage(), config.users().allowRegistrations()));
|
||||
}
|
||||
|
||||
@ServerExceptionMapper(AuthenticationFailedException.class)
|
||||
public RestResponse<AuthenticationFailed> authenticationFailed(AuthenticationFailedException e) {
|
||||
return RestResponse.status(RestResponse.Status.UNAUTHORIZED, new AuthenticationFailed(e.getMessage()));
|
||||
NewCookie logoutCookie = cookieService.buildLogoutCookie();
|
||||
return ResponseBuilder.create(Status.UNAUTHORIZED, new AuthenticationFailed(e.getMessage())).cookie(logoutCookie).build();
|
||||
}
|
||||
|
||||
@ServerExceptionMapper(ValidationException.class)
|
||||
|
||||
@@ -9,10 +9,13 @@ import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.InstantSource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.SequencedMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import jakarta.inject.Singleton;
|
||||
import jakarta.ws.rs.core.CacheControl;
|
||||
@@ -24,6 +27,9 @@ import org.apache.hc.client5.http.SystemDefaultDnsResolver;
|
||||
import org.apache.hc.client5.http.config.ConnectionConfig;
|
||||
import org.apache.hc.client5.http.config.RequestConfig;
|
||||
import org.apache.hc.client5.http.config.TlsConfig;
|
||||
import org.apache.hc.client5.http.entity.DeflateInputStream;
|
||||
import org.apache.hc.client5.http.entity.InputStreamFactory;
|
||||
import org.apache.hc.client5.http.entity.compress.ContentCoding;
|
||||
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
|
||||
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
|
||||
@@ -41,6 +47,7 @@ import org.apache.hc.core5.http.io.support.ClassicRequestBuilder;
|
||||
import org.apache.hc.core5.http.message.BasicHeader;
|
||||
import org.apache.hc.core5.util.TimeValue;
|
||||
import org.apache.hc.core5.util.Timeout;
|
||||
import org.brotli.dec.BrotliInputStream;
|
||||
import org.jboss.resteasy.reactive.common.headers.CacheControlDelegate;
|
||||
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
@@ -287,6 +294,11 @@ public class HttpGetter {
|
||||
headers.add(new BasicHeader(HttpHeaders.PRAGMA, "No-cache"));
|
||||
headers.add(new BasicHeader(HttpHeaders.CACHE_CONTROL, "no-cache"));
|
||||
|
||||
SequencedMap<String, InputStreamFactory> contentDecoderMap = new LinkedHashMap<>();
|
||||
contentDecoderMap.put(ContentCoding.GZIP.token(), GZIPInputStream::new);
|
||||
contentDecoderMap.put(ContentCoding.DEFLATE.token(), DeflateInputStream::new);
|
||||
contentDecoderMap.put(ContentCoding.BROTLI.token(), BrotliInputStream::new);
|
||||
|
||||
return HttpClientBuilder.create()
|
||||
.useSystemProperties()
|
||||
.disableAutomaticRetries()
|
||||
@@ -296,6 +308,7 @@ public class HttpGetter {
|
||||
.setConnectionManager(connectionManager)
|
||||
.evictExpiredConnections()
|
||||
.evictIdleConnections(TimeValue.of(idleConnectionsEvictionInterval))
|
||||
.setContentDecoderRegistry(new LinkedHashMap<>(contentDecoderMap))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import com.commafeed.backend.model.FeedEntry;
|
||||
import com.commafeed.backend.model.QFeedEntry;
|
||||
import com.querydsl.core.Tuple;
|
||||
import com.querydsl.core.types.dsl.NumberExpression;
|
||||
import com.querydsl.jpa.impl.JPAQuery;
|
||||
|
||||
@Singleton
|
||||
public class FeedEntryDAO extends GenericDAO<FeedEntry> {
|
||||
@@ -25,15 +26,21 @@ public class FeedEntryDAO extends GenericDAO<FeedEntry> {
|
||||
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) {
|
||||
public List<FeedCapacity> findFeedsExceedingCapacity(long maxCapacity, long max, boolean keepStarredEntries) {
|
||||
NumberExpression<Long> count = ENTRY.id.count();
|
||||
List<Tuple> tuples = query().select(ENTRY.feed.id, count)
|
||||
.from(ENTRY)
|
||||
.groupBy(ENTRY.feed)
|
||||
JPAQuery<Tuple> query = query().select(ENTRY.feed.id, count).from(ENTRY);
|
||||
|
||||
if (keepStarredEntries) {
|
||||
query.where(Predicates.isNotStarred(ENTRY));
|
||||
}
|
||||
|
||||
return query.groupBy(ENTRY.feed)
|
||||
.having(count.gt(maxCapacity))
|
||||
.limit(max)
|
||||
.fetch();
|
||||
return tuples.stream().map(t -> new FeedCapacity(t.get(ENTRY.feed.id), t.get(count))).toList();
|
||||
.fetch()
|
||||
.stream()
|
||||
.map(t -> new FeedCapacity(t.get(ENTRY.feed.id), t.get(count)))
|
||||
.toList();
|
||||
}
|
||||
|
||||
public int delete(Long feedId, long max) {
|
||||
@@ -44,21 +51,30 @@ public class FeedEntryDAO extends GenericDAO<FeedEntry> {
|
||||
/**
|
||||
* Delete entries older than a certain date
|
||||
*/
|
||||
public int deleteEntriesOlderThan(Instant olderThan, long max) {
|
||||
List<FeedEntry> list = query().selectFrom(ENTRY)
|
||||
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)
|
||||
.fetch();
|
||||
return delete(list);
|
||||
.limit(max);
|
||||
|
||||
if (keepStarredEntries) {
|
||||
query.where(Predicates.isNotStarred(ENTRY));
|
||||
}
|
||||
|
||||
return delete(query.fetch());
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the oldest entries of a feed
|
||||
*/
|
||||
public int deleteOldEntries(Long feedId, long max) {
|
||||
List<FeedEntry> list = query().selectFrom(ENTRY).where(ENTRY.feed.id.eq(feedId)).orderBy(ENTRY.published.asc()).limit(max).fetch();
|
||||
return delete(list);
|
||||
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) {
|
||||
query.where(Predicates.isNotStarred(ENTRY));
|
||||
}
|
||||
|
||||
return delete(query.fetch());
|
||||
}
|
||||
|
||||
public record FeedCapacity(Long id, Long capacity) {
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.commafeed.backend.dao;
|
||||
|
||||
import com.commafeed.backend.model.QFeedEntry;
|
||||
import com.commafeed.backend.model.QFeedEntryStatus;
|
||||
import com.querydsl.core.types.dsl.BooleanExpression;
|
||||
import com.querydsl.jpa.JPAExpressions;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
@UtilityClass
|
||||
public class Predicates {
|
||||
|
||||
private static final QFeedEntryStatus STATUS = QFeedEntryStatus.feedEntryStatus;
|
||||
|
||||
public static BooleanExpression isNotStarred(QFeedEntry entry) {
|
||||
return JPAExpressions.selectOne().from(STATUS).where(STATUS.entry.eq(entry).and(STATUS.starred.isTrue())).notExists();
|
||||
}
|
||||
}
|
||||
@@ -32,4 +32,8 @@ public class UserRoleDAO extends GenericDAO<UserRole> {
|
||||
public Set<Role> findRoles(User user) {
|
||||
return findAll(user).stream().map(UserRole::getRole).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public long countAdmins() {
|
||||
return query().select(ROLE.count()).from(ROLE).where(ROLE.role.eq(Role.ADMIN)).fetchOne();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ public class DefaultFaviconFetcher extends AbstractFaviconFetcher {
|
||||
return null;
|
||||
}
|
||||
|
||||
String href = icons.get(0).attr("abs:href");
|
||||
String href = icons.getFirst().attr("abs:href");
|
||||
if (StringUtils.isBlank(href)) {
|
||||
log.debug("No icon found in page");
|
||||
return null;
|
||||
|
||||
@@ -17,7 +17,7 @@ public record Favicon(byte[] icon, MediaType mediaType) {
|
||||
try {
|
||||
return MediaType.valueOf(contentType);
|
||||
} catch (Exception e) {
|
||||
log.debug("invalid content type '{}' received, returning default value", contentType);
|
||||
log.debug("invalid content type '{}' received, returning default value", contentType, e);
|
||||
return DEFAULT_MEDIA_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,9 +164,11 @@ public class FeedRefreshEngine {
|
||||
Instant lastLoginThreshold = config.feedRefresh().userInactivityPeriod().isZero() ? null
|
||||
: Instant.now().minus(config.feedRefresh().userInactivityPeriod());
|
||||
List<Feed> feeds = feedDAO.findNextUpdatable(max, lastLoginThreshold);
|
||||
// update disabledUntil to prevent feeds from being returned again by feedDAO.findNextUpdatable()
|
||||
Instant nextUpdateDate = Instant.now().plus(config.feedRefresh().interval());
|
||||
feedDAO.setDisabledUntil(feeds.stream().map(AbstractModel::getId).toList(), nextUpdateDate);
|
||||
if (!feeds.isEmpty()) {
|
||||
// update disabledUntil to prevent feeds from being returned again by feedDAO.findNextUpdatable()
|
||||
Instant nextUpdateDate = Instant.now().plus(config.feedRefresh().interval());
|
||||
feedDAO.setDisabledUntil(feeds.stream().map(AbstractModel::getId).toList(), nextUpdateDate);
|
||||
}
|
||||
return feeds;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -30,7 +30,11 @@ public class OPMLImporter {
|
||||
private final FeedSubscriptionService feedSubscriptionService;
|
||||
|
||||
public void importOpml(User user, String xml) throws IllegalArgumentException, FeedException {
|
||||
xml = xml.substring(xml.indexOf('<'));
|
||||
int index = xml.indexOf('<');
|
||||
if (index == -1) {
|
||||
throw new IllegalArgumentException("Invalid OPML: no start tag found");
|
||||
}
|
||||
xml = xml.substring(index);
|
||||
WireFeedInput input = new WireFeedInput();
|
||||
Opml feed = (Opml) input.build(new StringReader(xml));
|
||||
List<Outline> outlines = feed.getOutlines();
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.commafeed.backend.service;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
@@ -18,11 +17,10 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
// taken from http://www.javacodegeeks.com/2012/05/secure-password-storage-donts-dos-and.html
|
||||
@SuppressWarnings("serial")
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Singleton
|
||||
public class PasswordEncryptionService implements Serializable {
|
||||
public class PasswordEncryptionService {
|
||||
|
||||
public boolean authenticate(String attemptedPassword, byte[] encryptedPassword, byte[] salt) {
|
||||
if (StringUtils.isBlank(attemptedPassword)) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.commafeed.backend.service;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
@@ -95,7 +94,7 @@ public class UserService {
|
||||
}
|
||||
|
||||
String computedFeverApiKey = Digests.md5Hex(user.getName() + ":" + user.getApiKey());
|
||||
if (!computedFeverApiKey.equals(feverApiKey)) {
|
||||
if (!computedFeverApiKey.equalsIgnoreCase(feverApiKey)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@@ -139,10 +138,6 @@ public class UserService {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void createAdminUser() {
|
||||
register(CommaFeedConstants.USERNAME_ADMIN, "admin", "admin@commafeed.com", Arrays.asList(Role.ADMIN, Role.USER), true);
|
||||
}
|
||||
|
||||
public void createDemoUser() {
|
||||
register(CommaFeedConstants.USERNAME_DEMO, "demo", "demo@commafeed.com", Collections.singletonList(Role.USER), true);
|
||||
}
|
||||
|
||||
@@ -27,13 +27,13 @@ import lombok.extern.slf4j.Slf4j;
|
||||
@Singleton
|
||||
public class DatabaseCleaningService {
|
||||
|
||||
private final int batchSize;
|
||||
|
||||
private final UnitOfWork unitOfWork;
|
||||
private final FeedDAO feedDAO;
|
||||
private final FeedEntryDAO feedEntryDAO;
|
||||
private final FeedEntryContentDAO feedEntryContentDAO;
|
||||
private final FeedEntryStatusDAO feedEntryStatusDAO;
|
||||
private final int batchSize;
|
||||
private final boolean keepStarredEntries;
|
||||
private final Meter entriesDeletedMeter;
|
||||
|
||||
public DatabaseCleaningService(CommaFeedConfiguration config, UnitOfWork unitOfWork, FeedDAO feedDAO, FeedEntryDAO feedEntryDAO,
|
||||
@@ -44,6 +44,7 @@ public class DatabaseCleaningService {
|
||||
this.feedEntryContentDAO = feedEntryContentDAO;
|
||||
this.feedEntryStatusDAO = feedEntryStatusDAO;
|
||||
this.batchSize = config.database().cleanup().batchSize();
|
||||
this.keepStarredEntries = config.database().cleanup().keepStarredEntries();
|
||||
this.entriesDeletedMeter = metrics.meter(MetricRegistry.name(getClass(), "entriesDeleted"));
|
||||
}
|
||||
|
||||
@@ -86,21 +87,23 @@ public class DatabaseCleaningService {
|
||||
log.info("cleaning entries exceeding feed capacity");
|
||||
long total = 0;
|
||||
while (true) {
|
||||
List<FeedCapacity> feeds = unitOfWork.call(() -> feedEntryDAO.findFeedsExceedingCapacity(maxFeedCapacity, batchSize));
|
||||
List<FeedCapacity> feeds = unitOfWork
|
||||
.call(() -> feedEntryDAO.findFeedsExceedingCapacity(maxFeedCapacity, batchSize, keepStarredEntries));
|
||||
if (feeds.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (final FeedCapacity feed : feeds) {
|
||||
long remaining = feed.capacity() - maxFeedCapacity;
|
||||
int deleted;
|
||||
do {
|
||||
final long rem = remaining;
|
||||
int deleted = unitOfWork.call(() -> feedEntryDAO.deleteOldEntries(feed.id(), Math.min(batchSize, rem)));
|
||||
deleted = unitOfWork.call(() -> feedEntryDAO.deleteOldEntries(feed.id(), Math.min(batchSize, rem), keepStarredEntries));
|
||||
entriesDeletedMeter.mark(deleted);
|
||||
total += deleted;
|
||||
remaining -= deleted;
|
||||
log.debug("removed {} entries for feeds exceeding capacity", total);
|
||||
} while (remaining > 0);
|
||||
} while (deleted > 0 && remaining > 0);
|
||||
}
|
||||
}
|
||||
log.info("cleanup done: {} entries for feeds exceeding capacity deleted", total);
|
||||
@@ -111,7 +114,7 @@ public class DatabaseCleaningService {
|
||||
long total = 0;
|
||||
long deleted;
|
||||
do {
|
||||
deleted = unitOfWork.call(() -> feedEntryDAO.deleteEntriesOlderThan(olderThan, batchSize));
|
||||
deleted = unitOfWork.call(() -> feedEntryDAO.deleteEntriesOlderThan(olderThan, batchSize, keepStarredEntries));
|
||||
entriesDeletedMeter.mark(deleted);
|
||||
total += deleted;
|
||||
log.debug("removed {} old entries", total);
|
||||
|
||||
@@ -25,23 +25,8 @@ public class DatabaseStartupService {
|
||||
private final UserService userService;
|
||||
private final CommaFeedConfiguration config;
|
||||
|
||||
public void populateInitialData() {
|
||||
long count = unitOfWork.call(userDAO::count);
|
||||
if (count == 0) {
|
||||
unitOfWork.run(this::initialData);
|
||||
}
|
||||
}
|
||||
|
||||
private void initialData() {
|
||||
log.info("populating database with default values");
|
||||
try {
|
||||
userService.createAdminUser();
|
||||
if (config.users().createDemoAccount()) {
|
||||
userService.createDemoUser();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
public boolean isInitialSetupRequired() {
|
||||
return unitOfWork.call(userDAO::count) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,7 +14,7 @@ public class InPageReferenceFeedURLProvider implements FeedURLProvider {
|
||||
@Override
|
||||
public List<String> get(String url, String urlContent) {
|
||||
Document doc = Jsoup.parse(urlContent, url);
|
||||
if (!"html".equals(doc.children().get(0).tagName())) {
|
||||
if (!"html".equals(doc.children().getFirst().tagName())) {
|
||||
return List.of();
|
||||
}
|
||||
return Stream.concat(doc.select("link[type=application/atom+xml]").stream(), doc.select("link[type=application/rss+xml]").stream())
|
||||
|
||||
@@ -25,6 +25,9 @@ public class ServerInfo implements Serializable {
|
||||
@Schema(required = true)
|
||||
private boolean allowRegistrations;
|
||||
|
||||
@Schema(required = true)
|
||||
private boolean emailAddressRequired;
|
||||
|
||||
@Schema(required = true)
|
||||
private boolean smtpEnabled;
|
||||
|
||||
@@ -43,4 +46,10 @@ public class ServerInfo implements Serializable {
|
||||
@Schema(required = true)
|
||||
private long forceRefreshCooldownDuration;
|
||||
|
||||
@Schema(required = true)
|
||||
private boolean initialSetupRequired;
|
||||
|
||||
@Schema(required = true)
|
||||
private int minimumPasswordLength;
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import lombok.Data;
|
||||
@RegisterForReflection
|
||||
public class Settings implements Serializable {
|
||||
|
||||
@Schema(description = "user's preferred language, english if none", required = true)
|
||||
@Schema(description = "user's preferred language, english if none")
|
||||
private String language;
|
||||
|
||||
@Schema(description = "user reads all entries or unread entries only", required = true)
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.commafeed.frontend.model.request;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.eclipse.microprofile.openapi.annotations.media.Schema;
|
||||
|
||||
import com.commafeed.security.password.ValidPassword;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@Schema(description = "Initial admin account setup request")
|
||||
@Data
|
||||
public class InitialSetupRequest implements Serializable {
|
||||
|
||||
@Schema(description = "admin username", required = true)
|
||||
private String name;
|
||||
|
||||
@Schema(description = "admin password", required = true)
|
||||
@ValidPassword
|
||||
private String password;
|
||||
|
||||
@Schema(description = "admin email")
|
||||
private String email;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.commafeed.frontend.model.request;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import jakarta.validation.constraints.Email;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
import org.eclipse.microprofile.openapi.annotations.media.Schema;
|
||||
|
||||
import com.commafeed.security.password.ValidPassword;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@Data
|
||||
@Schema
|
||||
public class PasswordResetConfirmationRequest implements Serializable {
|
||||
|
||||
@Schema(description = "email address for password recovery", required = true)
|
||||
@Email
|
||||
@NotEmpty
|
||||
@Size(max = 255)
|
||||
private String email;
|
||||
|
||||
@Schema(description = "password recovery token", required = true)
|
||||
@NotEmpty
|
||||
private String token;
|
||||
|
||||
@Schema(description = "new password", required = true)
|
||||
@NotEmpty
|
||||
@ValidPassword
|
||||
private String password;
|
||||
}
|
||||
@@ -26,7 +26,6 @@ import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
|
||||
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
|
||||
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import com.commafeed.CommaFeedConstants;
|
||||
import com.commafeed.backend.dao.UserDAO;
|
||||
import com.commafeed.backend.dao.UserRoleDAO;
|
||||
import com.commafeed.backend.model.User;
|
||||
@@ -101,8 +100,8 @@ public class AdminREST {
|
||||
if (req.isAdmin() && !roles.contains(Role.ADMIN)) {
|
||||
userRoleDAO.persist(new UserRole(u, Role.ADMIN));
|
||||
} else if (!req.isAdmin() && roles.contains(Role.ADMIN)) {
|
||||
if (CommaFeedConstants.USERNAME_ADMIN.equals(u.getName())) {
|
||||
return Response.status(Status.FORBIDDEN).entity("You cannot remove the admin role from the admin user.").build();
|
||||
if (userRoleDAO.countAdmins() == 1) {
|
||||
return Response.status(Status.FORBIDDEN).entity("You cannot remove the admin role from the last admin user.").build();
|
||||
}
|
||||
for (UserRole userRole : userRoleDAO.findAll(u)) {
|
||||
if (userRole.getRole() == Role.ADMIN) {
|
||||
|
||||
@@ -178,7 +178,7 @@ public class CategoryREST {
|
||||
boolean hasMore = entries.getEntries().size() > limit;
|
||||
if (hasMore) {
|
||||
entries.setHasMore(true);
|
||||
entries.getEntries().remove(entries.getEntries().size() - 1);
|
||||
entries.getEntries().removeLast();
|
||||
}
|
||||
|
||||
entries.setTimestamp(System.currentTimeMillis());
|
||||
@@ -337,7 +337,7 @@ public class CategoryREST {
|
||||
}
|
||||
|
||||
FeedCategory parent = null;
|
||||
if (req.getParentId() != null && !CategoryREST.ALL.equals(req.getParentId())
|
||||
if (req.getParentId() != null && !ALL.equals(req.getParentId())
|
||||
&& !Strings.CS.equals(req.getParentId(), String.valueOf(req.getId()))) {
|
||||
parent = feedCategoryDAO.findById(user, Long.valueOf(req.getParentId()));
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ public class FeedREST {
|
||||
boolean hasMore = entries.getEntries().size() > limit;
|
||||
if (hasMore) {
|
||||
entries.setHasMore(true);
|
||||
entries.getEntries().remove(entries.getEntries().size() - 1);
|
||||
entries.getEntries().removeLast();
|
||||
}
|
||||
} else {
|
||||
return Response.status(Status.NOT_FOUND).entity("<message>feed not found</message>").build();
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.commafeed.CommaFeedVersion;
|
||||
import com.commafeed.backend.HttpGetter;
|
||||
import com.commafeed.backend.HttpGetter.HttpResult;
|
||||
import com.commafeed.backend.feed.ImageProxyUrl;
|
||||
import com.commafeed.backend.service.db.DatabaseStartupService;
|
||||
import com.commafeed.frontend.model.ServerInfo;
|
||||
import com.commafeed.security.Roles;
|
||||
|
||||
@@ -39,6 +40,7 @@ public class ServerREST {
|
||||
private final HttpGetter httpGetter;
|
||||
private final CommaFeedConfiguration config;
|
||||
private final CommaFeedVersion version;
|
||||
private final DatabaseStartupService databaseStartupService;
|
||||
|
||||
@Path("/get")
|
||||
@GET
|
||||
@@ -51,12 +53,15 @@ public class ServerREST {
|
||||
infos.setVersion(version.getVersion());
|
||||
infos.setGitCommit(version.getGitCommit());
|
||||
infos.setAllowRegistrations(config.users().allowRegistrations());
|
||||
infos.setEmailAddressRequired(config.users().emailAddressRequired());
|
||||
infos.setSmtpEnabled(config.passwordRecoveryEnabled());
|
||||
infos.setDemoAccountEnabled(config.users().createDemoAccount());
|
||||
infos.setWebsocketEnabled(config.websocket().enabled());
|
||||
infos.setWebsocketPingInterval(config.websocket().pingInterval().toMillis());
|
||||
infos.setTreeReloadInterval(config.websocket().treeReloadInterval().toMillis());
|
||||
infos.setForceRefreshCooldownDuration(config.feedRefresh().forceRefreshCooldownDuration().toMillis());
|
||||
infos.setInitialSetupRequired(databaseStartupService.isInitialSetupRequired());
|
||||
infos.setMinimumPasswordLength(config.users().minimumPasswordLength());
|
||||
return infos;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package com.commafeed.frontend.resource;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
@@ -19,13 +20,11 @@ import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.POST;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.core.Response.Status;
|
||||
import jakarta.ws.rs.core.UriInfo;
|
||||
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.hc.core5.net.URIBuilder;
|
||||
import org.eclipse.microprofile.openapi.annotations.Operation;
|
||||
@@ -50,8 +49,11 @@ import com.commafeed.backend.model.UserSettings.ScrollMode;
|
||||
import com.commafeed.backend.service.MailService;
|
||||
import com.commafeed.backend.service.PasswordEncryptionService;
|
||||
import com.commafeed.backend.service.UserService;
|
||||
import com.commafeed.backend.service.db.DatabaseStartupService;
|
||||
import com.commafeed.frontend.model.Settings;
|
||||
import com.commafeed.frontend.model.UserModel;
|
||||
import com.commafeed.frontend.model.request.InitialSetupRequest;
|
||||
import com.commafeed.frontend.model.request.PasswordResetConfirmationRequest;
|
||||
import com.commafeed.frontend.model.request.PasswordResetRequest;
|
||||
import com.commafeed.frontend.model.request.ProfileModificationRequest;
|
||||
import com.commafeed.frontend.model.request.RegistrationRequest;
|
||||
@@ -78,6 +80,7 @@ public class UserREST {
|
||||
private final UserSettingsDAO userSettingsDAO;
|
||||
private final UserService userService;
|
||||
private final PasswordEncryptionService encryptionService;
|
||||
private final DatabaseStartupService databaseStartupService;
|
||||
private final MailService mailService;
|
||||
private final CommaFeedConfiguration config;
|
||||
private final UriInfo uri;
|
||||
@@ -137,7 +140,6 @@ public class UserREST {
|
||||
s.getSharingSettings().setBuffer(true);
|
||||
|
||||
s.setScrollMarks(true);
|
||||
s.setLanguage("en");
|
||||
s.setScrollSpeed(400);
|
||||
s.setScrollMode(ScrollMode.IF_NEEDED);
|
||||
s.setEntriesToKeepOnTopWhenScrolling(1);
|
||||
@@ -149,7 +151,7 @@ public class UserREST {
|
||||
s.setMobileFooter(false);
|
||||
s.setUnreadCountTitle(false);
|
||||
s.setUnreadCountFavicon(true);
|
||||
s.setDisablePullToRefresh(true);
|
||||
s.setDisablePullToRefresh(false);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
@@ -231,7 +233,7 @@ public class UserREST {
|
||||
public Response saveUserProfile(@Valid @Parameter(required = true) ProfileModificationRequest request) {
|
||||
User user = authenticationContext.getCurrentUser();
|
||||
if (CommaFeedConstants.USERNAME_DEMO.equals(user.getName())) {
|
||||
return Response.status(Status.FORBIDDEN).build();
|
||||
return Response.status(Status.FORBIDDEN).entity("the profile of the demo account cannot be modified").build();
|
||||
}
|
||||
|
||||
Optional<User> login = userService.login(user.getName(), request.getCurrentPassword());
|
||||
@@ -276,6 +278,31 @@ public class UserREST {
|
||||
}
|
||||
}
|
||||
|
||||
@Path("/initialSetup")
|
||||
@PermitAll
|
||||
@POST
|
||||
@Transactional
|
||||
@Operation(
|
||||
summary = "Create the initial admin account",
|
||||
description = "This endpoint is only available when no users exist in the database")
|
||||
public Response initialSetup(@Valid @Parameter(required = true) InitialSetupRequest req) {
|
||||
boolean initialSetupRequired = databaseStartupService.isInitialSetupRequired();
|
||||
if (!initialSetupRequired) {
|
||||
return Response.status(Status.BAD_REQUEST).entity("Initial setup has already been completed").build();
|
||||
}
|
||||
|
||||
userService.register(req.getName(), req.getPassword(), req.getEmail(), List.of(Role.ADMIN, Role.USER), true);
|
||||
|
||||
if (config.users().createDemoAccount()) {
|
||||
User demo = userDAO.findByName(CommaFeedConstants.USERNAME_DEMO);
|
||||
if (demo == null) {
|
||||
userService.createDemoUser();
|
||||
}
|
||||
}
|
||||
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@Path("/passwordReset")
|
||||
@PermitAll
|
||||
@POST
|
||||
@@ -303,45 +330,44 @@ public class UserREST {
|
||||
}
|
||||
}
|
||||
|
||||
private String buildEmailContent(User user) throws URISyntaxException, MalformedURLException {
|
||||
private String buildEmailContent(User user) throws URISyntaxException {
|
||||
String publicUrl = Urls.removeTrailingSlash(uri.getBaseUri().toString());
|
||||
publicUrl += "/rest/user/passwordResetCallback";
|
||||
return String.format(
|
||||
"You asked for password recovery for account '%s', <a href='%s'>follow this link</a> to change your password. Ignore this if you didn't request a password recovery.",
|
||||
user.getName(), callbackUrl(user, publicUrl));
|
||||
}
|
||||
|
||||
private String callbackUrl(User user, String publicUrl) throws URISyntaxException, MalformedURLException {
|
||||
return new URIBuilder(publicUrl).addParameter("email", user.getEmail())
|
||||
.addParameter("token", user.getRecoverPasswordToken())
|
||||
.build()
|
||||
.toURL()
|
||||
.toString();
|
||||
private String callbackUrl(User user, String publicUrl) throws URISyntaxException {
|
||||
URIBuilder queryBuilder = new URIBuilder();
|
||||
queryBuilder.addParameter("email", user.getEmail());
|
||||
queryBuilder.addParameter("token", user.getRecoverPasswordToken());
|
||||
String queryString = queryBuilder.build().getRawQuery();
|
||||
return publicUrl + "/#/passwordReset?" + queryString;
|
||||
}
|
||||
|
||||
@Path("/passwordResetCallback")
|
||||
@PermitAll
|
||||
@GET
|
||||
@POST
|
||||
@Transactional
|
||||
@Produces(MediaType.TEXT_HTML)
|
||||
public Response passwordRecoveryCallback(@Parameter(required = true) @QueryParam("email") String email,
|
||||
@Parameter(required = true) @QueryParam("token") String token) {
|
||||
@Operation(summary = "confirm password reset with new password")
|
||||
public Response passwordRecoveryCallback(@Valid @Parameter(required = true) PasswordResetConfirmationRequest req) {
|
||||
String email = req.getEmail();
|
||||
String token = req.getToken();
|
||||
String password = req.getPassword();
|
||||
|
||||
Preconditions.checkNotNull(email);
|
||||
Preconditions.checkNotNull(token);
|
||||
Preconditions.checkNotNull(password);
|
||||
|
||||
User user = userDAO.findByEmail(email);
|
||||
if (user == null) {
|
||||
return Response.status(Status.UNAUTHORIZED).entity("Email not found.").build();
|
||||
if (user == null || user.getRecoverPasswordToken() == null || !user.getRecoverPasswordToken().equals(token)) {
|
||||
return Response.status(Status.UNAUTHORIZED).entity("Email not found or invalid token.").build();
|
||||
}
|
||||
if (user.getRecoverPasswordToken() == null || !user.getRecoverPasswordToken().equals(token)) {
|
||||
return Response.status(Status.UNAUTHORIZED).entity("Invalid token.").build();
|
||||
}
|
||||
if (ChronoUnit.DAYS.between(user.getRecoverPasswordTokenDate(), Instant.now()) >= 2) {
|
||||
return Response.status(Status.UNAUTHORIZED).entity("token expired.").build();
|
||||
if (ChronoUnit.MINUTES.between(user.getRecoverPasswordTokenDate(), Instant.now()) >= 30) {
|
||||
return Response.status(Status.UNAUTHORIZED).entity("Token expired.").build();
|
||||
}
|
||||
|
||||
String passwd = RandomStringUtils.secure().nextAlphanumeric(10);
|
||||
byte[] encryptedPassword = encryptionService.getEncryptedPassword(passwd, user.getSalt());
|
||||
byte[] encryptedPassword = encryptionService.getEncryptedPassword(password, user.getSalt());
|
||||
user.setPassword(encryptedPassword);
|
||||
if (StringUtils.isNotBlank(user.getApiKey())) {
|
||||
user.setApiKey(userService.generateApiKey(user));
|
||||
@@ -349,10 +375,7 @@ public class UserREST {
|
||||
user.setRecoverPasswordToken(null);
|
||||
user.setRecoverPasswordTokenDate(null);
|
||||
|
||||
String message = "Your new password is: " + passwd;
|
||||
message += "<br />";
|
||||
message += String.format("<a href=\"%s\">Back to Homepage</a>", uri.getBaseUri());
|
||||
return Response.ok(message).build();
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@Path("/profile/deleteAccount")
|
||||
@@ -361,9 +384,15 @@ public class UserREST {
|
||||
@Operation(summary = "Delete the user account")
|
||||
public Response deleteUser() {
|
||||
User user = authenticationContext.getCurrentUser();
|
||||
if (CommaFeedConstants.USERNAME_ADMIN.equals(user.getName()) || CommaFeedConstants.USERNAME_DEMO.equals(user.getName())) {
|
||||
return Response.status(Status.FORBIDDEN).build();
|
||||
if (CommaFeedConstants.USERNAME_DEMO.equals(user.getName())) {
|
||||
return Response.status(Status.FORBIDDEN).entity("the demo account cannot be deleted").build();
|
||||
}
|
||||
|
||||
Set<Role> roles = userRoleDAO.findRoles(user);
|
||||
if (roles.contains(Role.ADMIN) && userRoleDAO.countAdmins() == 1) {
|
||||
return Response.status(Status.FORBIDDEN).entity("The last admin account cannot be deleted").build();
|
||||
}
|
||||
|
||||
userService.unregister(userDAO.findById(user.getId()));
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.MultivaluedMap;
|
||||
import jakarta.ws.rs.core.UriInfo;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.microprofile.openapi.annotations.Operation;
|
||||
import org.jboss.resteasy.reactive.server.multipart.FormValue;
|
||||
import org.jboss.resteasy.reactive.server.multipart.MultipartFormDataInput;
|
||||
@@ -93,8 +94,8 @@ public class FeverREST {
|
||||
@Operation(hidden = true)
|
||||
public FeverResponse formUrlencoded(@Context UriInfo uri, @PathParam("userId") Long userId, MultivaluedMap<String, String> form) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
uri.getQueryParameters().forEach((k, v) -> params.put(k, v.get(0)));
|
||||
form.forEach((k, v) -> params.put(k, v.get(0)));
|
||||
uri.getQueryParameters().forEach((k, v) -> params.put(k, v.getFirst()));
|
||||
form.forEach((k, v) -> params.put(k, v.getFirst()));
|
||||
return handle(userId, params);
|
||||
}
|
||||
|
||||
@@ -106,7 +107,7 @@ public class FeverREST {
|
||||
@Operation(hidden = true)
|
||||
public FeverResponse noForm(@Context UriInfo uri, @PathParam("userId") Long userId) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
uri.getQueryParameters().forEach((k, v) -> params.put(k, v.get(0)));
|
||||
uri.getQueryParameters().forEach((k, v) -> params.put(k, v.getFirst()));
|
||||
return handle(userId, params);
|
||||
}
|
||||
|
||||
@@ -118,7 +119,7 @@ public class FeverREST {
|
||||
@Operation(hidden = true)
|
||||
public FeverResponse get(@Context UriInfo uri, @PathParam("userId") Long userId) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
uri.getQueryParameters().forEach((k, v) -> params.put(k, v.get(0)));
|
||||
uri.getQueryParameters().forEach((k, v) -> params.put(k, v.getFirst()));
|
||||
return handle(userId, params);
|
||||
}
|
||||
|
||||
@@ -131,7 +132,7 @@ public class FeverREST {
|
||||
@Operation(hidden = true)
|
||||
public FeverResponse formData(@Context UriInfo uri, @PathParam("userId") Long userId, MultipartFormDataInput form) {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
uri.getQueryParameters().forEach((k, v) -> params.put(k, v.get(0)));
|
||||
uri.getQueryParameters().forEach((k, v) -> params.put(k, v.getFirst()));
|
||||
form.getValues().forEach((k, v) -> params.put(k, v.stream().map(FormValue::getValue).findFirst().orElse(null)));
|
||||
return handle(userId, params);
|
||||
}
|
||||
@@ -177,8 +178,8 @@ public class FeverREST {
|
||||
List<String> entryIds = Stream.of(withIds.split(",")).map(String::trim).toList();
|
||||
resp.setItems(buildItems(user, subscriptions, entryIds));
|
||||
} else {
|
||||
Long sinceId = params.containsKey("since_id") ? Long.valueOf(params.get("since_id")) : null;
|
||||
Long maxId = params.containsKey("max_id") ? Long.valueOf(params.get("max_id")) : null;
|
||||
Long sinceId = Optional.ofNullable(params.get("since_id")).filter(StringUtils::isNotBlank).map(Long::valueOf).orElse(null);
|
||||
Long maxId = Optional.ofNullable(params.get("max_id")).filter(StringUtils::isNotBlank).map(Long::valueOf).orElse(null);
|
||||
resp.setItems(buildItems(user, subscriptions, sinceId, maxId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
package com.commafeed.frontend.servlet;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.inject.Singleton;
|
||||
import jakarta.ws.rs.GET;
|
||||
@@ -11,26 +8,25 @@ import jakarta.ws.rs.core.NewCookie;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.core.UriInfo;
|
||||
|
||||
import org.eclipse.microprofile.config.inject.ConfigProperty;
|
||||
import org.eclipse.microprofile.openapi.annotations.Operation;
|
||||
|
||||
import com.commafeed.security.CookieService;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Path("/logout")
|
||||
@PermitAll
|
||||
@Singleton
|
||||
public class LogoutServlet {
|
||||
|
||||
private final UriInfo uri;
|
||||
private final String cookieName;
|
||||
|
||||
public LogoutServlet(UriInfo uri, @ConfigProperty(name = "quarkus.http.auth.form.cookie-name") String cookieName) {
|
||||
this.uri = uri;
|
||||
this.cookieName = cookieName;
|
||||
}
|
||||
private final CookieService cookieService;
|
||||
|
||||
@GET
|
||||
@Operation(hidden = true)
|
||||
public Response get() {
|
||||
NewCookie removeCookie = new NewCookie.Builder(cookieName).maxAge(0).expiry(Date.from(Instant.EPOCH)).path("/").build();
|
||||
NewCookie removeCookie = cookieService.buildLogoutCookie();
|
||||
return Response.temporaryRedirect(uri.getBaseUri()).cookie(removeCookie).build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.commafeed.security;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
|
||||
import jakarta.inject.Singleton;
|
||||
import jakarta.ws.rs.core.NewCookie;
|
||||
|
||||
import io.quarkus.vertx.http.runtime.VertxHttpConfig;
|
||||
|
||||
@Singleton
|
||||
public class CookieService {
|
||||
|
||||
private final String cookieName;
|
||||
|
||||
public CookieService(VertxHttpConfig config) {
|
||||
this.cookieName = config.auth().form().cookieName();
|
||||
}
|
||||
|
||||
public NewCookie buildLogoutCookie() {
|
||||
return new NewCookie.Builder(cookieName).maxAge(0).expiry(Date.from(Instant.EPOCH)).path("/").build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,8 +6,6 @@ import jakarta.validation.ConstraintValidator;
|
||||
import jakarta.validation.ConstraintValidatorContext;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.passay.CharacterRule;
|
||||
import org.passay.EnglishCharacterData;
|
||||
import org.passay.LengthRule;
|
||||
import org.passay.PasswordData;
|
||||
import org.passay.PasswordValidator;
|
||||
@@ -19,7 +17,7 @@ import lombok.Setter;
|
||||
public class PasswordConstraintValidator implements ConstraintValidator<ValidPassword, String> {
|
||||
|
||||
@Setter
|
||||
private static boolean strict = true;
|
||||
private static int minimumPasswordLength;
|
||||
|
||||
@Override
|
||||
public void initialize(ValidPassword constraintAnnotation) {
|
||||
@@ -32,7 +30,7 @@ public class PasswordConstraintValidator implements ConstraintValidator<ValidPas
|
||||
return true;
|
||||
}
|
||||
|
||||
PasswordValidator validator = strict ? buildStrictPasswordValidator() : buildLoosePasswordValidator();
|
||||
PasswordValidator validator = buildPasswordValidator();
|
||||
RuleResult result = validator.validate(new PasswordData(value));
|
||||
|
||||
if (result.isValid()) {
|
||||
@@ -45,28 +43,11 @@ public class PasswordConstraintValidator implements ConstraintValidator<ValidPas
|
||||
return false;
|
||||
}
|
||||
|
||||
private PasswordValidator buildStrictPasswordValidator() {
|
||||
private PasswordValidator buildPasswordValidator() {
|
||||
return new PasswordValidator(
|
||||
// length
|
||||
new LengthRule(8, 256),
|
||||
// 1 uppercase char
|
||||
new CharacterRule(EnglishCharacterData.UpperCase, 1),
|
||||
// 1 lowercase char
|
||||
new CharacterRule(EnglishCharacterData.LowerCase, 1),
|
||||
// 1 digit
|
||||
new CharacterRule(EnglishCharacterData.Digit, 1),
|
||||
// 1 special char
|
||||
new CharacterRule(EnglishCharacterData.Special, 1),
|
||||
new LengthRule(minimumPasswordLength, 256),
|
||||
// no whitespace
|
||||
new WhitespaceRule());
|
||||
}
|
||||
|
||||
private PasswordValidator buildLoosePasswordValidator() {
|
||||
return new PasswordValidator(
|
||||
// length
|
||||
new LengthRule(6, 256),
|
||||
// no whitespace
|
||||
new WhitespaceRule());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
quarkus.http.port=8082
|
||||
quarkus.http.test-port=8085
|
||||
quarkus.http.enable-compression=true
|
||||
quarkus.http.enable-decompression=true
|
||||
|
||||
# http cache
|
||||
quarkus.http.static-resources.max-age=P365d
|
||||
|
||||
@@ -6,8 +6,6 @@ import jakarta.persistence.EntityManager;
|
||||
import org.hibernate.Session;
|
||||
import org.kohsuke.MetaInfServices;
|
||||
|
||||
import com.commafeed.backend.service.db.DatabaseStartupService;
|
||||
|
||||
import io.quarkus.test.junit.callback.QuarkusTestBeforeEachCallback;
|
||||
import io.quarkus.test.junit.callback.QuarkusTestMethodContext;
|
||||
|
||||
@@ -26,7 +24,5 @@ public class DatabaseReset implements QuarkusTestBeforeEachCallback {
|
||||
.getSessionFactory()
|
||||
.getSchemaManager()
|
||||
.truncateMappedObjects();
|
||||
|
||||
CDI.current().select(DatabaseStartupService.class).get().populateInitialData();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.commafeed;
|
||||
|
||||
public class TestConstants {
|
||||
public static final String ADMIN_USERNAME = "admin";
|
||||
public static final String ADMIN_PASSWORD = "admin";
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.zip.DeflaterOutputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
@@ -308,23 +307,26 @@ class HttpGetterTest {
|
||||
@Nested
|
||||
class Compression {
|
||||
|
||||
@Test
|
||||
void deflate() throws Exception {
|
||||
supportsCompression("deflate", DeflaterOutputStream::new);
|
||||
}
|
||||
private static final String ACCEPT_ENCODING = "gzip, deflate, br";
|
||||
|
||||
@Test
|
||||
void gzip() throws Exception {
|
||||
supportsCompression("gzip", GZIPOutputStream::new);
|
||||
}
|
||||
|
||||
@Test
|
||||
void deflate() throws Exception {
|
||||
supportsCompression("deflate", DeflaterOutputStream::new);
|
||||
}
|
||||
|
||||
void supportsCompression(String encoding, CompressionOutputStreamFunction compressionOutputStreamFunction) throws Exception {
|
||||
String body = "my body";
|
||||
|
||||
HttpGetterTest.this.mockServerClient.when(HttpRequest.request().withMethod("GET")).respond(req -> {
|
||||
String acceptEncodingHeader = req.getFirstHeader(HttpHeaders.ACCEPT_ENCODING);
|
||||
if (!Set.of(acceptEncodingHeader.split(", ")).contains(encoding)) {
|
||||
throw new Exception(encoding + " should be in the Accept-Encoding header");
|
||||
if (!ACCEPT_ENCODING.equals(acceptEncodingHeader)) {
|
||||
throw new Exception("Wrong value in the Accept-Encoding header, should be '%s' but was '%s'".formatted(ACCEPT_ENCODING,
|
||||
acceptEncodingHeader));
|
||||
}
|
||||
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
|
||||
@@ -31,10 +31,10 @@ class FeedUtilsTest {
|
||||
Assertions.assertEquals("Test Entry", syndEntry.getTitle());
|
||||
Assertions.assertEquals("Author Name", syndEntry.getAuthor());
|
||||
Assertions.assertEquals(1, syndEntry.getContents().size());
|
||||
Assertions.assertEquals("This is a test entry content.", syndEntry.getContents().get(0).getValue());
|
||||
Assertions.assertEquals("This is a test entry content.", syndEntry.getContents().getFirst().getValue());
|
||||
Assertions.assertEquals(1, syndEntry.getEnclosures().size());
|
||||
Assertions.assertEquals("http://example.com/enclosure.mp3", syndEntry.getEnclosures().get(0).getUrl());
|
||||
Assertions.assertEquals("audio/mpeg", syndEntry.getEnclosures().get(0).getType());
|
||||
Assertions.assertEquals("http://example.com/enclosure.mp3", syndEntry.getEnclosures().getFirst().getUrl());
|
||||
Assertions.assertEquals("audio/mpeg", syndEntry.getEnclosures().getFirst().getType());
|
||||
Assertions.assertEquals("http://example.com/test-entry", syndEntry.getLink());
|
||||
Assertions.assertEquals(Date.from(Instant.ofEpochSecond(1)), syndEntry.getPublishedDate());
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ class UserServiceTest {
|
||||
void apiLoginShouldReturnUserIfUserFoundFromApikeyLookupNotDisabled() {
|
||||
Mockito.when(userDAO.findByApiKey("apikey")).thenReturn(normalUser);
|
||||
Optional<User> returnedUser = userService.login("apikey");
|
||||
Assertions.assertEquals(normalUser, returnedUser.get());
|
||||
Assertions.assertEquals(Optional.of(normalUser), returnedUser);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -115,13 +115,13 @@ class DatabaseCleaningServiceTest {
|
||||
Mockito.when(feed2.id()).thenReturn(2L);
|
||||
Mockito.when(feed2.capacity()).thenReturn(120L);
|
||||
|
||||
Mockito.when(feedEntryDAO.findFeedsExceedingCapacity(50, BATCH_SIZE))
|
||||
Mockito.when(feedEntryDAO.findFeedsExceedingCapacity(50, BATCH_SIZE, false))
|
||||
.thenReturn(Arrays.asList(feed1, feed2))
|
||||
.thenReturn(Collections.emptyList());
|
||||
|
||||
Mockito.when(feedEntryDAO.deleteOldEntries(1L, 100)).thenReturn(80);
|
||||
Mockito.when(feedEntryDAO.deleteOldEntries(1L, 50)).thenReturn(50);
|
||||
Mockito.when(feedEntryDAO.deleteOldEntries(2L, 70)).thenReturn(70);
|
||||
Mockito.when(feedEntryDAO.deleteOldEntries(1L, 100, false)).thenReturn(80);
|
||||
Mockito.when(feedEntryDAO.deleteOldEntries(1L, 50, false)).thenReturn(50);
|
||||
Mockito.when(feedEntryDAO.deleteOldEntries(2L, 70, false)).thenReturn(70);
|
||||
|
||||
service.cleanEntriesForFeedsExceedingCapacity(50);
|
||||
|
||||
@@ -132,11 +132,11 @@ class DatabaseCleaningServiceTest {
|
||||
void cleanEntriesOlderThanDeletesOldEntries() {
|
||||
Instant cutoff = LocalDate.now().minusDays(30).atStartOfDay().toInstant(ZoneOffset.UTC);
|
||||
|
||||
Mockito.when(feedEntryDAO.deleteEntriesOlderThan(cutoff, BATCH_SIZE)).thenReturn(100, 50, 0);
|
||||
Mockito.when(feedEntryDAO.deleteEntriesOlderThan(cutoff, BATCH_SIZE, false)).thenReturn(100, 50, 0);
|
||||
|
||||
service.cleanEntriesOlderThan(cutoff);
|
||||
|
||||
Mockito.verify(feedEntryDAO, Mockito.times(3)).deleteEntriesOlderThan(cutoff, BATCH_SIZE);
|
||||
Mockito.verify(feedEntryDAO, Mockito.times(3)).deleteEntriesOlderThan(cutoff, BATCH_SIZE, false);
|
||||
Mockito.verify(entriesDeletedMeter, Mockito.times(3)).mark(Mockito.anyLong());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package com.commafeed.e2e;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.commafeed.TestConstants;
|
||||
import com.microsoft.playwright.BrowserContext;
|
||||
import com.microsoft.playwright.Locator;
|
||||
import com.microsoft.playwright.Page;
|
||||
import com.microsoft.playwright.assertions.PlaywrightAssertions;
|
||||
import com.microsoft.playwright.options.AriaRole;
|
||||
@@ -20,6 +21,11 @@ class AuthentificationIT {
|
||||
@InjectPlaywright
|
||||
private BrowserContext context;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
PlaywrightTestUtils.initialSetup();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void cleanup() {
|
||||
context.clearCookies();
|
||||
@@ -29,7 +35,7 @@ class AuthentificationIT {
|
||||
void loginFail() {
|
||||
Page page = context.newPage();
|
||||
page.navigate(getLoginPageUrl());
|
||||
PlaywrightTestUtils.login(page, "admin", "wrong_password");
|
||||
PlaywrightTestUtils.login(page, TestConstants.ADMIN_USERNAME, "wrong_password");
|
||||
PlaywrightAssertions.assertThat(page.getByRole(AriaRole.ALERT)).containsText("wrong username or password");
|
||||
}
|
||||
|
||||
@@ -41,20 +47,6 @@ class AuthentificationIT {
|
||||
PlaywrightAssertions.assertThat(page).hasURL("http://localhost:8085/#/app/category/all");
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerFailPasswordTooSimple() {
|
||||
Page page = context.newPage();
|
||||
page.navigate(getLoginPageUrl());
|
||||
page.getByText("Sign up!").click();
|
||||
PlaywrightTestUtils.register(page, "user", "user@domain.com", "pass");
|
||||
|
||||
Locator alert = page.getByRole(AriaRole.ALERT);
|
||||
PlaywrightAssertions.assertThat(alert).containsText("Password must be 8 or more characters in length.");
|
||||
PlaywrightAssertions.assertThat(alert).containsText("Password must contain 1 or more uppercase characters.");
|
||||
PlaywrightAssertions.assertThat(alert).containsText("Password must contain 1 or more digit characters.");
|
||||
PlaywrightAssertions.assertThat(alert).containsText("Password must contain 1 or more special characters.");
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerSuccess() {
|
||||
Page page = context.newPage();
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.commafeed.e2e;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.commafeed.TestConstants;
|
||||
import com.microsoft.playwright.BrowserContext;
|
||||
import com.microsoft.playwright.Page;
|
||||
import com.microsoft.playwright.assertions.PlaywrightAssertions;
|
||||
import com.microsoft.playwright.options.AriaRole;
|
||||
|
||||
import io.quarkiverse.playwright.InjectPlaywright;
|
||||
import io.quarkiverse.playwright.WithPlaywright;
|
||||
import io.quarkus.test.junit.QuarkusTest;
|
||||
|
||||
@QuarkusTest
|
||||
@WithPlaywright
|
||||
class InitialSetupIT {
|
||||
|
||||
@InjectPlaywright
|
||||
private BrowserContext context;
|
||||
|
||||
@Test
|
||||
void createAdminAccount() {
|
||||
Page page = context.newPage();
|
||||
page.navigate("http://localhost:8085");
|
||||
|
||||
page.getByPlaceholder("Admin User Name").fill(TestConstants.ADMIN_USERNAME);
|
||||
page.getByPlaceholder("Password").fill(TestConstants.ADMIN_PASSWORD);
|
||||
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Create Admin Account")).click();
|
||||
|
||||
PlaywrightAssertions.assertThat(page).hasURL("http://localhost:8085/#/app/category/all");
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,28 @@
|
||||
package com.commafeed.e2e;
|
||||
|
||||
import com.commafeed.TestConstants;
|
||||
import com.commafeed.frontend.model.request.InitialSetupRequest;
|
||||
import com.microsoft.playwright.Page;
|
||||
import com.microsoft.playwright.Page.GetByRoleOptions;
|
||||
import com.microsoft.playwright.options.AriaRole;
|
||||
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.http.ContentType;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
@UtilityClass
|
||||
public class PlaywrightTestUtils {
|
||||
|
||||
public static void initialSetup() {
|
||||
InitialSetupRequest req = new InitialSetupRequest();
|
||||
req.setName(TestConstants.ADMIN_USERNAME);
|
||||
req.setPassword(TestConstants.ADMIN_PASSWORD);
|
||||
|
||||
RestAssured.given().body(req).contentType(ContentType.JSON).post("rest/user/initialSetup").then().statusCode(200);
|
||||
}
|
||||
|
||||
public static void login(Page page) {
|
||||
login(page, "admin", "admin");
|
||||
login(page, TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
|
||||
}
|
||||
|
||||
public static void login(Page page, String username, String password) {
|
||||
|
||||
@@ -16,6 +16,7 @@ import org.mockserver.integration.ClientAndServer;
|
||||
import org.mockserver.model.HttpRequest;
|
||||
import org.mockserver.model.HttpResponse;
|
||||
|
||||
import com.commafeed.TestConstants;
|
||||
import com.commafeed.frontend.model.Entries;
|
||||
import com.microsoft.playwright.BrowserContext;
|
||||
import com.microsoft.playwright.Locator;
|
||||
@@ -45,7 +46,8 @@ class ReadingIT {
|
||||
.withBody(IOUtils.toString(getClass().getResource("/feed/rss.xml"), StandardCharsets.UTF_8))
|
||||
.withDelay(TimeUnit.MILLISECONDS, 100));
|
||||
|
||||
RestAssured.authentication = RestAssured.preemptive().basic("admin", "admin");
|
||||
PlaywrightTestUtils.initialSetup();
|
||||
RestAssured.authentication = RestAssured.preemptive().basic(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
||||
@@ -21,10 +21,12 @@ import org.mockserver.integration.ClientAndServer;
|
||||
import org.mockserver.model.HttpRequest;
|
||||
import org.mockserver.model.HttpResponse;
|
||||
|
||||
import com.commafeed.TestConstants;
|
||||
import com.commafeed.frontend.model.Category;
|
||||
import com.commafeed.frontend.model.Entries;
|
||||
import com.commafeed.frontend.model.Subscription;
|
||||
import com.commafeed.frontend.model.request.AddCategoryRequest;
|
||||
import com.commafeed.frontend.model.request.InitialSetupRequest;
|
||||
import com.commafeed.frontend.model.request.SubscribeRequest;
|
||||
|
||||
import io.restassured.RestAssured;
|
||||
@@ -76,11 +78,20 @@ public abstract class BaseIT {
|
||||
mockServerClient.when(FEED_REQUEST).respond(HttpResponse.response().withBody(IOUtils.toString(resource, StandardCharsets.UTF_8)));
|
||||
}
|
||||
|
||||
protected void initialSetup(String userName, String password) {
|
||||
InitialSetupRequest req = new InitialSetupRequest();
|
||||
req.setName(userName);
|
||||
req.setPassword(password);
|
||||
req.setEmail(userName + "@commafeed.com");
|
||||
|
||||
RestAssured.given().body(req).contentType(ContentType.JSON).post("rest/user/initialSetup").then().statusCode(200);
|
||||
}
|
||||
|
||||
protected List<HttpCookie> login() {
|
||||
List<Header> setCookieHeaders = RestAssured.given()
|
||||
.auth()
|
||||
.none()
|
||||
.formParams("j_username", "admin", "j_password", "admin")
|
||||
.formParams("j_username", TestConstants.ADMIN_USERNAME, "j_password", TestConstants.ADMIN_PASSWORD)
|
||||
.post("j_security_check")
|
||||
.then()
|
||||
.statusCode(HttpStatus.SC_OK)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user