forked from Archives/Athou_commafeed
Compare commits
191 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e1f6937802 | ||
|
|
0c0834b30f | ||
|
|
5ad4b97205 | ||
|
|
c4ec249bc4 | ||
|
|
cf8d3965d5 | ||
|
|
3903fd9374 | ||
|
|
77d59dabe8 | ||
|
|
56ca737297 | ||
|
|
9edb539be3 | ||
|
|
31a773d200 | ||
|
|
61355eabf7 | ||
|
|
569874e51f | ||
|
|
00d47901fc | ||
|
|
d8b4ef55ce | ||
|
|
da41a4cab9 | ||
|
|
8a90ef0471 | ||
|
|
b4ab32a578 | ||
|
|
03aa53abc8 | ||
|
|
2ae5c0cd8e | ||
|
|
cacc632443 | ||
|
|
28f865ccfa | ||
|
|
a4c949e8b3 | ||
|
|
6098994397 | ||
|
|
5763ca30d6 | ||
|
|
7d039d1001 | ||
|
|
7fe74af906 | ||
|
|
80b72aa30b | ||
|
|
3ba0d241f9 | ||
|
|
67428aa0c7 | ||
|
|
b9a0256031 | ||
|
|
f3c2296636 | ||
|
|
b6e8f21975 | ||
|
|
284f80045f | ||
|
|
f589477aa8 | ||
|
|
29cb296d09 | ||
|
|
86caa1450a | ||
|
|
9dd4b9e67f | ||
|
|
e2e654f05b | ||
|
|
72dbc62b41 | ||
|
|
0a21014668 | ||
|
|
b6d9d2a26c | ||
|
|
25c3a7748c | ||
|
|
b2bcfdd6eb | ||
|
|
2a978db406 | ||
|
|
9e40d0d066 | ||
|
|
c912650d59 | ||
|
|
464ebcb471 | ||
|
|
463e0e59d7 | ||
|
|
b4e5d8ef20 | ||
|
|
126905aeb3 | ||
|
|
1af10d3364 | ||
|
|
6ad854c019 | ||
|
|
b30117aa4d | ||
|
|
5a66482d1e | ||
|
|
2628ec49bb | ||
|
|
f3d15cf173 | ||
|
|
bbcf55ce57 | ||
|
|
72fc3716e7 | ||
|
|
81a6cfaa88 | ||
|
|
aed5165ef3 | ||
|
|
eaf2933726 | ||
|
|
39da4d9d36 | ||
|
|
e5ebd7ff39 | ||
|
|
b6ae3e4e1e | ||
|
|
32d1488352 | ||
|
|
b08d0a388f | ||
|
|
7fe004a696 | ||
|
|
f620d033b0 | ||
|
|
ba071ba71f | ||
|
|
6f3197302d | ||
|
|
131a8ebf68 | ||
|
|
8b24c125c2 | ||
|
|
52293376ec | ||
|
|
f8ac59af6a | ||
|
|
5c791e2305 | ||
|
|
6641bc0631 | ||
|
|
da690aa750 | ||
|
|
fb7f041454 | ||
|
|
ec4554c76e | ||
|
|
068e85fe6e | ||
|
|
ba926c674e | ||
|
|
836f8f14c0 | ||
|
|
eeecac96e1 | ||
|
|
ecc62f222a | ||
|
|
9022f93811 | ||
|
|
e7225d35b2 | ||
|
|
454fc03038 | ||
|
|
9c0674fd83 | ||
|
|
7a20482ddf | ||
|
|
32ad47ba16 | ||
|
|
fc562cce0f | ||
|
|
b029b251db | ||
|
|
e3e28e727f | ||
|
|
50cb728db7 | ||
|
|
c654ba4d1b | ||
|
|
846e29b15e | ||
|
|
f2b4062d73 | ||
|
|
9051e6a6db | ||
|
|
b733129043 | ||
|
|
d46b571444 | ||
|
|
7d744b4ce0 | ||
|
|
801dda912c | ||
|
|
a20005409a | ||
|
|
6f1411d075 | ||
|
|
1aa263a6c0 | ||
|
|
9d511ac7dd | ||
|
|
122e98cc76 | ||
|
|
e445e5ea39 | ||
|
|
5b9212015b | ||
|
|
293292f341 | ||
|
|
57d8a4dbb1 | ||
|
|
e104f531f9 | ||
|
|
bf1361926f | ||
|
|
cc4f4d9eb4 | ||
|
|
706bad26f1 | ||
|
|
4ecefe6491 | ||
|
|
937e7353ce | ||
|
|
1dcf76fc0a | ||
|
|
9d794dcad7 | ||
|
|
d11b666755 | ||
|
|
7a444e4861 | ||
|
|
5992795579 | ||
|
|
4441d76a7f | ||
|
|
c1305b56e3 | ||
|
|
cc0440c029 | ||
|
|
f65591c170 | ||
|
|
9a32dce9d1 | ||
|
|
789bd3edae | ||
|
|
256cd426d9 | ||
|
|
58af2da105 | ||
|
|
e0de397273 | ||
|
|
75cc3cf29c | ||
|
|
af60758e2a | ||
|
|
01180e95a2 | ||
|
|
fa683ef7e1 | ||
|
|
462d17a429 | ||
|
|
17f71a40d4 | ||
|
|
de91a3a05a | ||
|
|
ead587ee88 | ||
|
|
62b3e6fb3a | ||
|
|
037ff15045 | ||
|
|
ed35b06934 | ||
|
|
3cfb1a13a7 | ||
|
|
d04745d859 | ||
|
|
58b18f36c5 | ||
|
|
7282d18d8f | ||
|
|
8e58fa22b4 | ||
|
|
58d6eb2c5a | ||
|
|
2f7c7498e2 | ||
|
|
bcf8dcd551 | ||
|
|
511f0a60bb | ||
|
|
72db0d815f | ||
|
|
280d0b7fdd | ||
|
|
42e4575cb7 | ||
|
|
28a4bb403a | ||
|
|
cca3c907db | ||
|
|
1a5b932742 | ||
|
|
a1d3f3008a | ||
|
|
902f2efbd2 | ||
|
|
2e534af146 | ||
|
|
23ca30c3c2 | ||
|
|
517eedad00 | ||
|
|
216ea1fb42 | ||
|
|
640d1a0ce3 | ||
|
|
bba7425b5f | ||
|
|
7a1a49bfb4 | ||
|
|
e451e6698c | ||
|
|
9af3f21404 | ||
|
|
7b14a9c0c2 | ||
|
|
0b65cc9510 | ||
|
|
7879ab9b61 | ||
|
|
e6bebcafb3 | ||
|
|
3b465cebb7 | ||
|
|
aeb211be06 | ||
|
|
ad992aea7b | ||
|
|
d848f72a0b | ||
|
|
0db087908d | ||
|
|
42138d04d6 | ||
|
|
4522a9d0d5 | ||
|
|
7440fcad0e | ||
|
|
fc51c1882f | ||
|
|
e24498b31f | ||
|
|
60fdc79563 | ||
|
|
6729ebc6ea | ||
|
|
c8ff216ce5 | ||
|
|
98c4150cfe | ||
|
|
128332d710 | ||
|
|
eabcb519a4 | ||
|
|
5e14cead3d | ||
|
|
b601f938ff | ||
|
|
4acfda32d0 |
3
.gitattributes
vendored
Normal file
3
.gitattributes
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
* text eol=lf
|
||||||
|
*.cmd text eol=crlf
|
||||||
|
*.png binary
|
||||||
36
.github/stale.yml
vendored
36
.github/stale.yml
vendored
@@ -1,19 +1,19 @@
|
|||||||
# Number of days of inactivity before an issue becomes stale
|
# Number of days of inactivity before an issue becomes stale
|
||||||
daysUntilStale: 60
|
daysUntilStale: 60
|
||||||
# Number of days of inactivity before a stale issue is closed
|
# Number of days of inactivity before a stale issue is closed
|
||||||
daysUntilClose: 7
|
daysUntilClose: 7
|
||||||
# Issues with these labels will never be considered stale
|
# Issues with these labels will never be considered stale
|
||||||
exemptLabels:
|
exemptLabels:
|
||||||
- pinned
|
- pinned
|
||||||
- security
|
- security
|
||||||
- enhancement
|
- enhancement
|
||||||
- bug
|
- bug
|
||||||
# Label to use when marking an issue as stale
|
# Label to use when marking an issue as stale
|
||||||
staleLabel: wontfix
|
staleLabel: wontfix
|
||||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||||
markComment: >
|
markComment: >
|
||||||
This issue has been automatically marked as stale because it has not had
|
This issue has been automatically marked as stale because it has not had
|
||||||
recent activity. It will be closed if no further activity occurs. Thank you
|
recent activity. It will be closed if no further activity occurs. Thank you
|
||||||
for your contributions.
|
for your contributions.
|
||||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||||
closeComment: false
|
closeComment: false
|
||||||
496
.github/workflows/ci.yml
vendored
496
.github/workflows/ci.yml
vendored
@@ -1,227 +1,269 @@
|
|||||||
name: ci
|
name: ci
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
JAVA_VERSION: 21
|
JAVA_VERSION: 21
|
||||||
DOCKER_BUILD_SUMMARY: false
|
DOCKER_BUILD_SUMMARY: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
if: github.event_name != 'pull_request' || github.actor != 'renovate[bot]' # renovate already triggers the build on pushes
|
if: github.event_name != 'pull_request' || github.actor != 'renovate[bot]' # renovate already triggers the build on pushes
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ "ubuntu-latest", "ubuntu-22.04-arm", "windows-latest" ]
|
os: [ "ubuntu-latest", "ubuntu-22.04-arm", "windows-latest" ]
|
||||||
database: [ "h2", "postgresql", "mysql", "mariadb" ]
|
database: [ "h2", "postgresql", "mysql", "mariadb" ]
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
# Checkout
|
# Checkout
|
||||||
- name: Configure git to checkout as-is
|
- name: Checkout
|
||||||
run: git config --global core.autocrlf false
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||||
|
with:
|
||||||
- name: Checkout
|
fetch-depth: 0
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
|
||||||
with:
|
# Setup
|
||||||
fetch-depth: 0
|
- name: Set up GraalVM
|
||||||
|
uses: graalvm/setup-graalvm@01ed653ac833fe80569f1ef9f25585ba2811baab # v1
|
||||||
# Setup
|
with:
|
||||||
- name: Set up GraalVM
|
java-version: ${{ env.JAVA_VERSION }}
|
||||||
uses: graalvm/setup-graalvm@b0cb26a8da53cb3e97cdc0c827d8e3071240e730 # v1
|
distribution: "graalvm"
|
||||||
with:
|
cache: "maven"
|
||||||
java-version: ${{ env.JAVA_VERSION }}
|
|
||||||
distribution: "graalvm"
|
- name: Install Playwright dependencies
|
||||||
cache: "maven"
|
run: sudo apt-get install -y libgbm1
|
||||||
|
if: matrix.os != 'windows-latest'
|
||||||
- name: Install Playwright dependencies
|
|
||||||
run: sudo apt-get install -y libgbm1
|
# Build & Test
|
||||||
if: matrix.os != 'windows-latest'
|
- name: Build with Maven
|
||||||
|
run: mvn --batch-mode --no-transfer-progress install -Pnative -P${{ matrix.database }} -DskipTests=${{ matrix.os == 'windows-latest' && matrix.database != 'h2' }}
|
||||||
# Build & Test
|
|
||||||
- name: Build with Maven
|
# Build pages
|
||||||
run: mvn --batch-mode --no-transfer-progress install -Pnative -P${{ matrix.database }} -DskipTests=${{ matrix.os == 'windows-latest' && matrix.database != 'h2' }}
|
- name: Copy generated markdown documentation to /documentation
|
||||||
|
run: mkdir documentation && cp ./commafeed-server/target/quarkus-generated-doc/config/commafeed-server.md ./documentation/README.md
|
||||||
# Upload artifacts
|
|
||||||
- name: Upload cross-platform app
|
- name: Generate pages
|
||||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4
|
uses: wranders/markdown-to-pages-action@8d8a750832932ac785f5424c8c5543aa0b26bb9a # v1
|
||||||
if: matrix.os == 'ubuntu-latest' # we only need to upload the cross-platform artifact once per database
|
with:
|
||||||
with:
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
name: commafeed-${{ matrix.database }}-jvm
|
out_path: target/pages
|
||||||
path: commafeed-server/target/commafeed-*.zip
|
files: |-
|
||||||
|
README.md
|
||||||
- name: Upload native executable
|
documentation/README.md
|
||||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4
|
|
||||||
with:
|
# Upload artifacts
|
||||||
name: commafeed-${{ matrix.database }}-${{ runner.os }}-${{ runner.arch }}
|
- name: Upload cross-platform app
|
||||||
path: commafeed-server/target/commafeed-*-runner*
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||||
|
if: matrix.os == 'ubuntu-latest' # we only need to upload the cross-platform artifact once per database
|
||||||
docker:
|
with:
|
||||||
runs-on: ubuntu-latest
|
name: commafeed-${{ matrix.database }}-jvm
|
||||||
needs: build
|
path: commafeed-server/target/commafeed-*.zip
|
||||||
env:
|
|
||||||
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
|
- name: Upload native executable
|
||||||
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||||
strategy:
|
with:
|
||||||
matrix:
|
name: commafeed-${{ matrix.database }}-${{ runner.os }}-${{ runner.arch }}
|
||||||
database: [ "h2", "postgresql", "mysql", "mariadb" ]
|
path: commafeed-server/target/commafeed-*-runner*
|
||||||
|
|
||||||
steps:
|
- name: Upload pages
|
||||||
# Checkout
|
uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3
|
||||||
- name: Checkout
|
if: matrix.os == 'ubuntu-latest' && matrix.database == 'h2' # we only need to upload the pages once
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
with:
|
||||||
with:
|
path: target/pages
|
||||||
fetch-depth: 0
|
|
||||||
|
docker:
|
||||||
# Setup
|
runs-on: ubuntu-latest
|
||||||
- name: Set up QEMU
|
needs: build
|
||||||
uses: docker/setup-qemu-action@4574d27a4764455b42196d70a065bc6853246a25 # v3
|
env:
|
||||||
|
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@f7ce87c1d6bead3e36075b2ce75da1f6cc28aaca # v3
|
strategy:
|
||||||
|
matrix:
|
||||||
- name: Install required packages
|
database: [ "h2", "postgresql", "mysql", "mariadb" ]
|
||||||
run: sudo apt-get install -y rename unzip
|
|
||||||
|
steps:
|
||||||
# Prepare artifacts
|
# Checkout
|
||||||
- name: Download artifacts
|
- name: Checkout
|
||||||
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||||
with:
|
with:
|
||||||
pattern: commafeed-${{ matrix.database }}-*
|
fetch-depth: 0
|
||||||
path: ./artifacts
|
|
||||||
merge-multiple: true
|
# Setup
|
||||||
|
- name: Set up QEMU
|
||||||
- name: Set the exec flag on the native executables
|
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3
|
||||||
run: chmod +x artifacts/*-runner
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
- name: Rename native executables to match buildx TARGETARCH
|
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3
|
||||||
run: |
|
|
||||||
rename 's/x86_64/amd64/g' artifacts/*
|
- name: Install required packages
|
||||||
rename 's/aarch_64/arm64/g' artifacts/*
|
run: sudo apt-get install -y rename unzip
|
||||||
|
|
||||||
- name: Unzip jvm package
|
# Prepare artifacts
|
||||||
run: |
|
- name: Download artifacts
|
||||||
unzip artifacts/*-jvm.zip -d artifacts/extracted-jvm-package
|
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4
|
||||||
rename 's/commafeed-.*/quarkus-app/g' artifacts/extracted-jvm-package/*
|
with:
|
||||||
|
pattern: commafeed-${{ matrix.database }}-*
|
||||||
# Docker
|
path: ./artifacts
|
||||||
- name: Login to Container Registry
|
merge-multiple: true
|
||||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3
|
|
||||||
if: ${{ env.DOCKERHUB_USERNAME != '' }}
|
- name: Set the exec flag on the native executables
|
||||||
with:
|
run: chmod +x artifacts/*-runner
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
- name: Rename native executables to match buildx TARGETARCH
|
||||||
|
run: |
|
||||||
## build but don't push for PRs and renovate
|
rename 's/x86_64/amd64/g' artifacts/*
|
||||||
- name: Docker build - native
|
rename 's/aarch_64/arm64/g' artifacts/*
|
||||||
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6
|
|
||||||
with:
|
- name: Unzip jvm package
|
||||||
context: .
|
run: |
|
||||||
file: commafeed-server/src/main/docker/Dockerfile.native
|
unzip artifacts/*-jvm.zip -d artifacts/extracted-jvm-package
|
||||||
push: false
|
rename 's/commafeed-.*/quarkus-app/g' artifacts/extracted-jvm-package/*
|
||||||
platforms: linux/amd64,linux/arm64/v8
|
|
||||||
|
# Docker
|
||||||
- name: Docker build - jvm
|
- name: Login to Container Registry
|
||||||
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6
|
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
|
||||||
with:
|
if: ${{ env.DOCKERHUB_USERNAME != '' }}
|
||||||
context: .
|
with:
|
||||||
file: commafeed-server/src/main/docker/Dockerfile.jvm
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
push: false
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
platforms: linux/amd64,linux/arm64/v8
|
|
||||||
|
## build but don't push for PRs and renovate
|
||||||
## build and push tag
|
- name: Docker build - native
|
||||||
- name: Docker build and push tag - native
|
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6
|
||||||
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6
|
with:
|
||||||
if: ${{ github.ref_type == 'tag' }}
|
context: .
|
||||||
with:
|
file: commafeed-server/src/main/docker/Dockerfile.native
|
||||||
context: .
|
push: false
|
||||||
file: commafeed-server/src/main/docker/Dockerfile.native
|
platforms: linux/amd64,linux/arm64/v8
|
||||||
push: ${{ env.DOCKERHUB_USERNAME != '' }}
|
|
||||||
platforms: linux/amd64,linux/arm64/v8
|
- name: Docker build - jvm
|
||||||
tags: |
|
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6
|
||||||
athou/commafeed:latest-${{ matrix.database }}
|
with:
|
||||||
athou/commafeed:${{ github.ref_name }}-${{ matrix.database }}
|
context: .
|
||||||
|
file: commafeed-server/src/main/docker/Dockerfile.jvm
|
||||||
- name: Docker build and push tag - jvm
|
push: false
|
||||||
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6
|
platforms: linux/amd64,linux/arm64/v8
|
||||||
if: ${{ github.ref_type == 'tag' }}
|
|
||||||
with:
|
## build and push tag
|
||||||
context: .
|
- name: Docker build and push tag - native
|
||||||
file: commafeed-server/src/main/docker/Dockerfile.jvm
|
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6
|
||||||
push: ${{ env.DOCKERHUB_USERNAME != '' }}
|
if: ${{ github.ref_type == 'tag' }}
|
||||||
platforms: linux/amd64,linux/arm64/v8
|
with:
|
||||||
tags: |
|
context: .
|
||||||
athou/commafeed:latest-${{ matrix.database }}-jvm
|
file: commafeed-server/src/main/docker/Dockerfile.native
|
||||||
athou/commafeed:${{ github.ref_name }}-${{ matrix.database }}-jvm
|
push: ${{ env.DOCKERHUB_USERNAME != '' }}
|
||||||
|
platforms: linux/amd64,linux/arm64/v8
|
||||||
## build and push master
|
tags: |
|
||||||
- name: Docker build and push master - native
|
athou/commafeed:latest-${{ matrix.database }}
|
||||||
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6
|
athou/commafeed:${{ github.ref_name }}-${{ matrix.database }}
|
||||||
if: ${{ github.ref_name == 'master' }}
|
|
||||||
with:
|
- name: Docker build and push tag - jvm
|
||||||
context: .
|
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6
|
||||||
file: commafeed-server/src/main/docker/Dockerfile.native
|
if: ${{ github.ref_type == 'tag' }}
|
||||||
push: ${{ env.DOCKERHUB_USERNAME != '' }}
|
with:
|
||||||
platforms: linux/amd64,linux/arm64/v8
|
context: .
|
||||||
tags: athou/commafeed:master-${{ matrix.database }}
|
file: commafeed-server/src/main/docker/Dockerfile.jvm
|
||||||
|
push: ${{ env.DOCKERHUB_USERNAME != '' }}
|
||||||
- name: Docker build and push master - jvm
|
platforms: linux/amd64,linux/arm64/v8
|
||||||
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6
|
tags: |
|
||||||
if: ${{ github.ref_name == 'master' }}
|
athou/commafeed:latest-${{ matrix.database }}-jvm
|
||||||
with:
|
athou/commafeed:${{ github.ref_name }}-${{ matrix.database }}-jvm
|
||||||
context: .
|
|
||||||
file: commafeed-server/src/main/docker/Dockerfile.jvm
|
## build and push master
|
||||||
push: ${{ env.DOCKERHUB_USERNAME != '' }}
|
- name: Docker build and push master - native
|
||||||
platforms: linux/amd64,linux/arm64/v8
|
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6
|
||||||
tags: athou/commafeed:master-${{ matrix.database }}-jvm
|
if: ${{ github.ref_name == 'master' }}
|
||||||
|
with:
|
||||||
release:
|
context: .
|
||||||
runs-on: ubuntu-latest
|
file: commafeed-server/src/main/docker/Dockerfile.native
|
||||||
needs:
|
push: ${{ env.DOCKERHUB_USERNAME != '' }}
|
||||||
- build
|
platforms: linux/amd64,linux/arm64/v8
|
||||||
- docker
|
tags: athou/commafeed:master-${{ matrix.database }}
|
||||||
permissions:
|
|
||||||
contents: write
|
- name: Docker build and push master - jvm
|
||||||
if: github.ref_type == 'tag'
|
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6
|
||||||
|
if: ${{ github.ref_name == 'master' }}
|
||||||
steps:
|
with:
|
||||||
- name: Checkout
|
context: .
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
file: commafeed-server/src/main/docker/Dockerfile.jvm
|
||||||
with:
|
push: ${{ env.DOCKERHUB_USERNAME != '' }}
|
||||||
fetch-depth: 0
|
platforms: linux/amd64,linux/arm64/v8
|
||||||
|
tags: athou/commafeed:master-${{ matrix.database }}-jvm
|
||||||
- name: Download artifacts
|
|
||||||
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4
|
release:
|
||||||
with:
|
runs-on: ubuntu-latest
|
||||||
pattern: commafeed-*
|
needs:
|
||||||
path: ./artifacts
|
- build
|
||||||
merge-multiple: true
|
- docker
|
||||||
|
permissions:
|
||||||
- name: Set the exec flag on the native executables
|
contents: write
|
||||||
run: chmod +x artifacts/*-runner
|
if: github.ref_type == 'tag'
|
||||||
|
|
||||||
- name: Extract Changelog Entry
|
steps:
|
||||||
uses: mindsers/changelog-reader-action@32aa5b4c155d76c94e4ec883a223c947b2f02656 # v2
|
- name: Checkout
|
||||||
id: changelog_reader
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||||
with:
|
with:
|
||||||
version: ${{ github.ref_name }}
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Create GitHub release
|
- name: Download artifacts
|
||||||
uses: ncipollo/release-action@cdcc88a9acf3ca41c16c37bb7d21b9ad48560d87 # v1
|
uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4
|
||||||
with:
|
with:
|
||||||
name: CommaFeed ${{ github.ref_name }}
|
pattern: commafeed-*
|
||||||
body: ${{ steps.changelog_reader.outputs.changes }}
|
path: ./artifacts
|
||||||
artifacts: ./artifacts/*
|
merge-multiple: true
|
||||||
|
|
||||||
- name: Update Docker Hub Description
|
- name: Set the exec flag on the native executables
|
||||||
uses: peter-evans/dockerhub-description@e98e4d1628a5f3be2be7c231e50981aee98723ae # v4
|
run: chmod +x artifacts/*-runner
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
- name: Extract Changelog Entry
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
uses: mindsers/changelog-reader-action@32aa5b4c155d76c94e4ec883a223c947b2f02656 # v2
|
||||||
repository: athou/commafeed
|
id: changelog_reader
|
||||||
short-description: ${{ github.event.repository.description }}
|
with:
|
||||||
readme-filepath: commafeed-server/src/main/docker/README.md
|
version: ${{ github.ref_name }}
|
||||||
|
|
||||||
|
- name: Create GitHub release
|
||||||
|
uses: ncipollo/release-action@440c8c1cb0ed28b9f43e4d1d670870f059653174 # v1
|
||||||
|
with:
|
||||||
|
name: CommaFeed ${{ github.ref_name }}
|
||||||
|
body: ${{ steps.changelog_reader.outputs.changes }}
|
||||||
|
artifacts: ./artifacts/*
|
||||||
|
|
||||||
|
|
||||||
|
update-dockerhub-description:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: release
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Update Docker Hub Description
|
||||||
|
uses: peter-evans/dockerhub-description@432a30c9e07499fd01da9f8a49f0faf9e0ca5b77 # v4
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
repository: athou/commafeed
|
||||||
|
short-description: ${{ github.event.repository.description }}
|
||||||
|
readme-filepath: commafeed-server/src/main/docker/README.md
|
||||||
|
|
||||||
|
|
||||||
|
deploy-pages:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: release
|
||||||
|
permissions:
|
||||||
|
pages: write
|
||||||
|
id-token: write
|
||||||
|
environment:
|
||||||
|
name: github-pages
|
||||||
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4
|
||||||
|
id: deployment
|
||||||
|
|||||||
36
.mvn/wrapper/maven-wrapper.properties
vendored
36
.mvn/wrapper/maven-wrapper.properties
vendored
@@ -1,18 +1,18 @@
|
|||||||
# Licensed to the Apache Software Foundation (ASF) under one
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
# or more contributor license agreements. See the NOTICE file
|
# or more contributor license agreements. See the NOTICE file
|
||||||
# distributed with this work for additional information
|
# distributed with this work for additional information
|
||||||
# regarding copyright ownership. The ASF licenses this file
|
# regarding copyright ownership. The ASF licenses this file
|
||||||
# to you under the Apache License, Version 2.0 (the
|
# to you under the Apache License, Version 2.0 (the
|
||||||
# "License"); you may not use this file except in compliance
|
# "License"); you may not use this file except in compliance
|
||||||
# with the License. You may obtain a copy of the License at
|
# with the License. You may obtain a copy of the License at
|
||||||
#
|
#
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
#
|
#
|
||||||
# Unless required by applicable law or agreed to in writing,
|
# Unless required by applicable law or agreed to in writing,
|
||||||
# software distributed under the License is distributed on an
|
# software distributed under the License is distributed on an
|
||||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
# KIND, either express or implied. See the License for the
|
# KIND, either express or implied. See the License for the
|
||||||
# specific language governing permissions and limitations
|
# specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
distributionType=only-script
|
distributionType=only-script
|
||||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
|
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
|
||||||
|
|||||||
937
CHANGELOG.md
937
CHANGELOG.md
@@ -1,461 +1,476 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## [5.6.0]
|
## [5.7.0]
|
||||||
|
|
||||||
- To better respect the bandwidth of feed owners, the default value of `commafeed.feed-refresh.interval-empirical` is now true. This means feeds no longer refresh exactly every 5 minutes (the default value of `commafeed.feed-refresh.interval`) but between 5 minutes and 4 hours (the default value of the new `commafeed.feed-refresh.max-interval` setting). The interval is calculated based on feed activity, so highly active feeds refresh more often (#1677)
|
- Add Shift+J/Shift+K keyboard shortcuts to navigate to the next/previous feed or category with unread entries (#1746)
|
||||||
- Many previously hardcoded values used in feed refresh interval calculation are now exposed as settings (#1677)
|
- Add the referrer "no-referrer" meta to index.html (#1724)
|
||||||
- Access to local addresses is now blocked to mitigate server-side request forgery (SSRF) attacks, which could potentially expose internal resources. You might want to disable the new `commafeed.http-client.block-local-addresses` setting if you subscribe to feeds only available on your local network and you trust all your users
|
- Load custom JS code when the app is done loading (#1724)
|
||||||
- If a feed responds with a "429 - Too many requests" response, a backoff mechanism is triggered when the response does not contain a "Retry-After" header
|
- Correctly handle feeds that return an unmodified Last-Modified header but a different ETag header (#1730)
|
||||||
|
- Restore gzip compression of responses that was accidentaly disabled since 5.0.0
|
||||||
## [5.5.0]
|
- Fix tooltips not showing up in mobile view
|
||||||
|
- Fix the bookmarklet generator on the About page
|
||||||
- CommaFeed now honors the Retry-After response header and will not try to refresh a feed sooner than the value of this header
|
|
||||||
- Audio enclosures (e.g. podcasts) now fill available entry width
|
## [5.6.1]
|
||||||
- Fix an issue with some labels not correctly internationalized
|
|
||||||
|
- Restore support for iframes in feed entries (#1688)
|
||||||
## [5.4.0]
|
- There is now a package available for Arch Linux thanks to @dcelasun (#1691)
|
||||||
|
|
||||||
- An arm64 native executable is now available for download on the releases page
|
## [5.6.0]
|
||||||
- The native executable Docker image now supports arm64
|
|
||||||
- Fixed an issue with feeds that declared an invalid DOCTYPE (#1260)
|
- To better respect the bandwidth of feed owners, the default value of `commafeed.feed-refresh.interval-empirical` is now true. This means feeds no longer refresh exactly every 5 minutes (the default value of `commafeed.feed-refresh.interval`) but between 5 minutes and 4 hours (the default value of the new `commafeed.feed-refresh.max-interval` setting). The interval is calculated based on feed activity, so highly active feeds refresh more often (#1677)
|
||||||
|
- Many previously hardcoded values used in feed refresh interval calculation are now exposed as settings (#1677)
|
||||||
## [5.3.6]
|
- Access to local addresses is now blocked to mitigate server-side request forgery (SSRF) attacks, which could potentially expose internal resources. You might want to disable the new `commafeed.http-client.block-local-addresses` setting if you subscribe to feeds only available on your local network and you trust all your users
|
||||||
|
- If a feed responds with a "429 - Too many requests" response, a backoff mechanism is triggered when the response does not contain a "Retry-After" header
|
||||||
- Ignore invalid Cache-Control header values (#1619)
|
|
||||||
|
## [5.5.0]
|
||||||
## [5.3.5]
|
|
||||||
|
- CommaFeed now honors the Retry-After response header and will not try to refresh a feed sooner than the value of this header
|
||||||
- Fixed an issue with the aspect ratio of images of some feeds (#1595)
|
- Audio enclosures (e.g. podcasts) now fill available entry width
|
||||||
- CommaFeed now honors the Cache-Control response header and will not try to refresh a feed sooner than its max-age property (#1615)
|
- Fix an issue with some labels not correctly internationalized
|
||||||
- Added support for compilation with JDK 23+. If you're building CommaFeed from sources with a JDK 17 or 21, you may need to update it to the most recent patch version to support `-proc:full` (#1618)
|
|
||||||
|
## [5.4.0]
|
||||||
## [5.3.4]
|
|
||||||
|
- An arm64 native executable is now available for download on the releases page
|
||||||
- Added support for Internationalized Domain Names (#1588)
|
- The native executable Docker image now supports arm64
|
||||||
|
- Fixed an issue with feeds that declared an invalid DOCTYPE (#1260)
|
||||||
## [5.3.3]
|
|
||||||
|
## [5.3.6]
|
||||||
- Removed image bottom margins (#1587)
|
|
||||||
|
- Ignore invalid Cache-Control header values (#1619)
|
||||||
## [5.3.2]
|
|
||||||
|
## [5.3.5]
|
||||||
- Fixed an issue that could cause some images from not being rendered correctly (#1587)
|
|
||||||
|
- Fixed an issue with the aspect ratio of images of some feeds (#1595)
|
||||||
## [5.3.1]
|
- CommaFeed now honors the Cache-Control response header and will not try to refresh a feed sooner than its max-age property (#1615)
|
||||||
|
- Added support for compilation with JDK 23+. If you're building CommaFeed from sources with a JDK 17 or 21, you may need to update it to the most recent patch version to support `-proc:full` (#1618)
|
||||||
- Fixed an issue that could cause some HTTP feeds to return a 400 error (#1572)
|
|
||||||
|
## [5.3.4]
|
||||||
## [5.3.0]
|
|
||||||
|
- Added support for Internationalized Domain Names (#1588)
|
||||||
- Added a setting to set a cooldown on the "fetch all my feeds" action, disabled by default (#1556)
|
|
||||||
- Fixed an issue that could cause entries to not correctly load when using the "next" header button (#1557)
|
## [5.3.3]
|
||||||
|
|
||||||
## [5.2.0]
|
- Removed image bottom margins (#1587)
|
||||||
|
|
||||||
- Added an option to keep a number of entries above the selected entry when scrolling
|
## [5.3.2]
|
||||||
- Added a cache to the HTTP client to reduce the number of requests made to feeds when subscribing (#1431)
|
|
||||||
- Feeds are no longer refreshed between the moment its last user unsubscribes and the moment the feed is cleaned up (every hour)
|
- Fixed an issue that could cause some images from not being rendered correctly (#1587)
|
||||||
- Fixed an issue that could cause entries to not correctly load when using keyboard navigation (#1557)
|
|
||||||
|
## [5.3.1]
|
||||||
## [5.1.1]
|
|
||||||
|
- Fixed an issue that could cause some HTTP feeds to return a 400 error (#1572)
|
||||||
- Fixed database migration issue when upgrading from 5.0.0 to 5.1.0 on MariaDB (#1544)
|
|
||||||
- When feeds without unread entries are hidden from the tree, the feed is displayed in the tree until another one is selected (#1543)
|
## [5.3.0]
|
||||||
|
|
||||||
## [5.1.0]
|
- Added a setting to set a cooldown on the "fetch all my feeds" action, disabled by default (#1556)
|
||||||
|
- Fixed an issue that could cause entries to not correctly load when using the "next" header button (#1557)
|
||||||
- Added a setting for showing/hiding unread count in the browser's tab title/favicon (#1518)
|
|
||||||
- Fixed an issue that could prevent the app from starting on some systems (#1532)
|
## [5.2.0]
|
||||||
- Added a cache busting filter for the webapp index.html and openapi documentation to make sure they are always up to date
|
|
||||||
- Reduced database cleanup log verbosity
|
- Added an option to keep a number of entries above the selected entry when scrolling
|
||||||
|
- Added a cache to the HTTP client to reduce the number of requests made to feeds when subscribing (#1431)
|
||||||
## [5.0.2]
|
- Feeds are no longer refreshed between the moment its last user unsubscribes and the moment the feed is cleaned up (every hour)
|
||||||
|
- Fixed an issue that could cause entries to not correctly load when using keyboard navigation (#1557)
|
||||||
- Fix favicon fetching for Youtube channels in native mode when Google auth key is set
|
|
||||||
- Fix an error that appears in the logs when fetching some favicons
|
## [5.1.1]
|
||||||
|
|
||||||
## [5.0.1]
|
- Fixed database migration issue when upgrading from 5.0.0 to 5.1.0 on MariaDB (#1544)
|
||||||
|
- When feeds without unread entries are hidden from the tree, the feed is displayed in the tree until another one is selected (#1543)
|
||||||
- Configure native compilation to support older CPU architectures (#1524)
|
|
||||||
|
## [5.1.0]
|
||||||
## [5.0.0]
|
|
||||||
|
- Added a setting for showing/hiding unread count in the browser's tab title/favicon (#1518)
|
||||||
CommaFeed is now powered by Quarkus instead of Dropwizard. Read the rationale behind this change in
|
- Fixed an issue that could prevent the app from starting on some systems (#1532)
|
||||||
the [announcement](https://github.com/Athou/commafeed/discussions/1517).
|
- Added a cache busting filter for the webapp index.html and openapi documentation to make sure they are always up to date
|
||||||
The gist of it is that CommaFeed can now be compiled to a native binary, resulting in blazing fast startup times (around
|
- Reduced database cleanup log verbosity
|
||||||
0.3s) and very low memory footprint (< 50M).
|
|
||||||
|
## [5.0.2]
|
||||||
- CommaFeed now has a different package for each supported database.
|
|
||||||
- If you are deploying CommaFeed with a precompiled package, please
|
- Fix favicon fetching for Youtube channels in native mode when Google auth key is set
|
||||||
read [this section of the README](https://github.com/Athou/commafeed/tree/master?tab=readme-ov-file#download-a-precompiled-package).
|
- Fix an error that appears in the logs when fetching some favicons
|
||||||
- If you are building CommaFeed from sources, please
|
|
||||||
read [this section of the README](https://github.com/Athou/commafeed/tree/master?tab=readme-ov-file#build-from-sources).
|
## [5.0.1]
|
||||||
- If you are using the Docker image, please read the instructions on
|
|
||||||
the [Docker Hub page](https://hub.docker.com/r/athou/commafeed).
|
- Configure native compilation to support older CPU architectures (#1524)
|
||||||
- Due to the switch to Quarkus, the way CommaFeed is configured is very different (the `config.yml` file is gone).
|
|
||||||
Please
|
## [5.0.0]
|
||||||
read [this section of the README](https://github.com/Athou/commafeed/tree/master?tab=readme-ov-file#configuration).
|
|
||||||
Note that a lot of configuration elements have been removed or renamed and are now nested/grouped by feature.
|
CommaFeed is now powered by Quarkus instead of Dropwizard. Read the rationale behind this change in
|
||||||
- Added a setting to prevent parsing large feeds to avoid out of memory errors. The default is 5MB.
|
the [announcement](https://github.com/Athou/commafeed/discussions/1517).
|
||||||
- Use a different icon for filtering unread entries and marking an entry as read (#1506)
|
The gist of it is that CommaFeed can now be compiled to a native binary, resulting in blazing fast startup times (around
|
||||||
- Added various HTML attributes to ease custom JS/CSS customization (#1507)
|
0.3s) and very low memory footprint (< 50M).
|
||||||
- The Redis cache has been removed. There have been multiple enhancements to the feed refresh engine and it is no longer
|
|
||||||
needed, even for instances with a large number of feeds.
|
- CommaFeed now has a different package for each supported database.
|
||||||
- The H2 migration tool that automatically upgrades H2 databases from format 2 to 3 has been removed. If you're using
|
- If you are deploying CommaFeed with a precompiled package, please
|
||||||
the H2 embedded database, please upgrade to at least version 4.3.0 before upgrading to CommaFeed 5.0.0.
|
read [this section of the README](https://github.com/Athou/commafeed/tree/master?tab=readme-ov-file#download-a-precompiled-package).
|
||||||
|
- If you are building CommaFeed from sources, please
|
||||||
## [4.6.0]
|
read [this section of the README](https://github.com/Athou/commafeed/tree/master?tab=readme-ov-file#build-from-sources).
|
||||||
|
- If you are using the Docker image, please read the instructions on
|
||||||
- switched from Temurin to OpenJ9 as the JVM used in the Docker image, resulting in memory usage reduction by up to 50%
|
the [Docker Hub page](https://hub.docker.com/r/athou/commafeed).
|
||||||
- fix an issue that could cause old entries to reappear if they were updated by their author (#1486)
|
- Due to the switch to Quarkus, the way CommaFeed is configured is very different (the `config.yml` file is gone).
|
||||||
- show all entries regardless of their read status when searching with keywords, even if the ui is configured to show
|
Please
|
||||||
unread entries only
|
read [this section of the README](https://github.com/Athou/commafeed/tree/master?tab=readme-ov-file#configuration).
|
||||||
|
Note that a lot of configuration elements have been removed or renamed and are now nested/grouped by feature.
|
||||||
## [4.5.0]
|
- Added a setting to prevent parsing large feeds to avoid out of memory errors. The default is 5MB.
|
||||||
|
- Use a different icon for filtering unread entries and marking an entry as read (#1506)
|
||||||
- significantly reduce the time needed to retrieve entries or mark them as read, especially when there are a lot of
|
- Added various HTML attributes to ease custom JS/CSS customization (#1507)
|
||||||
entries (#1452)
|
- The Redis cache has been removed. There have been multiple enhancements to the feed refresh engine and it is no longer
|
||||||
- fix a race condition where a feed could be refreshed before it was created in the database
|
needed, even for instances with a large number of feeds.
|
||||||
- fix an issue that could cause the websocket notification to contain the wrong number of unread entries when using
|
- The H2 migration tool that automatically upgrades H2 databases from format 2 to 3 has been removed. If you're using
|
||||||
mysql/mariadb
|
the H2 embedded database, please upgrade to at least version 4.3.0 before upgrading to CommaFeed 5.0.0.
|
||||||
- fix an error when trying to mark all starred entries as read
|
|
||||||
- remove the `onlyIds` parameter from REST endpoints since retrieving all the entries is now just as fast
|
## [4.6.0]
|
||||||
- remove support for microsoft sqlserver because it's not covered with integration tests (please open an issue if you'd
|
|
||||||
like it back)
|
- switched from Temurin to OpenJ9 as the JVM used in the Docker image, resulting in memory usage reduction by up to 50%
|
||||||
|
- fix an issue that could cause old entries to reappear if they were updated by their author (#1486)
|
||||||
## [4.4.1]
|
- show all entries regardless of their read status when searching with keywords, even if the ui is configured to show
|
||||||
|
unread entries only
|
||||||
- fix vertical scrolling issues with Safari (#1168)
|
|
||||||
- the default value for new users for the "star entry" button and the "open in new tab" button in the entry headers is
|
## [4.5.0]
|
||||||
now "on desktop" instead of "always"
|
|
||||||
- the "keyboard shortcuts" help page now shows "Cmd" instead of "Ctrl" on macOS (#1389)
|
- significantly reduce the time needed to retrieve entries or mark them as read, especially when there are a lot of
|
||||||
- remove a superfluous feed fetch when subscribing to a feed (#1431)
|
entries (#1452)
|
||||||
- the Docker image now uses Java 21
|
- fix a race condition where a feed could be refreshed before it was created in the database
|
||||||
|
- fix an issue that could cause the websocket notification to contain the wrong number of unread entries when using
|
||||||
## [4.4.0]
|
mysql/mariadb
|
||||||
|
- fix an error when trying to mark all starred entries as read
|
||||||
- add support for sharing using the browser native capabilities if available (#1255)
|
- remove the `onlyIds` parameter from REST endpoints since retrieving all the entries is now just as fast
|
||||||
- add a button in the entry headers to star an entry (#1025)
|
- remove support for microsoft sqlserver because it's not covered with integration tests (please open an issue if you'd
|
||||||
- add a button in the entry headers to open links in a new tab (#1333)
|
like it back)
|
||||||
- add two options in the settings to toggle those buttons
|
|
||||||
- accept .opml file extension when importing and export with the .opml extension
|
## [4.4.1]
|
||||||
- the "mark as read" option is no longer shown in the context menu for entries that are too old to be marked as read (
|
|
||||||
older than `keepStatusDays`) (#1303)
|
- fix vertical scrolling issues with Safari (#1168)
|
||||||
|
- the default value for new users for the "star entry" button and the "open in new tab" button in the entry headers is
|
||||||
## [4.3.3]
|
now "on desktop" instead of "always"
|
||||||
|
- the "keyboard shortcuts" help page now shows "Cmd" instead of "Ctrl" on macOS (#1389)
|
||||||
- fix OPML import (#1279)
|
- remove a superfluous feed fetch when subscribing to a feed (#1431)
|
||||||
|
- the Docker image now uses Java 21
|
||||||
## [4.3.2]
|
|
||||||
|
## [4.4.0]
|
||||||
- added support for unix sockets (#1278)
|
|
||||||
|
- add support for sharing using the browser native capabilities if available (#1255)
|
||||||
## [4.3.1]
|
- add a button in the entry headers to star an entry (#1025)
|
||||||
|
- add a button in the entry headers to open links in a new tab (#1333)
|
||||||
- fix an issue that prevents new feeds from being added when mysql/mariadb is used as the database and the database
|
- add two options in the settings to toggle those buttons
|
||||||
timezone is not UTC (#1239)
|
- accept .opml file extension when importing and export with the .opml extension
|
||||||
- videos in enclosures can no longer have a width larger than the page (#1240)
|
- the "mark as read" option is no longer shown in the context menu for entries that are too old to be marked as read (
|
||||||
|
older than `keepStatusDays`) (#1303)
|
||||||
## [4.3.0]
|
|
||||||
|
## [4.3.3]
|
||||||
- h2 (the embedded database) has been upgraded to 2.2.224
|
|
||||||
- this version uses a different file format than 2.1.x, the first time you start CommaFeed with this version, the
|
- fix OPML import (#1279)
|
||||||
database will be automatically converted to the new format
|
|
||||||
- add a setting to completely disable scrolling to selected entry (#1157)
|
## [4.3.2]
|
||||||
- add a css class reflecting the current view mode to ease custom css rules (#1232)
|
|
||||||
- fix an issue that prevents new feeds from being added when mysql/mariadb is used as the database (#1239)
|
- added support for unix sockets (#1278)
|
||||||
|
|
||||||
## [4.2.1]
|
## [4.3.1]
|
||||||
|
|
||||||
- fix an issue that caused the tree to show an incorrect unread count after a websocket notification because entries
|
- fix an issue that prevents new feeds from being added when mysql/mariadb is used as the database and the database
|
||||||
that were already marked as read by a filtering expression were not ignored (#1191)
|
timezone is not UTC (#1239)
|
||||||
|
- videos in enclosures can no longer have a width larger than the page (#1240)
|
||||||
## [4.2.0]
|
|
||||||
|
## [4.3.0]
|
||||||
- add a setting to display the action buttons in the footer instead of in the header on mobile (#1121)
|
|
||||||
- the websocket notification now contains everything needed to update the UI, the client no longer needs to make an API
|
- h2 (the embedded database) has been upgraded to 2.2.224
|
||||||
call to get the latest data when receiving the notification
|
- this version uses a different file format than 2.1.x, the first time you start CommaFeed with this version, the
|
||||||
- add a workaround to the Fever API for the Unread iOS app (#1188)
|
database will be automatically converted to the new format
|
||||||
- fix an issue that caused dates to be saved incorrectly if the database server and the application server were in
|
- add a setting to completely disable scrolling to selected entry (#1157)
|
||||||
different timezones (#1187)
|
- add a css class reflecting the current view mode to ease custom css rules (#1232)
|
||||||
|
- fix an issue that prevents new feeds from being added when mysql/mariadb is used as the database (#1239)
|
||||||
## [4.1.0]
|
|
||||||
|
## [4.2.1]
|
||||||
- it is now possible to open the sidebar on mobile by swiping to the right (#1098)
|
|
||||||
- swiping to mark entries as read/unread changed from swiping right to left because swiping right now opens the sidebar
|
- fix an issue that caused the tree to show an incorrect unread count after a websocket notification because entries
|
||||||
- the full hierarchy of categories are now displayed in the category dropdown (#1045)
|
that were already marked as read by a filtering expression were not ignored (#1191)
|
||||||
- added a setting `maxEntriesAgeDays` to delete old entries based on their age during database cleanup.
|
|
||||||
The setting is disabled by default for existing installations, except for the docker image where it is enabled and set
|
## [4.2.0]
|
||||||
to 365 days
|
|
||||||
- if user registrations are disabled on your instance which is the default behavior, users are redirected on the login
|
- add a setting to display the action buttons in the footer instead of in the header on mobile (#1121)
|
||||||
page instead of the welcome page when not logged in (#1185)
|
- the websocket notification now contains everything needed to update the UI, the client no longer needs to make an API
|
||||||
- the sidebar resizer is no longer shown in the middle of the screen on mobile
|
call to get the latest data when receiving the notification
|
||||||
- when using the system color scheme and the system is using a dark theme, feed entries no longer flicker on load
|
- add a workaround to the Fever API for the Unread iOS app (#1188)
|
||||||
- the demo account (if enabled) cannot register custom javascript code anymore
|
- fix an issue that caused dates to be saved incorrectly if the database server and the application server were in
|
||||||
- removed the usage of `toSorted` in the client because older browsers do not support it (#1183)
|
different timezones (#1187)
|
||||||
- the openapi documentation is no longer cached by the browser so you always have access to the latest version
|
|
||||||
- added a memory management section to the readme, reading it is recommended if you are running CommaFeed on a server
|
## [4.1.0]
|
||||||
with limited memory
|
|
||||||
- fixed an issue that caused users without an email address set to be unable to edit their profile (#1184)
|
- it is now possible to open the sidebar on mobile by swiping to the right (#1098)
|
||||||
|
- swiping to mark entries as read/unread changed from swiping right to left because swiping right now opens the sidebar
|
||||||
## [4.0.0]
|
- the full hierarchy of categories are now displayed in the category dropdown (#1045)
|
||||||
|
- added a setting `maxEntriesAgeDays` to delete old entries based on their age during database cleanup.
|
||||||
- migrated from dropwizard 2 to dropwizard 4, Java 17+ is now required
|
The setting is disabled by default for existing installations, except for the docker image where it is enabled and set
|
||||||
- entries that were fetched and inserted in the database but not yet shown in the UI are no longer marked as read when
|
to 365 days
|
||||||
marking all entries as read
|
- if user registrations are disabled on your instance which is the default behavior, users are redirected on the login
|
||||||
- your custom sidebar width is now persisted in the local storage of your browser
|
page instead of the welcome page when not logged in (#1185)
|
||||||
- there is now a third color scheme option in addition to light and dark: system (follows the system color scheme)
|
- the sidebar resizer is no longer shown in the middle of the screen on mobile
|
||||||
- added support for youtube playlist favicons
|
- when using the system color scheme and the system is using a dark theme, feed entries no longer flicker on load
|
||||||
- custom JS code is now executed when the app is done loading instead of when the page is loaded
|
- the demo account (if enabled) cannot register custom javascript code anymore
|
||||||
- the favicon is now correctly returned for feeds that return an invalid content type
|
- removed the usage of `toSorted` in the client because older browsers do not support it (#1183)
|
||||||
- the feed refresh engine now uses httpclient5 with connection pooling and no longer creates a new client for each
|
- the openapi documentation is no longer cached by the browser so you always have access to the latest version
|
||||||
request, reducing CPU usage
|
- added a memory management section to the readme, reading it is recommended if you are running CommaFeed on a server
|
||||||
- updated UI library Mantine to 7.0, improving performance
|
with limited memory
|
||||||
- the h2 embedded database is now compacted on shutdown to reclaim unused space
|
- fixed an issue that caused users without an email address set to be unable to edit their profile (#1184)
|
||||||
- the admin connector on port 8084 is now disabled in config.yml.example. Disabling it in your config.yml is
|
|
||||||
recommended (see https://github.com/Athou/commafeed/commit/929df60f09cce56020b0962ab111cd8349b271b0)
|
## [4.0.0]
|
||||||
- migrated documentation from swagger 2 to openapi 3
|
|
||||||
- added a GET method to the fever api to indicate that the endpoint is working correctly when accessed from a browser
|
- migrated from dropwizard 2 to dropwizard 4, Java 17+ is now required
|
||||||
- the websocket connection can now be disabled, the websocket ping interval and the tree reload interval can now be
|
- entries that were fetched and inserted in the database but not yet shown in the UI are no longer marked as read when
|
||||||
configured (see config.yml.example)
|
marking all entries as read
|
||||||
- the websocket connection now works correctly when the context root of the application is not "/"
|
- your custom sidebar width is now persisted in the local storage of your browser
|
||||||
- unstable pubsubhubbub support was removed
|
- there is now a third color scheme option in addition to light and dark: system (follows the system color scheme)
|
||||||
|
- added support for youtube playlist favicons
|
||||||
## [3.10.1]
|
- custom JS code is now executed when the app is done loading instead of when the page is loaded
|
||||||
|
- the favicon is now correctly returned for feeds that return an invalid content type
|
||||||
- swap next and previous buttons (#1159)
|
- the feed refresh engine now uses httpclient5 with connection pooling and no longer creates a new client for each
|
||||||
- unread count for subscriptions will now be shortened starting at 10k instead of 1k
|
request, reducing CPU usage
|
||||||
- increased websocket ping interval to just under a minute to reduce data and battery usage on mobile
|
- updated UI library Mantine to 7.0, improving performance
|
||||||
- only refresh subscription tree on a timer if websocket connection is unavailable
|
- the h2 embedded database is now compacted on shutdown to reclaim unused space
|
||||||
- the Docker image now uses less memory by returning unused memory to the OS
|
- the admin connector on port 8084 is now disabled in config.yml.example. Disabling it in your config.yml is
|
||||||
- add support for Java 21
|
recommended (see https://github.com/Athou/commafeed/commit/929df60f09cce56020b0962ab111cd8349b271b0)
|
||||||
|
- migrated documentation from swagger 2 to openapi 3
|
||||||
## [3.10.0]
|
- added a GET method to the fever api to indicate that the endpoint is working correctly when accessed from a browser
|
||||||
|
- the websocket connection can now be disabled, the websocket ping interval and the tree reload interval can now be
|
||||||
- added a Fever-compatible API that is usable with mobile clients that support the Fever API (see instructions in
|
configured (see config.yml.example)
|
||||||
Settings -> Profile)
|
- the websocket connection now works correctly when the context root of the application is not "/"
|
||||||
- long entry titles are no longer shortened in the detailed view
|
- unstable pubsubhubbub support was removed
|
||||||
- added the "s" keyboard shortcut to star/unstar entries
|
|
||||||
- http sessions are now stored in the database (they were stored on disk before)
|
## [3.10.1]
|
||||||
- fixed an issue that made it impossible to override the database url in a config.yml mounted in the Docker image
|
|
||||||
|
- swap next and previous buttons (#1159)
|
||||||
## [3.9.0]
|
- unread count for subscriptions will now be shortened starting at 10k instead of 1k
|
||||||
|
- increased websocket ping interval to just under a minute to reduce data and battery usage on mobile
|
||||||
- improve performance by disabling the loader when nothing is loading (most noticeable on mobile)
|
- only refresh subscription tree on a timer if websocket connection is unavailable
|
||||||
- added a setting to disable the 'mark all as read' confirmation
|
- the Docker image now uses less memory by returning unused memory to the OS
|
||||||
- added a setting to disable the custom context menu
|
- add support for Java 21
|
||||||
- if the custom context is enabled, it can still be disabled by pressing the shift key
|
|
||||||
- the announcement feature is now working again and supports html ('announcement' configuration element in config.yml)
|
## [3.10.0]
|
||||||
- add support for MariaDB 11+
|
|
||||||
- fix entry header shortly rendered as mobile on desktop, causing a small visual glitch
|
- added a Fever-compatible API that is usable with mobile clients that support the Fever API (see instructions in
|
||||||
- fix an issue that could cause a feed to not refresh correctly if the url was very long
|
Settings -> Profile)
|
||||||
- database cleanup batch size is now configurable
|
- long entry titles are no longer shortened in the detailed view
|
||||||
- css parsing errors are no longer logged to the standard output
|
- added the "s" keyboard shortcut to star/unstar entries
|
||||||
- fix small errors in the api documentation
|
- http sessions are now stored in the database (they were stored on disk before)
|
||||||
|
- fixed an issue that made it impossible to override the database url in a config.yml mounted in the Docker image
|
||||||
## [3.8.1]
|
|
||||||
|
## [3.9.0]
|
||||||
- in expanded mode, don't scroll when clicking on the body of the current entry
|
|
||||||
- improve content cleanup task performance for instances with a very large number of feeds
|
- improve performance by disabling the loader when nothing is loading (most noticeable on mobile)
|
||||||
|
- added a setting to disable the 'mark all as read' confirmation
|
||||||
## [3.8.0]
|
- added a setting to disable the custom context menu
|
||||||
|
- if the custom context is enabled, it can still be disabled by pressing the shift key
|
||||||
- add previous and next buttons in the toolbar
|
- the announcement feature is now working again and supports html ('announcement' configuration element in config.yml)
|
||||||
- add a setting to always scroll selected entry to the top of the page, even if it fits entirely on screen
|
- add support for MariaDB 11+
|
||||||
- clicking on the body of an entry in expanded mode selects it and marks it as read
|
- fix entry header shortly rendered as mobile on desktop, causing a small visual glitch
|
||||||
- add rich text editor with autocomplete for custom css and js code in settings (desktop only)
|
- fix an issue that could cause a feed to not refresh correctly if the url was very long
|
||||||
- dramatically improve performance while scrolling
|
- database cleanup batch size is now configurable
|
||||||
- fix broken welcome page mobile layout
|
- css parsing errors are no longer logged to the standard output
|
||||||
- format dates in user locale instead of GMT in relative date popups
|
- fix small errors in the api documentation
|
||||||
|
|
||||||
## [3.7.0]
|
## [3.8.1]
|
||||||
|
|
||||||
- the sidebar is now resizable
|
- in expanded mode, don't scroll when clicking on the body of the current entry
|
||||||
- added the "f" keyboard shortcut to hide the sidebar
|
- improve content cleanup task performance for instances with a very large number of feeds
|
||||||
- added tooltips to relative dates with the exact date
|
|
||||||
- add a setting to hide commafeed from search engines (exposes a robots.txt file, enabled by default)
|
## [3.8.0]
|
||||||
- the browser extension unread count now updates when articles are marked as read/unread in the app
|
|
||||||
- The "b" keyboard shortcut now works as expected on Chrome but requires the browser extension to be installed
|
- add previous and next buttons in the toolbar
|
||||||
- dark mode has been disabled on the api documentation page as it was unreadable
|
- add a setting to always scroll selected entry to the top of the page, even if it fits entirely on screen
|
||||||
- improvement to the feed refresh queuing logic when "heavy load" mode is enabled
|
- clicking on the body of an entry in expanded mode selects it and marks it as read
|
||||||
- fix a bug that could prevent feeds and categories from being edited
|
- add rich text editor with autocomplete for custom css and js code in settings (desktop only)
|
||||||
|
- dramatically improve performance while scrolling
|
||||||
## [3.6.0]
|
- fix broken welcome page mobile layout
|
||||||
|
- format dates in user locale instead of GMT in relative date popups
|
||||||
- add a button to open CommaFeed in a new tab and a button to open options when using the browser extension
|
|
||||||
- clicking on the entry title in expanded mode now opens the link instead of doing nothing
|
## [3.7.0]
|
||||||
- add tooltips to buttons when the mobile layout is used on desktop
|
|
||||||
- redirect the user to the welcome page if the user was deleted from the database
|
- the sidebar is now resizable
|
||||||
- add link to api documentation on welcome page
|
- added the "f" keyboard shortcut to hide the sidebar
|
||||||
- the unread count is now correctly updated when using the "/next" bookmarklet while redis cache is enabled
|
- added tooltips to relative dates with the exact date
|
||||||
|
- add a setting to hide commafeed from search engines (exposes a robots.txt file, enabled by default)
|
||||||
## [3.5.0]
|
- the browser extension unread count now updates when articles are marked as read/unread in the app
|
||||||
|
- The "b" keyboard shortcut now works as expected on Chrome but requires the browser extension to be installed
|
||||||
- add compatibility with the new version of the CommaFeed browser extension
|
- dark mode has been disabled on the api documentation page as it was unreadable
|
||||||
- disable pull-to-refresh on mobile as it messes with vertical scrolling
|
- improvement to the feed refresh queuing logic when "heavy load" mode is enabled
|
||||||
- add css classes to feed entries to help with custom css rules
|
- fix a bug that could prevent feeds and categories from being edited
|
||||||
- api documentation page no longer requires users to be authenticated
|
|
||||||
- add a setting to limit the number of feeds a user can subscribe to
|
## [3.6.0]
|
||||||
- add a setting to disable strict password policy
|
|
||||||
- add feed refresh engine metrics
|
- add a button to open CommaFeed in a new tab and a button to open options when using the browser extension
|
||||||
- fix redis timeouts
|
- clicking on the entry title in expanded mode now opens the link instead of doing nothing
|
||||||
|
- add tooltips to buttons when the mobile layout is used on desktop
|
||||||
## [3.4.0]
|
- redirect the user to the welcome page if the user was deleted from the database
|
||||||
|
- add link to api documentation on welcome page
|
||||||
- add support for arm64 docker images
|
- the unread count is now correctly updated when using the "/next" bookmarklet while redis cache is enabled
|
||||||
- add divider to visually separate read-only information from form on the profile settings page
|
|
||||||
- reduce javascript bundle size by 30% by loading only the necessary translations
|
## [3.5.0]
|
||||||
- add a standalone donate page with all ways to support CommaFeed
|
|
||||||
- fix an issue introduced in 3.1.0 that could make CommaFeed not refresh feeds as fast as before on instances with lots
|
- add compatibility with the new version of the CommaFeed browser extension
|
||||||
of feeds
|
- disable pull-to-refresh on mobile as it messes with vertical scrolling
|
||||||
- fix alignment of icon with text for category tree nodes
|
- add css classes to feed entries to help with custom css rules
|
||||||
- fix alignment of burger button with the rest of the header on mobile
|
- api documentation page no longer requires users to be authenticated
|
||||||
|
- add a setting to limit the number of feeds a user can subscribe to
|
||||||
## [3.3.2]
|
- add a setting to disable strict password policy
|
||||||
|
- add feed refresh engine metrics
|
||||||
- restore entry selection indicator (left orange border) that was lost with the mantine 6.x upgrade (3.3.0)
|
- fix redis timeouts
|
||||||
- add dividers to visually separate read-only information from forms on feed and category details pages
|
|
||||||
- reduced javascript bundle size by 10%
|
## [3.4.0]
|
||||||
|
|
||||||
## [3.3.1]
|
- add support for arm64 docker images
|
||||||
|
- add divider to visually separate read-only information from form on the profile settings page
|
||||||
- fix long feed names not being shortened to respect tree max width
|
- reduce javascript bundle size by 30% by loading only the necessary translations
|
||||||
|
- add a standalone donate page with all ways to support CommaFeed
|
||||||
## [3.3.0]
|
- fix an issue introduced in 3.1.0 that could make CommaFeed not refresh feeds as fast as before on instances with lots
|
||||||
|
of feeds
|
||||||
- there are now database changes, rolling back to 2.x will no longer be possible
|
- fix alignment of icon with text for category tree nodes
|
||||||
- restore support for user custom CSS rules
|
- fix alignment of burger button with the rest of the header on mobile
|
||||||
- add support for user custom JS code that will be executed on page load
|
|
||||||
|
## [3.3.2]
|
||||||
## [3.2.0]
|
|
||||||
|
- restore entry selection indicator (left orange border) that was lost with the mantine 6.x upgrade (3.3.0)
|
||||||
- restore the welcome page
|
- add dividers to visually separate read-only information from forms on feed and category details pages
|
||||||
- only apply hover effect for unread entries (same as commafeed v2)
|
- reduced javascript bundle size by 10%
|
||||||
- move notifications at the bottom of the screen
|
|
||||||
- always use https for sharing urls
|
## [3.3.1]
|
||||||
- add support for redis ACLs
|
|
||||||
- transition to google analytics v4
|
- fix long feed names not being shortened to respect tree max width
|
||||||
|
|
||||||
## [3.1.0]
|
## [3.3.0]
|
||||||
|
|
||||||
- add an even more compact layout
|
- there are now database changes, rolling back to 2.x will no longer be possible
|
||||||
- restore hover effect from commafeed 2.x
|
- restore support for user custom CSS rules
|
||||||
- view mode (compact, expanded, ...) is now stored on the device so you can have a different view mode on desktop and
|
- add support for user custom JS code that will be executed on page load
|
||||||
mobile
|
|
||||||
- fix for the "Illegal attempt to associate a collection with two open sessions." error
|
## [3.2.0]
|
||||||
- feed fetching workflow is now orchestrated with rxjava, removing a lot of code
|
|
||||||
|
- restore the welcome page
|
||||||
## [3.0.1]
|
- only apply hover effect for unread entries (same as commafeed v2)
|
||||||
|
- move notifications at the bottom of the screen
|
||||||
- allow env variable substitution in config.yml
|
- always use https for sharing urls
|
||||||
- e.g. having a custom config.yml file with `app.session.path=${SOME_ENV_VAR}` will substitute `SOME_ENV_VAR` with its
|
- add support for redis ACLs
|
||||||
value
|
- transition to google analytics v4
|
||||||
- allow env variable prefixed with `CF_` to override config.yml properties
|
|
||||||
- e.g. setting `CF_APP_ALLOWREGISTRATIONS=true` will set `app.allowRegistrations` to `true`
|
## [3.1.0]
|
||||||
|
|
||||||
## [3.0.0]
|
- add an even more compact layout
|
||||||
|
- restore hover effect from commafeed 2.x
|
||||||
- complete overhaul of the UI
|
- view mode (compact, expanded, ...) is now stored on the device so you can have a different view mode on desktop and
|
||||||
- backend and frontend are now in separate maven modules
|
mobile
|
||||||
- no changes to the api or the database
|
- fix for the "Illegal attempt to associate a collection with two open sessions." error
|
||||||
- Docker images are now automatically built and available at https://hub.docker.com/r/athou/commafeed
|
- feed fetching workflow is now orchestrated with rxjava, removing a lot of code
|
||||||
|
|
||||||
## [2.6.0]
|
## [3.0.1]
|
||||||
|
|
||||||
- add support for media content as a backup for missing content (useful for youtube feeds)
|
- allow env variable substitution in config.yml
|
||||||
- correctly follow http error code 308 redirects
|
- e.g. having a custom config.yml file with `app.session.path=${SOME_ENV_VAR}` will substitute `SOME_ENV_VAR` with its
|
||||||
- fixed a bug that prevented users from deleting their account
|
value
|
||||||
- fixed a bug that made commafeed store entry contents multiple times
|
- allow env variable prefixed with `CF_` to override config.yml properties
|
||||||
- fixed a bug that prevented the app to be used as an installed app on mobile devices if the context path of commafeed
|
- e.g. setting `CF_APP_ALLOWREGISTRATIONS=true` will set `app.allowRegistrations` to `true`
|
||||||
was not "/"
|
|
||||||
- fixed a bug that prevented entries from being "marked as read older than xxx" for a feed that was just added
|
## [3.0.0]
|
||||||
- removed support for google+ and readability as those services no longer exist
|
|
||||||
- removed support for deploying on openshift
|
- complete overhaul of the UI
|
||||||
- removed alphabetical sorting of entries because of really poor performance (title cannot be indexed)
|
- backend and frontend are now in separate maven modules
|
||||||
- improve performance for instances with the heavy load setting enabled by preventing CommaFeed from fetching feeds from
|
- no changes to the api or the database
|
||||||
users that did not log in for a long time
|
- Docker images are now automatically built and available at https://hub.docker.com/r/athou/commafeed
|
||||||
- various dependencies upgrades (notably dropwizard from 1.3 to 2.1)
|
|
||||||
- add support for mariadb
|
## [2.6.0]
|
||||||
- add support for java17+ runtime
|
|
||||||
- various security improvements
|
- add support for media content as a backup for missing content (useful for youtube feeds)
|
||||||
|
- correctly follow http error code 308 redirects
|
||||||
## [2.5.0]
|
- fixed a bug that prevented users from deleting their account
|
||||||
|
- fixed a bug that made commafeed store entry contents multiple times
|
||||||
- unread count is now displayed in a favicon badge when supported
|
- fixed a bug that prevented the app to be used as an installed app on mobile devices if the context path of commafeed
|
||||||
- the user agent string for the bot fetching feeds is now configurable
|
was not "/"
|
||||||
- feed parsing performance improvements
|
- fixed a bug that prevented entries from being "marked as read older than xxx" for a feed that was just added
|
||||||
- support for java9+ runtime
|
- removed support for google+ and readability as those services no longer exist
|
||||||
- can now properly start from an empty postgresql database
|
- removed support for deploying on openshift
|
||||||
|
- removed alphabetical sorting of entries because of really poor performance (title cannot be indexed)
|
||||||
## [2.4.0]
|
- improve performance for instances with the heavy load setting enabled by preventing CommaFeed from fetching feeds from
|
||||||
|
users that did not log in for a long time
|
||||||
- users were not able to change password or delete account
|
- various dependencies upgrades (notably dropwizard from 1.3 to 2.1)
|
||||||
- fix api key generation
|
- add support for mariadb
|
||||||
- feed entries can now be sorted alphabetically
|
- add support for java17+ runtime
|
||||||
- fix facebook sharing
|
- various security improvements
|
||||||
- fix layout on iOS
|
|
||||||
- postgresql driver update (fix for postgres 9.6)
|
## [2.5.0]
|
||||||
- various internationalization fixes
|
|
||||||
- security fixes
|
- unread count is now displayed in a favicon badge when supported
|
||||||
|
- the user agent string for the bot fetching feeds is now configurable
|
||||||
## [2.3.0]
|
- feed parsing performance improvements
|
||||||
|
- support for java9+ runtime
|
||||||
- dropwizard upgrade 0.9.1
|
- can now properly start from an empty postgresql database
|
||||||
- feed enclosures are hidden if they already displayed in the content
|
|
||||||
- fix youtube favicons
|
## [2.4.0]
|
||||||
- various internationalization fixes
|
|
||||||
|
- users were not able to change password or delete account
|
||||||
## [2.2.0]
|
- fix api key generation
|
||||||
|
- feed entries can now be sorted alphabetically
|
||||||
- fix youtube and instagram favicon fetching
|
- fix facebook sharing
|
||||||
- mark as read filter was lost when a feed was rearranged with drag&drop
|
- fix layout on iOS
|
||||||
- feed entry categories are now displayed if available
|
- postgresql driver update (fix for postgres 9.6)
|
||||||
- various performance and dependencies upgrades
|
- various internationalization fixes
|
||||||
- java8 is now required
|
- security fixes
|
||||||
|
|
||||||
## [2.1.0]
|
## [2.3.0]
|
||||||
|
|
||||||
- dropwizard upgrade to 0.8.0
|
- dropwizard upgrade 0.9.1
|
||||||
- you have to remove the "app.contextPath" setting from your yml file, you can optionally use
|
- feed enclosures are hidden if they already displayed in the content
|
||||||
server.applicationContextPath instead
|
- fix youtube favicons
|
||||||
- new setting app.maxFeedCapacity for deleting old entries
|
- various internationalization fixes
|
||||||
- ability to set filtering expressions for subscriptions to automatically mark new entries as read based on title,
|
|
||||||
content, author or url.
|
## [2.2.0]
|
||||||
- ability to use !keyword or -keyword to exclude a keyword from a search query
|
|
||||||
- facebook feeds now show user favicon instead of facebook favicon
|
- fix youtube and instagram favicon fetching
|
||||||
- new dark theme 'nightsky'
|
- mark as read filter was lost when a feed was rearranged with drag&drop
|
||||||
|
- feed entry categories are now displayed if available
|
||||||
## [2.0.3]
|
- various performance and dependencies upgrades
|
||||||
|
- java8 is now required
|
||||||
- internet explorer ajax cache workaround
|
|
||||||
- categories are now deletable again
|
## [2.1.0]
|
||||||
- openshift support is back
|
|
||||||
- youtube feeds now show user favicon instead of youtube favicon
|
- dropwizard upgrade to 0.8.0
|
||||||
|
- you have to remove the "app.contextPath" setting from your yml file, you can optionally use
|
||||||
## [2.0.2]
|
server.applicationContextPath instead
|
||||||
|
- new setting app.maxFeedCapacity for deleting old entries
|
||||||
- api using the api key is now working again
|
- ability to set filtering expressions for subscriptions to automatically mark new entries as read based on title,
|
||||||
- context path is now configurable in config.yml (see app.contextPath in config.yml.example)
|
content, author or url.
|
||||||
- fix login on firefox when fields are autofilled by the browser
|
- ability to use !keyword or -keyword to exclude a keyword from a search query
|
||||||
- fix scrolling of subscriptions list on mobile
|
- facebook feeds now show user favicon instead of facebook favicon
|
||||||
- user is now logged in after registration
|
- new dark theme 'nightsky'
|
||||||
- fix link to documentation on home page and about page
|
|
||||||
- fields autocomplete is disabled on the profile page
|
## [2.0.3]
|
||||||
- users are able to delete their account again
|
|
||||||
- chinese and malaysian translation files are now correctly loaded
|
- internet explorer ajax cache workaround
|
||||||
- software version in user-agent when fetching feeds is no longer hardcoded
|
- categories are now deletable again
|
||||||
- admin settings page is now read only, settings are configured in config.yml
|
- openshift support is back
|
||||||
- added link to metrics on the admin settings page
|
- youtube feeds now show user favicon instead of youtube favicon
|
||||||
- Rome (rss library) upgrade to 1.5.0
|
|
||||||
|
## [2.0.2]
|
||||||
## [2.0.1]
|
|
||||||
|
- api using the api key is now working again
|
||||||
- the redis pool no longer throws an exception when it is unable to aquire a new connection
|
- context path is now configurable in config.yml (see app.contextPath in config.yml.example)
|
||||||
|
- fix login on firefox when fields are autofilled by the browser
|
||||||
## [2.0.0]
|
- fix scrolling of subscriptions list on mobile
|
||||||
|
- user is now logged in after registration
|
||||||
- The backend has been completely rewritten using Dropwizard instead of TomEE, resulting in a lot less memory
|
- fix link to documentation on home page and about page
|
||||||
consumption and better overall performances.
|
- fields autocomplete is disabled on the profile page
|
||||||
See the README on how to build CommaFeed from now on.
|
- users are able to delete their account again
|
||||||
- CommaFeed should no longer fetch the same feed multiple times in a row
|
- chinese and malaysian translation files are now correctly loaded
|
||||||
- Users can use their username or email to log in
|
- software version in user-agent when fetching feeds is no longer hardcoded
|
||||||
|
- admin settings page is now read only, settings are configured in config.yml
|
||||||
|
- added link to metrics on the admin settings page
|
||||||
|
- Rome (rss library) upgrade to 1.5.0
|
||||||
|
|
||||||
|
## [2.0.1]
|
||||||
|
|
||||||
|
- the redis pool no longer throws an exception when it is unable to aquire a new connection
|
||||||
|
|
||||||
|
## [2.0.0]
|
||||||
|
|
||||||
|
- The backend has been completely rewritten using Dropwizard instead of TomEE, resulting in a lot less memory
|
||||||
|
consumption and better overall performances.
|
||||||
|
See the README on how to build CommaFeed from now on.
|
||||||
|
- CommaFeed should no longer fetch the same feed multiple times in a row
|
||||||
|
- Users can use their username or email to log in
|
||||||
|
|||||||
60
LICENSE
60
LICENSE
@@ -1,31 +1,31 @@
|
|||||||
Apache License, Version 2.0 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/
|
Apache License, Version 2.0 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
1. Definitions.
|
1. Definitions.
|
||||||
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
||||||
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
||||||
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
||||||
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
||||||
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
|
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
||||||
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
|
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
||||||
2. Grant of Copyright License.
|
2. Grant of Copyright License.
|
||||||
Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
||||||
3. Grant of Patent License.
|
3. Grant of Patent License.
|
||||||
Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
|
Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
|
||||||
4. Redistribution.
|
4. Redistribution.
|
||||||
You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
||||||
You must give any other recipients of the Work or Derivative Works a copy of this License; and You must cause any modified files to carry prominent notices stating that You changed the files; and You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
|
You must give any other recipients of the Work or Derivative Works a copy of this License; and You must cause any modified files to carry prominent notices stating that You changed the files; and You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
|
||||||
5. Submission of Contributions.
|
5. Submission of Contributions.
|
||||||
Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
|
Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
|
||||||
6. Trademarks.
|
6. Trademarks.
|
||||||
This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
||||||
7. Disclaimer of Warranty.
|
7. Disclaimer of Warranty.
|
||||||
Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
|
Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
|
||||||
8. Limitation of Liability.
|
8. Limitation of Liability.
|
||||||
In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
||||||
9. Accepting Warranty or Additional Liability.
|
9. Accepting Warranty or Additional Liability.
|
||||||
While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
||||||
END OF TERMS AND CONDITIONS
|
END OF TERMS AND CONDITIONS
|
||||||
12
README.md
12
README.md
@@ -48,17 +48,17 @@ system and database of choice.
|
|||||||
|
|
||||||
There are two types of packages:
|
There are two types of packages:
|
||||||
|
|
||||||
- The `linux-x86_64` and `windows-x86_64` packages are compiled natively and contain an executable that can be run
|
- The `linux-x86_64`, `linux-aarch_64` and `windows-x86_64` packages are compiled natively and contain an executable that can be run
|
||||||
directly.
|
directly.
|
||||||
- The `jvm` package is a zip file containing all `.jar` files required to run the application. This package works on all
|
- The `jvm` package is a zip file containing all `.jar` files required to run the application. This package works on all
|
||||||
platforms and is started with `java -jar quarkus-run.jar`.
|
platforms but requires a JRE and is started with `java -jar quarkus-run.jar`.
|
||||||
|
|
||||||
If available for your operating system, the native package is recommended because it has a faster startup time and lower
|
If available for your operating system, the native package is recommended because it has a faster startup time and lower
|
||||||
memory usage.
|
memory usage.
|
||||||
|
|
||||||
### Build from sources
|
### Build from sources
|
||||||
|
|
||||||
./mvnw clean package [-P<database>] [-Pnative] [-DskipTests]
|
./mvnw clean package [-P<database> [-Pnative]] [-DskipTests]
|
||||||
|
|
||||||
- `<database>` can be one of `h2`, `postgresql`, `mysql` or `mariadb`. The default is `h2`.
|
- `<database>` can be one of `h2`, `postgresql`, `mysql` or `mariadb`. The default is `h2`.
|
||||||
- `-Pnative` compiles the application to native code. This requires GraalVM to be installed (`GRAALVM_HOME` environment
|
- `-Pnative` compiles the application to native code. This requires GraalVM to be installed (`GRAALVM_HOME` environment
|
||||||
@@ -73,6 +73,10 @@ When the build is complete:
|
|||||||
- if you used the native profile, the executable is located at
|
- if you used the native profile, the executable is located at
|
||||||
`commafeed-server/target/commafeed-<version>-<database>-<platform>-<arch>-runner[.exe]`
|
`commafeed-server/target/commafeed-<version>-<database>-<platform>-<arch>-runner[.exe]`
|
||||||
|
|
||||||
|
### Distribution packages
|
||||||
|
|
||||||
|
- Arch Linux users can use [the CommaFeed package on AUR](https://aur.archlinux.org/pkgbase/commafeed), which builds native binaries with GraalVM for all supported databases.
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
CommaFeed doesn't require any configuration to run with its embedded database (H2). The database file will be stored in
|
CommaFeed doesn't require any configuration to run with its embedded database (H2). The database file will be stored in
|
||||||
@@ -100,7 +104,7 @@ There are multiple ways to configure CommaFeed:
|
|||||||
|
|
||||||
The properties file is recommended because CommaFeed will be able to warn about invalid properties and typos.
|
The properties file is recommended because CommaFeed will be able to warn about invalid properties and typos.
|
||||||
|
|
||||||
All [CommaFeed settings](commafeed-server/doc/commafeed.md) are optional and have sensible default values.
|
All [CommaFeed settings](https://athou.github.io/commafeed/documentation) are optional and have sensible default values.
|
||||||
|
|
||||||
When logging in, credentials are stored in an encrypted cookie. The encryption key is randomly generated at startup,
|
When logging in, credentials are stored in an encrypted cookie. The encryption key is randomly generated at startup,
|
||||||
meaning that you will have to log back in after each restart of the application. To prevent this, you can set the
|
meaning that you will have to log back in after each restart of the application. To prevent this, you can set the
|
||||||
|
|||||||
@@ -5,9 +5,7 @@
|
|||||||
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
||||||
<link rel="manifest" href="manifest.json" />
|
<link rel="manifest" href="manifest.json" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||||
|
<meta name="referrer" content="no-referrer" />
|
||||||
<link rel="stylesheet" type="text/css" href="custom_css.css" />
|
|
||||||
<script type="text/javascript" src="custom_js.js"></script>
|
|
||||||
|
|
||||||
<title>CommaFeed</title>
|
<title>CommaFeed</title>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
2089
commafeed-client/package-lock.json
generated
2089
commafeed-client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -4,62 +4,65 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --host",
|
"dev": "vite",
|
||||||
"dev:typescript": "tsc --watch",
|
"dev:host": "vite --host",
|
||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"test": "vitest",
|
"test": "vitest",
|
||||||
"test:ci": "vitest run",
|
"test:ci": "vitest run",
|
||||||
"lint": "biome check ./src",
|
"lint": "biome check",
|
||||||
"lint:fix": "biome check --write ./src",
|
"lint:fix": "biome check --write",
|
||||||
"i18n:extract": "lingui extract --clean"
|
"i18n:extract": "lingui extract --clean"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.14.0",
|
"@emotion/react": "^11.14.0",
|
||||||
"@fontsource/open-sans": "^5.1.1",
|
"@fontsource/open-sans": "^5.2.5",
|
||||||
"@mantine/core": "^7.16.3",
|
"@lingui/core": "^5.3.0",
|
||||||
"@mantine/form": "^7.16.3",
|
"@lingui/react": "^5.3.0",
|
||||||
"@mantine/hooks": "^7.16.3",
|
"@mantine/core": "^7.17.3",
|
||||||
"@mantine/modals": "^7.16.3",
|
"@mantine/form": "^7.17.3",
|
||||||
"@mantine/notifications": "^7.16.3",
|
"@mantine/hooks": "^7.17.3",
|
||||||
"@mantine/spotlight": "^7.16.3",
|
"@mantine/modals": "^7.17.3",
|
||||||
"@lingui/core": "^5.2.0",
|
"@mantine/notifications": "^7.17.3",
|
||||||
"@lingui/react": "^5.2.0",
|
"@mantine/spotlight": "^7.17.3",
|
||||||
"@monaco-editor/react": "^4.7.0",
|
"@monaco-editor/react": "^4.7.0",
|
||||||
"@reduxjs/toolkit": "^2.5.1",
|
"@reduxjs/toolkit": "^2.6.1",
|
||||||
"axios": "^1.7.9",
|
"axios": "^1.8.4",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"escape-string-regexp": "^5.0.0",
|
"escape-string-regexp": "^5.0.0",
|
||||||
"interweave": "^13.1.1",
|
"interweave": "^13.1.1",
|
||||||
"monaco-editor": "^0.52.2",
|
"monaco-editor": "^0.52.2",
|
||||||
"mousetrap": "^1.6.5",
|
"mousetrap": "^1.6.5",
|
||||||
"react": "^19.0.0",
|
"react": "^19.1.0",
|
||||||
"react-async-hook": "^4.0.0",
|
"react-async-hook": "^4.0.0",
|
||||||
"react-contexify": "^6.0.0",
|
"react-contexify": "^6.0.0",
|
||||||
"react-device-detect": "^2.2.3",
|
"react-device-detect": "^2.2.3",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-draggable": "^4.4.6",
|
"react-draggable": "^4.4.6",
|
||||||
"react-ga4": "^2.1.0",
|
"react-ga4": "^2.1.0",
|
||||||
"react-icons": "^5.4.0",
|
"react-icons": "^5.5.0",
|
||||||
"react-infinite-scroller": "^1.2.6",
|
"react-infinite-scroller": "^1.2.6",
|
||||||
"react-redux": "^9.2.0",
|
"react-redux": "^9.2.0",
|
||||||
"react-router-dom": "^7.1.5",
|
"react-router-dom": "^7.4.1",
|
||||||
"react-swipeable": "^7.0.2",
|
"react-swipeable": "^7.0.2",
|
||||||
"redoc": "^2.4.0",
|
"redoc": "^2.4.0",
|
||||||
"style-to-object": "^1.0.8",
|
"style-to-object": "^1.0.8",
|
||||||
"throttle-debounce": "^5.0.2",
|
"throttle-debounce": "^5.0.2",
|
||||||
"tinycon": "^0.6.8",
|
"tinycon": "^0.6.8",
|
||||||
"tss-react": "^4.9.15",
|
"tss-react": "^4.9.16",
|
||||||
"websocket-heartbeat-js": "^1.1.3"
|
"websocket-heartbeat-js": "^1.1.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "^1.9.4",
|
"@biomejs/biome": "^1.9.4",
|
||||||
"@lingui/babel-plugin-lingui-macro": "^5.2.0",
|
"@lingui/babel-plugin-lingui-macro": "^5.3.0",
|
||||||
"@lingui/cli": "^5.2.0",
|
"@lingui/cli": "^5.3.0",
|
||||||
"@lingui/vite-plugin": "^5.2.0",
|
"@lingui/vite-plugin": "^5.3.0",
|
||||||
|
"@testing-library/jest-dom": "^6.6.3",
|
||||||
|
"@testing-library/react": "^16.3.0",
|
||||||
|
"@testing-library/user-event": "^14.6.1",
|
||||||
"@types/mousetrap": "^1.6.15",
|
"@types/mousetrap": "^1.6.15",
|
||||||
"@types/react": "^19.0.8",
|
"@types/react": "^19.1.0",
|
||||||
"@types/react-dom": "^19.0.3",
|
"@types/react-dom": "^19.1.1",
|
||||||
"@types/react-infinite-scroller": "^1.2.5",
|
"@types/react-infinite-scroller": "^1.2.5",
|
||||||
"@types/throttle-debounce": "^5.0.2",
|
"@types/throttle-debounce": "^5.0.2",
|
||||||
"@types/tinycon": "^0.6.7",
|
"@types/tinycon": "^0.6.7",
|
||||||
@@ -67,16 +70,15 @@
|
|||||||
"babel-plugin-macros": "^3.1.0",
|
"babel-plugin-macros": "^3.1.0",
|
||||||
"jsdom": "^26.0.0",
|
"jsdom": "^26.0.0",
|
||||||
"rollup-plugin-visualizer": "^5.14.0",
|
"rollup-plugin-visualizer": "^5.14.0",
|
||||||
"typescript": "^5.7.3",
|
"typescript": "^5.8.2",
|
||||||
"vite": "^6.1.0",
|
"vite": "^6.2.5",
|
||||||
"vite-plugin-checker": "^0.8.0",
|
"vite-plugin-checker": "^0.9.1",
|
||||||
"vite-tsconfig-paths": "^5.1.4",
|
"vite-tsconfig-paths": "^5.1.4",
|
||||||
"vitest": "^3.0.5",
|
"vitest": "^3.1.1"
|
||||||
"vitest-mock-extended": "^2.0.2"
|
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"react-infinite-scroller": {
|
"react-infinite-scroller": {
|
||||||
"react": "^19.0.0"
|
"react": "^19.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,96 +1,97 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.commafeed</groupId>
|
<groupId>com.commafeed</groupId>
|
||||||
<artifactId>commafeed</artifactId>
|
<artifactId>commafeed</artifactId>
|
||||||
<version>5.6.0</version>
|
<version>5.7.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>commafeed-client</artifactId>
|
<artifactId>commafeed-client</artifactId>
|
||||||
<name>CommaFeed Client</name>
|
<name>CommaFeed Client</name>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<!-- renovate: datasource=node-version depName=node -->
|
<!-- renovate: datasource=node-version depName=node -->
|
||||||
<node.version>v22.14.0</node.version>
|
<node.version>v22.14.0</node.version>
|
||||||
<!-- renovate: datasource=npm depName=npm -->
|
<!-- renovate: datasource=npm depName=npm -->
|
||||||
<npm.version>11.1.0</npm.version>
|
<npm.version>11.2.0</npm.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>com.github.eirslett</groupId>
|
<groupId>com.github.eirslett</groupId>
|
||||||
<artifactId>frontend-maven-plugin</artifactId>
|
<artifactId>frontend-maven-plugin</artifactId>
|
||||||
<version>1.15.1</version>
|
<version>1.15.1</version>
|
||||||
<?m2e ignore?>
|
<?m2e ignore?>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<id>install node and npm</id>
|
<id>install node and npm</id>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>install-node-and-npm</goal>
|
<goal>install-node-and-npm</goal>
|
||||||
</goals>
|
</goals>
|
||||||
<phase>compile</phase>
|
<phase>compile</phase>
|
||||||
<configuration>
|
<configuration>
|
||||||
<nodeVersion>${node.version}</nodeVersion>
|
<nodeVersion>${node.version}</nodeVersion>
|
||||||
<npmVersion>${npm.version}</npmVersion>
|
<npmVersion>${npm.version}</npmVersion>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
<execution>
|
<execution>
|
||||||
<id>npm install</id>
|
<id>npm install</id>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>npm</goal>
|
<goal>npm</goal>
|
||||||
</goals>
|
</goals>
|
||||||
<phase>compile</phase>
|
<phase>compile</phase>
|
||||||
<configuration>
|
<configuration>
|
||||||
<arguments>ci</arguments>
|
<arguments>ci</arguments>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
<execution>
|
<execution>
|
||||||
<id>npm run test</id>
|
<id>npm run test</id>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>npm</goal>
|
<goal>npm</goal>
|
||||||
</goals>
|
</goals>
|
||||||
<phase>compile</phase>
|
<phase>compile</phase>
|
||||||
<configuration>
|
<configuration>
|
||||||
<arguments>run test:ci</arguments>
|
<arguments>run test:ci</arguments>
|
||||||
</configuration>
|
<skip>${skipTests}</skip>
|
||||||
</execution>
|
</configuration>
|
||||||
<execution>
|
</execution>
|
||||||
<id>npm run build</id>
|
<execution>
|
||||||
<goals>
|
<id>npm run build</id>
|
||||||
<goal>npm</goal>
|
<goals>
|
||||||
</goals>
|
<goal>npm</goal>
|
||||||
<phase>compile</phase>
|
</goals>
|
||||||
<configuration>
|
<phase>compile</phase>
|
||||||
<arguments>run build</arguments>
|
<configuration>
|
||||||
</configuration>
|
<arguments>run build</arguments>
|
||||||
</execution>
|
</configuration>
|
||||||
</executions>
|
</execution>
|
||||||
</plugin>
|
</executions>
|
||||||
<plugin>
|
</plugin>
|
||||||
<artifactId>maven-resources-plugin</artifactId>
|
<plugin>
|
||||||
<version>3.3.1</version>
|
<artifactId>maven-resources-plugin</artifactId>
|
||||||
<executions>
|
<version>3.3.1</version>
|
||||||
<execution>
|
<executions>
|
||||||
<id>copy web interface to resources</id>
|
<execution>
|
||||||
<phase>prepare-package</phase>
|
<id>copy web interface to resources</id>
|
||||||
<goals>
|
<phase>prepare-package</phase>
|
||||||
<goal>copy-resources</goal>
|
<goals>
|
||||||
</goals>
|
<goal>copy-resources</goal>
|
||||||
<configuration>
|
</goals>
|
||||||
<outputDirectory>${project.build.directory}/classes/META-INF/resources</outputDirectory>
|
<configuration>
|
||||||
<resources>
|
<outputDirectory>${project.build.directory}/classes/META-INF/resources</outputDirectory>
|
||||||
<resource>
|
<resources>
|
||||||
<directory>dist</directory>
|
<resource>
|
||||||
<filtering>false</filtering>
|
<directory>dist</directory>
|
||||||
</resource>
|
<filtering>false</filtering>
|
||||||
</resources>
|
</resource>
|
||||||
</configuration>
|
</resources>
|
||||||
</execution>
|
</configuration>
|
||||||
</executions>
|
</execution>
|
||||||
</plugin>
|
</executions>
|
||||||
</plugins>
|
</plugin>
|
||||||
</build>
|
</plugins>
|
||||||
|
</build>
|
||||||
</project>
|
</project>
|
||||||
@@ -12,6 +12,7 @@ import { DisablePullToRefresh } from "components/DisablePullToRefresh"
|
|||||||
import { ErrorBoundary } from "components/ErrorBoundary"
|
import { ErrorBoundary } from "components/ErrorBoundary"
|
||||||
import { Header } from "components/header/Header"
|
import { Header } from "components/header/Header"
|
||||||
import { Tree } from "components/sidebar/Tree"
|
import { Tree } from "components/sidebar/Tree"
|
||||||
|
import { useAppLoading } from "hooks/useAppLoading"
|
||||||
import { useBrowserExtension } from "hooks/useBrowserExtension"
|
import { useBrowserExtension } from "hooks/useBrowserExtension"
|
||||||
import { useI18n } from "i18n"
|
import { useI18n } from "i18n"
|
||||||
import { WelcomePage } from "pages/WelcomePage"
|
import { WelcomePage } from "pages/WelcomePage"
|
||||||
@@ -29,7 +30,7 @@ import { TagDetailsPage } from "pages/app/TagDetailsPage"
|
|||||||
import { LoginPage } from "pages/auth/LoginPage"
|
import { LoginPage } from "pages/auth/LoginPage"
|
||||||
import { PasswordRecoveryPage } from "pages/auth/PasswordRecoveryPage"
|
import { PasswordRecoveryPage } from "pages/auth/PasswordRecoveryPage"
|
||||||
import { RegistrationPage } from "pages/auth/RegistrationPage"
|
import { RegistrationPage } from "pages/auth/RegistrationPage"
|
||||||
import React, { useEffect } from "react"
|
import React, { useEffect, useState } from "react"
|
||||||
import { isSafari } from "react-device-detect"
|
import { isSafari } from "react-device-detect"
|
||||||
import ReactGA from "react-ga4"
|
import ReactGA from "react-ga4"
|
||||||
import { HashRouter, Navigate, Route, Routes, useLocation, useNavigate } from "react-router-dom"
|
import { HashRouter, Navigate, Route, Routes, useLocation, useNavigate } from "react-router-dom"
|
||||||
@@ -169,6 +170,38 @@ function BrowserExtensionBadgeUnreadCountHandler() {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function CustomJsHandler() {
|
||||||
|
const [scriptLoaded, setScriptLoaded] = useState(false)
|
||||||
|
const { loading } = useAppLoading()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (scriptLoaded || loading) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const script = document.createElement("script")
|
||||||
|
script.src = "custom_js.js"
|
||||||
|
script.async = true
|
||||||
|
document.body.appendChild(script)
|
||||||
|
|
||||||
|
setScriptLoaded(true)
|
||||||
|
}, [scriptLoaded, loading])
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
function CustomCssHandler() {
|
||||||
|
useEffect(() => {
|
||||||
|
const link = document.createElement("link")
|
||||||
|
link.rel = "stylesheet"
|
||||||
|
link.type = "text/css"
|
||||||
|
link.href = "custom_css.css"
|
||||||
|
document.head.appendChild(link)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
useI18n()
|
useI18n()
|
||||||
const root = useAppSelector(state => state.tree.rootCategory)
|
const root = useAppSelector(state => state.tree.rootCategory)
|
||||||
@@ -188,15 +221,19 @@ export function App() {
|
|||||||
<UnreadCountTitleHandler unreadCount={unreadCount} enabled={unreadCountTitle} />
|
<UnreadCountTitleHandler unreadCount={unreadCount} enabled={unreadCountTitle} />
|
||||||
<UnreadCountFaviconHandler unreadCount={unreadCount} enabled={unreadCountFavicon} />
|
<UnreadCountFaviconHandler unreadCount={unreadCount} enabled={unreadCountFavicon} />
|
||||||
<BrowserExtensionBadgeUnreadCountHandler />
|
<BrowserExtensionBadgeUnreadCountHandler />
|
||||||
|
<CustomJsHandler />
|
||||||
|
<CustomCssHandler />
|
||||||
|
|
||||||
|
{/* disable pull-to-refresh as it messes with vertical scrolling
|
||||||
|
safari behaves weirdly when overscroll-behavior is set to none so we disable it only for other browsers
|
||||||
|
https://github.com/Athou/commafeed/issues/1168
|
||||||
|
*/}
|
||||||
|
{!isSafari && <DisablePullToRefresh />}
|
||||||
|
|
||||||
<HashRouter>
|
<HashRouter>
|
||||||
<GoogleAnalyticsHandler />
|
<GoogleAnalyticsHandler />
|
||||||
<RedirectHandler />
|
<RedirectHandler />
|
||||||
<AppRoutes />
|
<AppRoutes />
|
||||||
{/* disable pull-to-refresh as it messes with vertical scrolling
|
|
||||||
safari behaves weirdly when overscroll-behavior is set to none so we disable it only for other browsers
|
|
||||||
https://github.com/Athou/commafeed/issues/1168
|
|
||||||
*/}
|
|
||||||
{!isSafari && <DisablePullToRefresh />}
|
|
||||||
</HashRouter>
|
</HashRouter>
|
||||||
</>
|
</>
|
||||||
</Providers>
|
</Providers>
|
||||||
|
|||||||
@@ -1,25 +1,20 @@
|
|||||||
import { configureStore } from "@reduxjs/toolkit"
|
import { configureStore } from "@reduxjs/toolkit"
|
||||||
import type { client } from "app/client"
|
import { client } from "app/client"
|
||||||
import { loadEntries, loadMoreEntries, markAllEntries, markEntry } from "app/entries/thunks"
|
import { loadEntries, loadMoreEntries, markAllEntries, markEntry } from "app/entries/thunks"
|
||||||
import { type RootState, reducers } from "app/store"
|
import { type RootState, reducers } from "app/store"
|
||||||
import type { Entries, Entry } from "app/types"
|
import type { Entries, Entry } from "app/types"
|
||||||
import type { AxiosResponse } from "axios"
|
import type { AxiosResponse } from "axios"
|
||||||
import { beforeEach, describe, expect, it, vi } from "vitest"
|
import { beforeEach, describe, expect, it, vi } from "vitest"
|
||||||
import { any, mockReset } from "vitest-mock-extended"
|
|
||||||
|
|
||||||
const mockClient = await vi.hoisted(async () => {
|
vi.mock(import("app/client"))
|
||||||
const mockModule = await import("vitest-mock-extended")
|
|
||||||
return mockModule.mockDeep<typeof client>()
|
|
||||||
})
|
|
||||||
vi.mock("app/client", () => ({ client: mockClient }))
|
|
||||||
|
|
||||||
describe("entries", () => {
|
describe("entries", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockReset(mockClient)
|
vi.resetAllMocks()
|
||||||
})
|
})
|
||||||
|
|
||||||
it("loads entries", async () => {
|
it("loads entries", async () => {
|
||||||
mockClient.feed.getEntries.calledWith(any()).mockResolvedValue({
|
vi.mocked(client.feed.getEntries).mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
entries: [{ id: "3" } as Entry],
|
entries: [{ id: "3" } as Entry],
|
||||||
hasMore: false,
|
hasMore: false,
|
||||||
@@ -53,7 +48,7 @@ describe("entries", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("loads more entries", async () => {
|
it("loads more entries", async () => {
|
||||||
mockClient.category.getEntries.calledWith(any()).mockResolvedValue({
|
vi.mocked(client.category.getEntries).mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
entries: [{ id: "4" } as Entry],
|
entries: [{ id: "4" } as Entry],
|
||||||
hasMore: false,
|
hasMore: false,
|
||||||
@@ -113,7 +108,7 @@ describe("entries", () => {
|
|||||||
{ id: "3", read: true },
|
{ id: "3", read: true },
|
||||||
{ id: "4", read: false },
|
{ id: "4", read: false },
|
||||||
])
|
])
|
||||||
expect(mockClient.entry.mark).toHaveBeenCalledWith({ id: "3", read: true })
|
expect(client.entry.mark).toHaveBeenCalledWith({ id: "3", read: true })
|
||||||
})
|
})
|
||||||
|
|
||||||
it("marks all entries as read", () => {
|
it("marks all entries as read", () => {
|
||||||
@@ -140,6 +135,6 @@ describe("entries", () => {
|
|||||||
{ id: "3", read: true },
|
{ id: "3", read: true },
|
||||||
{ id: "4", read: true },
|
{ id: "4", read: true },
|
||||||
])
|
])
|
||||||
expect(mockClient.category.markEntries).toHaveBeenCalledWith({ id: "all", read: true })
|
expect(client.category.markEntries).toHaveBeenCalledWith({ id: "all", read: true })
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { createAppAsyncThunk } from "app/async-thunk"
|
import { createAppAsyncThunk } from "app/async-thunk"
|
||||||
import { client } from "app/client"
|
import { client } from "app/client"
|
||||||
|
import { redirectToCategory, redirectToFeed } from "app/redirect/thunks"
|
||||||
import { incrementUnreadCount } from "app/tree/slice"
|
import { incrementUnreadCount } from "app/tree/slice"
|
||||||
import type { CollapseRequest } from "app/types"
|
import type { CollapseRequest, Subscription } from "app/types"
|
||||||
import { flattenCategoryTree } from "app/utils"
|
import { flattenCategoryTree, visitCategoryTree } from "app/utils"
|
||||||
|
|
||||||
export const reloadTree = createAppAsyncThunk("tree/reload", async () => await client.category.getRoot().then(r => r.data))
|
export const reloadTree = createAppAsyncThunk("tree/reload", async () => await client.category.getRoot().then(r => r.data))
|
||||||
|
|
||||||
@@ -11,6 +12,50 @@ export const collapseTreeCategory = createAppAsyncThunk(
|
|||||||
async (req: CollapseRequest) => await client.category.collapse(req)
|
async (req: CollapseRequest) => await client.category.collapse(req)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export const selectNextUnreadTreeItem = createAppAsyncThunk(
|
||||||
|
"tree/selectNextUnreadItem",
|
||||||
|
(
|
||||||
|
arg: {
|
||||||
|
direction: "forward" | "backward"
|
||||||
|
},
|
||||||
|
thunkApi
|
||||||
|
) => {
|
||||||
|
const state = thunkApi.getState()
|
||||||
|
const root = state.tree.rootCategory
|
||||||
|
if (!root) return
|
||||||
|
|
||||||
|
const { source } = state.entries
|
||||||
|
if (source.type === "category") {
|
||||||
|
const categories = flattenCategoryTree(root)
|
||||||
|
if (arg.direction === "backward") categories.reverse()
|
||||||
|
|
||||||
|
const index = categories.findIndex(c => c.id === source.id)
|
||||||
|
if (index === -1) return
|
||||||
|
|
||||||
|
for (let i = index + 1; i < categories.length; i++) {
|
||||||
|
const c = categories[i]
|
||||||
|
if (c.feeds.some(f => f.unread > 0)) {
|
||||||
|
return thunkApi.dispatch(redirectToCategory(String(c.id)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (source.type === "feed") {
|
||||||
|
const feeds: Subscription[] = []
|
||||||
|
visitCategoryTree(root, c => feeds.push(...c.feeds), { childrenFirst: true })
|
||||||
|
if (arg.direction === "backward") feeds.reverse()
|
||||||
|
|
||||||
|
const index = feeds.findIndex(f => f.id === +source.id)
|
||||||
|
if (index === -1) return
|
||||||
|
|
||||||
|
for (let i = index + 1; i < feeds.length; i++) {
|
||||||
|
const f = feeds[i]
|
||||||
|
if (f.unread > 0) {
|
||||||
|
return thunkApi.dispatch(redirectToFeed(String(f.id)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
export const newFeedEntriesDiscovered = createAppAsyncThunk(
|
export const newFeedEntriesDiscovered = createAppAsyncThunk(
|
||||||
"tree/new-feed-entries-discovered",
|
"tree/new-feed-entries-discovered",
|
||||||
async ({ feedId, amount }: { feedId: number; amount: number }, thunkApi) => {
|
async ({ feedId, amount }: { feedId: number; amount: number }, thunkApi) => {
|
||||||
|
|||||||
119
commafeed-client/src/app/tree/tree.test.ts
Normal file
119
commafeed-client/src/app/tree/tree.test.ts
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
import { configureStore } from "@reduxjs/toolkit"
|
||||||
|
import { type RootState, reducers } from "app/store"
|
||||||
|
import { selectNextUnreadTreeItem } from "app/tree/thunks"
|
||||||
|
import type { Category, Subscription } from "app/types"
|
||||||
|
import { describe, expect, it } from "vitest"
|
||||||
|
|
||||||
|
const createCategory = (id: string): Category => ({
|
||||||
|
id,
|
||||||
|
name: id,
|
||||||
|
children: [],
|
||||||
|
feeds: [],
|
||||||
|
expanded: true,
|
||||||
|
position: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
const createFeed = (id: number, unread: number): Subscription => ({
|
||||||
|
id,
|
||||||
|
name: String(id),
|
||||||
|
unread,
|
||||||
|
errorCount: 0,
|
||||||
|
position: 0,
|
||||||
|
feedUrl: "",
|
||||||
|
feedLink: "",
|
||||||
|
iconUrl: "",
|
||||||
|
})
|
||||||
|
|
||||||
|
const root = createCategory("root")
|
||||||
|
|
||||||
|
const catA = createCategory("catA")
|
||||||
|
catA.feeds.push(createFeed(1, 0), createFeed(2, 0), createFeed(3, 1))
|
||||||
|
|
||||||
|
const catB = createCategory("catB")
|
||||||
|
|
||||||
|
const catC = createCategory("catC")
|
||||||
|
catC.feeds.push(createFeed(4, 1))
|
||||||
|
|
||||||
|
root.children.push(catA, catB, catC)
|
||||||
|
|
||||||
|
describe("selectNextUnreadTreeItem", () => {
|
||||||
|
it("selects the next unread category", async () => {
|
||||||
|
const store = configureStore({
|
||||||
|
reducer: reducers,
|
||||||
|
preloadedState: {
|
||||||
|
tree: {
|
||||||
|
rootCategory: root,
|
||||||
|
},
|
||||||
|
entries: {
|
||||||
|
source: {
|
||||||
|
type: "category",
|
||||||
|
id: "catA",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as RootState,
|
||||||
|
})
|
||||||
|
|
||||||
|
await store.dispatch(selectNextUnreadTreeItem({ direction: "forward" }))
|
||||||
|
expect(store.getState().redirect.to).toBe("/app/category/catC")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("selects the previous unread category", async () => {
|
||||||
|
const store = configureStore({
|
||||||
|
reducer: reducers,
|
||||||
|
preloadedState: {
|
||||||
|
tree: {
|
||||||
|
rootCategory: root,
|
||||||
|
},
|
||||||
|
entries: {
|
||||||
|
source: {
|
||||||
|
type: "category",
|
||||||
|
id: "catC",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as RootState,
|
||||||
|
})
|
||||||
|
|
||||||
|
await store.dispatch(selectNextUnreadTreeItem({ direction: "backward" }))
|
||||||
|
expect(store.getState().redirect.to).toBe("/app/category/catA")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("selects the next unread feed", async () => {
|
||||||
|
const store = configureStore({
|
||||||
|
reducer: reducers,
|
||||||
|
preloadedState: {
|
||||||
|
tree: {
|
||||||
|
rootCategory: root,
|
||||||
|
},
|
||||||
|
entries: {
|
||||||
|
source: {
|
||||||
|
type: "feed",
|
||||||
|
id: "1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as RootState,
|
||||||
|
})
|
||||||
|
|
||||||
|
await store.dispatch(selectNextUnreadTreeItem({ direction: "forward" }))
|
||||||
|
expect(store.getState().redirect.to).toBe("/app/feed/3")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("selects the previous unread feed", async () => {
|
||||||
|
const store = configureStore({
|
||||||
|
reducer: reducers,
|
||||||
|
preloadedState: {
|
||||||
|
tree: {
|
||||||
|
rootCategory: root,
|
||||||
|
},
|
||||||
|
entries: {
|
||||||
|
source: {
|
||||||
|
type: "feed",
|
||||||
|
id: "4",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as RootState,
|
||||||
|
})
|
||||||
|
|
||||||
|
await store.dispatch(selectNextUnreadTreeItem({ direction: "backward" }))
|
||||||
|
expect(store.getState().redirect.to).toBe("/app/feed/3")
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,11 +1,22 @@
|
|||||||
import { throttle } from "throttle-debounce"
|
import { throttle } from "throttle-debounce"
|
||||||
import type { Category } from "./types"
|
import type { Category } from "./types"
|
||||||
|
|
||||||
export function visitCategoryTree(category: Category, visitor: (category: Category) => void): void {
|
export function visitCategoryTree(
|
||||||
visitor(category)
|
category: Category,
|
||||||
for (const child of category.children) {
|
visitor: (category: Category) => void,
|
||||||
visitCategoryTree(child, visitor)
|
options?: {
|
||||||
|
childrenFirst?: boolean
|
||||||
}
|
}
|
||||||
|
): void {
|
||||||
|
const childrenFirst = options?.childrenFirst
|
||||||
|
|
||||||
|
if (!childrenFirst) visitor(category)
|
||||||
|
|
||||||
|
for (const child of category.children) {
|
||||||
|
visitCategoryTree(child, visitor, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (childrenFirst) visitor(category)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function flattenCategoryTree(category: Category): Category[] {
|
export function flattenCategoryTree(category: Category): Category[] {
|
||||||
|
|||||||
47
commafeed-client/src/components/ActionButton.test.tsx
Normal file
47
commafeed-client/src/components/ActionButton.test.tsx
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import type { I18nContext } from "@lingui/react"
|
||||||
|
import { MantineProvider } from "@mantine/core"
|
||||||
|
import { fireEvent, render, screen, waitFor } from "@testing-library/react"
|
||||||
|
import { useActionButton } from "hooks/useActionButton"
|
||||||
|
import { describe, expect, it, vi } from "vitest"
|
||||||
|
import { ActionButton } from "./ActionButton"
|
||||||
|
|
||||||
|
vi.mock(import("@lingui/react"), () => ({
|
||||||
|
useLingui: vi.fn().mockReturnValue({
|
||||||
|
_: msg => msg,
|
||||||
|
} as I18nContext),
|
||||||
|
}))
|
||||||
|
vi.mock(import("hooks/useActionButton"))
|
||||||
|
|
||||||
|
const label = "Test Label"
|
||||||
|
const icon = "Test Icon"
|
||||||
|
describe("ActionButton", () => {
|
||||||
|
it("renders Button with label on desktop", () => {
|
||||||
|
vi.mocked(useActionButton).mockReturnValue({ mobile: false, spacing: 0 })
|
||||||
|
|
||||||
|
render(<ActionButton label={label} icon={icon} />, { wrapper: MantineProvider })
|
||||||
|
expect(screen.getByText(label)).toBeInTheDocument()
|
||||||
|
expect(screen.getByText(icon)).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("renders ActionIcon with tooltip on mobile", async () => {
|
||||||
|
vi.mocked(useActionButton).mockReturnValue({ mobile: true, spacing: 0 })
|
||||||
|
|
||||||
|
render(<ActionButton label={label} icon={icon} />, { wrapper: MantineProvider })
|
||||||
|
expect(screen.queryByText(label)).not.toBeInTheDocument()
|
||||||
|
expect(screen.getByText(icon)).toBeInTheDocument()
|
||||||
|
|
||||||
|
fireEvent.mouseEnter(screen.getByRole("button"))
|
||||||
|
const tooltip = await waitFor(() => screen.getByRole("tooltip"))
|
||||||
|
expect(tooltip).toContainHTML(label)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("calls onClick handler when clicked", () => {
|
||||||
|
vi.mocked(useActionButton).mockReturnValue({ mobile: false, spacing: 0 })
|
||||||
|
const clickListener = vi.fn()
|
||||||
|
|
||||||
|
render(<ActionButton label={label} icon={icon} onClick={clickListener} />, { wrapper: MantineProvider })
|
||||||
|
fireEvent.click(screen.getByRole("button"))
|
||||||
|
|
||||||
|
expect(clickListener).toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
import type { MessageDescriptor } from "@lingui/core"
|
import type { MessageDescriptor } from "@lingui/core"
|
||||||
import { useLingui } from "@lingui/react"
|
import { useLingui } from "@lingui/react"
|
||||||
import { ActionIcon, Button, type ButtonVariant, Tooltip, useMantineTheme } from "@mantine/core"
|
import { ActionIcon, Box, Button, type ButtonVariant, Tooltip, useMantineTheme } from "@mantine/core"
|
||||||
import type { ActionIconVariant } from "@mantine/core/lib/components/ActionIcon/ActionIcon"
|
import type { ActionIconVariant } from "@mantine/core/lib/components/ActionIcon/ActionIcon"
|
||||||
import { Constants } from "app/constants"
|
import { Constants } from "app/constants"
|
||||||
import { useActionButton } from "hooks/useActionButton"
|
import { useActionButton } from "hooks/useActionButton"
|
||||||
import { type MouseEventHandler, type ReactNode, forwardRef } from "react"
|
import { type MouseEventHandler, type ReactNode, forwardRef } from "react"
|
||||||
|
|
||||||
interface ActionButtonProps {
|
interface ActionButtonProps {
|
||||||
|
icon: ReactNode
|
||||||
className?: string
|
className?: string
|
||||||
icon?: ReactNode
|
|
||||||
label?: string | MessageDescriptor
|
label?: string | MessageDescriptor
|
||||||
onClick?: MouseEventHandler
|
onClick?: MouseEventHandler
|
||||||
variant?: ActionIconVariant & ButtonVariant
|
variant?: ActionIconVariant & ButtonVariant
|
||||||
@@ -19,7 +19,7 @@ interface ActionButtonProps {
|
|||||||
/**
|
/**
|
||||||
* Switches between Button with label (desktop) and ActionIcon (mobile)
|
* Switches between Button with label (desktop) and ActionIcon (mobile)
|
||||||
*/
|
*/
|
||||||
export const ActionButton = forwardRef<HTMLButtonElement, ActionButtonProps>((props: ActionButtonProps, ref) => {
|
export const ActionButton = forwardRef<HTMLDivElement, ActionButtonProps>((props: ActionButtonProps, ref) => {
|
||||||
const { mobile } = useActionButton()
|
const { mobile } = useActionButton()
|
||||||
const theme = useMantineTheme()
|
const theme = useMantineTheme()
|
||||||
const { _ } = useLingui()
|
const { _ } = useLingui()
|
||||||
@@ -27,31 +27,36 @@ export const ActionButton = forwardRef<HTMLButtonElement, ActionButtonProps>((pr
|
|||||||
const label = typeof props.label === "string" ? props.label : props.label && _(props.label)
|
const label = typeof props.label === "string" ? props.label : props.label && _(props.label)
|
||||||
const variant = props.variant ?? "subtle"
|
const variant = props.variant ?? "subtle"
|
||||||
const iconOnly = (mobile && !props.showLabelOnMobile) || (!mobile && props.hideLabelOnDesktop)
|
const iconOnly = (mobile && !props.showLabelOnMobile) || (!mobile && props.hideLabelOnDesktop)
|
||||||
return iconOnly ? (
|
|
||||||
<Tooltip label={label} openDelay={Constants.tooltip.delay}>
|
return (
|
||||||
<ActionIcon
|
<Box ref={ref}>
|
||||||
ref={ref}
|
{iconOnly && (
|
||||||
color={theme.primaryColor}
|
<Tooltip label={label} openDelay={Constants.tooltip.delay}>
|
||||||
variant={variant}
|
<ActionIcon
|
||||||
className={props.className}
|
color={theme.primaryColor}
|
||||||
onClick={props.onClick}
|
variant={variant}
|
||||||
aria-label={label}
|
className={props.className}
|
||||||
>
|
onClick={props.onClick}
|
||||||
{props.icon}
|
aria-label={label}
|
||||||
</ActionIcon>
|
>
|
||||||
</Tooltip>
|
{props.icon}
|
||||||
) : (
|
</ActionIcon>
|
||||||
<Button
|
</Tooltip>
|
||||||
ref={ref}
|
)}
|
||||||
variant={variant}
|
{!iconOnly && (
|
||||||
size="xs"
|
<Button
|
||||||
className={props.className}
|
variant={variant}
|
||||||
leftSection={props.icon}
|
size="xs"
|
||||||
onClick={props.onClick}
|
className={props.className}
|
||||||
aria-label={label}
|
leftSection={props.icon}
|
||||||
>
|
onClick={props.onClick}
|
||||||
{label}
|
aria-label={label}
|
||||||
</Button>
|
>
|
||||||
|
{label}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
ActionButton.displayName = "HeaderButton"
|
ActionButton.displayName = "HeaderButton"
|
||||||
|
|||||||
@@ -33,6 +33,26 @@ export function KeyboardShortcutsHelp() {
|
|||||||
<Kbd>K</Kbd>
|
<Kbd>K</Kbd>
|
||||||
</Table.Td>
|
</Table.Td>
|
||||||
</Table.Tr>
|
</Table.Tr>
|
||||||
|
<Table.Tr>
|
||||||
|
<Table.Td>
|
||||||
|
<Trans>Select next unread feed/category</Trans>
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td>
|
||||||
|
<Kbd>Shift</Kbd>
|
||||||
|
<span> + </span>
|
||||||
|
<Kbd>J</Kbd>
|
||||||
|
</Table.Td>
|
||||||
|
</Table.Tr>
|
||||||
|
<Table.Tr>
|
||||||
|
<Table.Td>
|
||||||
|
<Trans>Select previous unread feed/category</Trans>
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td>
|
||||||
|
<Kbd>Shift</Kbd>
|
||||||
|
<span> + </span>
|
||||||
|
<Kbd>K</Kbd>
|
||||||
|
</Table.Td>
|
||||||
|
</Table.Tr>
|
||||||
<Table.Tr>
|
<Table.Tr>
|
||||||
<Table.Td>
|
<Table.Td>
|
||||||
<Trans>Set focus on next entry without opening it</Trans>
|
<Trans>Set focus on next entry without opening it</Trans>
|
||||||
|
|||||||
27
commafeed-client/src/components/content/Content.test.tsx
Normal file
27
commafeed-client/src/components/content/Content.test.tsx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { MantineProvider } from "@mantine/core"
|
||||||
|
import { render } from "@testing-library/react"
|
||||||
|
import { Content } from "components/content/Content"
|
||||||
|
import React from "react"
|
||||||
|
import { describe, expect, it } from "vitest"
|
||||||
|
|
||||||
|
describe("Content component", () => {
|
||||||
|
it("renders basic content", () => {
|
||||||
|
const { container } = render(<Content content="<p>Hello World</p>" />, { wrapper: MantineProvider })
|
||||||
|
expect(container.querySelector("p")).toHaveTextContent("Hello World")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("renders highlighted text when highlight prop is provided", () => {
|
||||||
|
const { container } = render(<Content content="Hello World" highlight="World" />, { wrapper: MantineProvider })
|
||||||
|
expect(container.querySelector("mark")).toHaveTextContent("World")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("renders iframe tag when included in content", () => {
|
||||||
|
const { container } = render(<Content content='<iframe src="https://example.com"></iframe>' />, { wrapper: MantineProvider })
|
||||||
|
expect(container.querySelector("iframe")).toHaveAttribute("src", "https://example.com")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("does not render unsupported tags", () => {
|
||||||
|
const { container } = render(<Content content='<script>alert("test")</script>' />, { wrapper: MantineProvider })
|
||||||
|
expect(container.querySelector("script")).toBeNull()
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -4,7 +4,7 @@ import { calculatePlaceholderSize } from "app/utils"
|
|||||||
import { ImageWithPlaceholderWhileLoading } from "components/ImageWithPlaceholderWhileLoading"
|
import { ImageWithPlaceholderWhileLoading } from "components/ImageWithPlaceholderWhileLoading"
|
||||||
import { BasicHtmlStyles } from "components/content/BasicHtmlStyles"
|
import { BasicHtmlStyles } from "components/content/BasicHtmlStyles"
|
||||||
import escapeStringRegexp from "escape-string-regexp"
|
import escapeStringRegexp from "escape-string-regexp"
|
||||||
import { type ChildrenNode, Interweave, type MatchResponse, Matcher, type Node, type TransformCallback } from "interweave"
|
import { ALLOWED_TAG_LIST, type ChildrenNode, Interweave, type MatchResponse, Matcher, type Node, type TransformCallback } from "interweave"
|
||||||
import React from "react"
|
import React from "react"
|
||||||
import styleToObject from "style-to-object"
|
import styleToObject from "style-to-object"
|
||||||
import { tss } from "tss"
|
import { tss } from "tss"
|
||||||
@@ -67,20 +67,19 @@ const transform: TransformCallback = node => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class HighlightMatcher extends Matcher {
|
class HighlightMatcher extends Matcher {
|
||||||
private readonly search: string
|
private readonly regexp: RegExp
|
||||||
|
|
||||||
constructor(search: string) {
|
constructor(search: string) {
|
||||||
super("highlight")
|
super("highlight")
|
||||||
this.search = escapeStringRegexp(search)
|
this.regexp = new RegExp(escapeStringRegexp(search).split(" ").join("|"), "i")
|
||||||
}
|
}
|
||||||
|
|
||||||
match(string: string): MatchResponse<unknown> | null {
|
match(string: string): MatchResponse<unknown> | null {
|
||||||
const pattern = this.search.split(" ").join("|")
|
return this.doMatch(string, this.regexp, () => ({}))
|
||||||
return this.doMatch(string, new RegExp(pattern, "i"), () => ({}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
replaceWith(children: ChildrenNode): Node {
|
replaceWith(children: ChildrenNode): Node {
|
||||||
return <Mark>{children}</Mark>
|
return <Mark key={0}>{children}</Mark>
|
||||||
}
|
}
|
||||||
|
|
||||||
asTag(): string {
|
asTag(): string {
|
||||||
@@ -88,6 +87,9 @@ class HighlightMatcher extends Matcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// allow iframe tag
|
||||||
|
const allowList = [...ALLOWED_TAG_LIST, "iframe"]
|
||||||
|
|
||||||
// memoize component because Interweave is costly
|
// memoize component because Interweave is costly
|
||||||
const Content = React.memo((props: ContentProps) => {
|
const Content = React.memo((props: ContentProps) => {
|
||||||
const { classes } = useStyles()
|
const { classes } = useStyles()
|
||||||
@@ -96,7 +98,7 @@ const Content = React.memo((props: ContentProps) => {
|
|||||||
return (
|
return (
|
||||||
<BasicHtmlStyles>
|
<BasicHtmlStyles>
|
||||||
<Box className={classes.content}>
|
<Box className={classes.content}>
|
||||||
<Interweave content={props.content} transform={transform} matchers={matchers} />
|
<Interweave content={props.content} transform={transform} matchers={matchers} allowList={allowList} />
|
||||||
</Box>
|
</Box>
|
||||||
</BasicHtmlStyles>
|
</BasicHtmlStyles>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
import { redirectToRootCategory } from "app/redirect/thunks"
|
import { redirectToRootCategory } from "app/redirect/thunks"
|
||||||
import { useAppDispatch, useAppSelector } from "app/store"
|
import { useAppDispatch, useAppSelector } from "app/store"
|
||||||
import { toggleSidebar } from "app/tree/slice"
|
import { toggleSidebar } from "app/tree/slice"
|
||||||
|
import { selectNextUnreadTreeItem } from "app/tree/thunks"
|
||||||
import { KeyboardShortcutsHelp } from "components/KeyboardShortcutsHelp"
|
import { KeyboardShortcutsHelp } from "components/KeyboardShortcutsHelp"
|
||||||
import { Loader } from "components/Loader"
|
import { Loader } from "components/Loader"
|
||||||
import { useBrowserExtension } from "hooks/useBrowserExtension"
|
import { useBrowserExtension } from "hooks/useBrowserExtension"
|
||||||
@@ -172,6 +173,8 @@ export function FeedEntries() {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
useMousetrap("shift+j", async () => await dispatch(selectNextUnreadTreeItem({ direction: "forward" })))
|
||||||
|
useMousetrap("shift+k", async () => await dispatch(selectNextUnreadTreeItem({ direction: "backward" })))
|
||||||
useMousetrap("space", () => {
|
useMousetrap("space", () => {
|
||||||
if (selectedEntry) {
|
if (selectedEntry) {
|
||||||
if (selectedEntry.expanded) {
|
if (selectedEntry.expanded) {
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr ""
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0> هل تحتاج إلى حساب؟ </0> <1> اشترك! </ 1>"
|
msgstr "<0> هل تحتاج إلى حساب؟ </0> <1> اشترك! </ 1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "حول"
|
msgstr "حول"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "إضافة فئة"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "إضافة مستخدم"
|
msgstr "إضافة مستخدم"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "إداري"
|
msgstr "إداري"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "الكل"
|
msgstr "الكل"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr ""
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "إلغاء"
|
msgstr "إلغاء"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "الفئة"
|
msgstr "الفئة"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr ""
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "مضغوط"
|
msgstr "مضغوط"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "تأكيد"
|
msgstr "تأكيد"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr "تنازلي"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "عرض"
|
msgstr "عرض"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "تنزيل"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "اسحب الرابط إلى شريط الإشارات"
|
msgstr "اسحب الرابط إلى شريط الإشارات"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "البريد الإلكتروني"
|
msgstr "البريد الإلكتروني"
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "عنوان البريد الإلكتروني"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "تحرير المستخدم"
|
msgstr "تحرير المستخدم"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "ممكن"
|
msgstr "ممكن"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "موسع"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "قم بتصدير اشتراكاتك وفئاتك كملف OPML يمكن استيراده في خدمات قراءة الأعلاف الأخرى"
|
msgstr "قم بتصدير اشتراكاتك وفئاتك كملف OPML يمكن استيراده في خدمات قراءة الأعلاف الأخرى"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr ""
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "اسم الخلاصة"
|
msgstr "اسم الخلاصة"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "موجز URL"
|
msgstr "موجز URL"
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr ""
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "هل نسيت كلمة المرور؟"
|
msgstr "هل نسيت كلمة المرور؟"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "قم بإنشاء مفتاح API في ملف التعريف الخاص بك أولاً."
|
msgstr "قم بإنشاء مفتاح API في ملف التعريف الخاص بك أولاً."
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "قم بإنشاء مفتاح API في ملف التعريف الخاص
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "إنشاء مفتاح API جديد"
|
msgstr "إنشاء مفتاح API جديد"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "رابط الخلاصة المولدة"
|
msgstr "رابط الخلاصة المولدة"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -440,13 +440,13 @@ msgstr "استيراد"
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "في العرض الموسع ، التمرير عبر الإدخالات وضع علامة عليها كمقروءة"
|
msgstr "في العرض الموسع ، التمرير عبر الإدخالات وضع علامة عليها كمقروءة"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "إبقاء غير مقروءة"
|
msgstr "إبقاء غير مقروءة"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "اختصارات لوحة المفاتيح"
|
msgstr "اختصارات لوحة المفاتيح"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "آخر رسالة تحديث"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "رابط"
|
msgstr "رابط"
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "تحميل الاشتراكات ..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "تحميل العلامات ..."
|
msgstr "تحميل العلامات ..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "تسجيل الدخول"
|
msgstr "تسجيل الدخول"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "تسجيل الخروج"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "إدارة المستخدمين"
|
msgstr "إدارة المستخدمين"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "إدارة المستخدمين"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "تعليم الكل كمقروء"
|
msgstr "تعليم الكل كمقروء"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "تعليم كافة الإدخالات كمقروءة"
|
msgstr "تعليم كافة الإدخالات كمقروءة"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "وضع علامة كمقروء"
|
msgstr "وضع علامة كمقروء"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "وضع علامة كمقروءة حتى هنا"
|
msgstr "وضع علامة كمقروءة حتى هنا"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "تحريك الصفحة لأسفل"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "تحريك الصفحة لأعلى"
|
msgstr "تحريك الصفحة لأعلى"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr "لا"
|
msgstr "لا"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "الاسم"
|
msgstr "الاسم"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "كلمة مرور جديدة"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "الأحدث أولاً"
|
msgstr "الأحدث أولاً"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "التالي"
|
msgstr "التالي"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "والد"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "الفئة الأصل"
|
msgstr "الفئة الأصل"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "كلمة المرور"
|
msgstr "كلمة المرور"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "استعادة كلمة المرور"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "كلمات المرور غير متطابقة"
|
msgstr "كلمات المرور غير متطابقة"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "المنـصب"
|
msgstr "المنـصب"
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "الملف الشخصي"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "استعادة كلمة السر"
|
msgstr "استعادة كلمة السر"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "تحديث"
|
msgstr "تحديث"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr ""
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "حفظ"
|
msgstr "حفظ"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "قم بالتمرير بسلاسة عند التنقل بين الإدخ
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "بحث"
|
msgstr "بحث"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "بحث"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "يتطلب البحث 3 أحرف على الأقل"
|
msgstr "يتطلب البحث 3 أحرف على الأقل"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "ضع التركيز على الإدخال التالي دون فتحه"
|
msgstr "ضع التركيز على الإدخال التالي دون فتحه"
|
||||||
@@ -850,9 +858,9 @@ msgstr ""
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "قم بالتسجيل"
|
msgstr "قم بالتسجيل"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "شيء سيء حدث للتو ..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "فضاء"
|
msgstr "فضاء"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "النجم"
|
msgstr "النجم"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "مميز بنجمة"
|
msgstr "مميز بنجمة"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "اشتراك"
|
msgstr "اشتراك"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr ""
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "غير مقروءة"
|
msgstr "غير مقروءة"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "إلغاء النجم"
|
msgstr "إلغاء النجم"
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr "<0>Ei,</0><1> sóc la Jérémie de Bèlgica i fa més de 10 anys que tre
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>Necessites un compte?</0><1>Registreu-vos!</1>"
|
msgstr "<0>Necessites un compte?</0><1>Registreu-vos!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Sobre"
|
msgstr "Sobre"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "Afegeix categoria"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Afegeix usuari"
|
msgstr "Afegeix usuari"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Administrador"
|
msgstr "Administrador"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Tot"
|
msgstr "Tot"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr "Extensió del navegador"
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Cancel·la"
|
msgstr "Cancel·la"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Categoria"
|
msgstr "Categoria"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr "CommaFeed versió {version} ({version})."
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Compacte"
|
msgstr "Compacte"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Confirma"
|
msgstr "Confirma"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr "Desc"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr "Detallat"
|
msgstr "Detallat"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Mostra"
|
msgstr "Mostra"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr "Donar"
|
msgstr "Donar"
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "Descarrega"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "Arrossegueu l'enllaç a la barra d'adreces d'interès"
|
msgstr "Arrossegueu l'enllaç a la barra d'adreces d'interès"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "Correu electrònic"
|
msgstr "Correu electrònic"
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "Adreça de correu electrònic"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Edita l'usuari"
|
msgstr "Edita l'usuari"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "activat"
|
msgstr "activat"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "Ampliat"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "exporteu les vostres subscripcions i categories com a fitxer OPML que es pot importar a altres serveis de lectura de feeds"
|
msgstr "exporteu les vostres subscripcions i categories com a fitxer OPML que es pot importar a altres serveis de lectura de feeds"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr "Opcions de l'extensió"
|
msgstr "Opcions de l'extensió"
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr "Opcions de l'extensió"
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "Nom del canal"
|
msgstr "Nom del canal"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "URL del canal"
|
msgstr "URL del canal"
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr ""
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Heu oblidat la contrasenya?"
|
msgstr "Heu oblidat la contrasenya?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "primer genereu una clau API al vostre perfil."
|
msgstr "primer genereu una clau API al vostre perfil."
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "primer genereu una clau API al vostre perfil."
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "Genera una nova clau d'API"
|
msgstr "Genera una nova clau d'API"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "URL del feed generat"
|
msgstr "URL del feed generat"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr "Vés a {0}"
|
msgstr "Vés a {0}"
|
||||||
@@ -440,13 +440,13 @@ msgstr "Importació"
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "a la vista ampliada, desplaçant-se per les entrades les marqueu com a llegides"
|
msgstr "a la vista ampliada, desplaçant-se per les entrades les marqueu com a llegides"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Mantenir sense llegir"
|
msgstr "Mantenir sense llegir"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Dreceres de teclat"
|
msgstr "Dreceres de teclat"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "últim missatge d'actualització"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr "Clar"
|
msgstr "Clar"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "Enllaç"
|
msgstr "Enllaç"
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "S'estan carregant les subscripcions..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "Carregant les etiquetes..."
|
msgstr "Carregant les etiquetes..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Inicia sessió"
|
msgstr "Inicia sessió"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "Tanca sessió"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Gestionar usuaris"
|
msgstr "Gestionar usuaris"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "Gestionar usuaris"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "Marca-ho tot com a llegit"
|
msgstr "Marca-ho tot com a llegit"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "Marqueu totes les entrades com a llegides"
|
msgstr "Marqueu totes les entrades com a llegides"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Marca com a llegit"
|
msgstr "Marca com a llegit"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "Marca com a llegit fins aquí"
|
msgstr "Marca com a llegit fins aquí"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "Mou la pàgina cap avall"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "Mou la pàgina cap amunt"
|
msgstr "Mou la pàgina cap amunt"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nom"
|
msgstr "Nom"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "Contrasenya nova"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "El més nou primer"
|
msgstr "El més nou primer"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Següent"
|
msgstr "Següent"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "pares"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "Categoria pare"
|
msgstr "Categoria pare"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Contrasenya"
|
msgstr "Contrasenya"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "Recuperació de contrasenya"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Les contrasenyes no coincideixen"
|
msgstr "Les contrasenyes no coincideixen"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Posició"
|
msgstr "Posició"
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "Perfil"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Recuperar la contrasenya"
|
msgstr "Recuperar la contrasenya"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Actualitzar"
|
msgstr "Actualitzar"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr "API REST"
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr "Clic dret"
|
msgstr "Clic dret"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Desa"
|
msgstr "Desa"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "Desplaceu-vos suaument quan navegueu entre entrades"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr "Desplaçament"
|
msgstr "Desplaçament"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Cerca"
|
msgstr "Cerca"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "Cerca"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "la cerca requereix almenys 3 caràcters"
|
msgstr "la cerca requereix almenys 3 caràcters"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "posa el focus a la següent entrada sense obrir-la"
|
msgstr "posa el focus a la següent entrada sense obrir-la"
|
||||||
@@ -850,9 +858,9 @@ msgstr ""
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "Registra't"
|
msgstr "Registra't"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "Acaba de passar una cosa dolenta..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Espai"
|
msgstr "Espai"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "Estrella"
|
msgstr "Estrella"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "Estrellat"
|
msgstr "Estrellat"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "Subscriu-te"
|
msgstr "Subscriu-te"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr "Prova la demostració!"
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Sense llegir"
|
msgstr "Sense llegir"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "Desestrellar"
|
msgstr "Desestrellar"
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr ""
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>Potřebujete účet?</0><1>Zaregistrujte se!</1>"
|
msgstr "<0>Potřebujete účet?</0><1>Zaregistrujte se!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Asi"
|
msgstr "Asi"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "Přidat kategorii"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Přidat uživatele"
|
msgstr "Přidat uživatele"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Správce"
|
msgstr "Správce"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Všechny"
|
msgstr "Všechny"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr ""
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Zrušit"
|
msgstr "Zrušit"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Kategorie"
|
msgstr "Kategorie"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr ""
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Kompaktní"
|
msgstr "Kompaktní"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Potvrdit"
|
msgstr "Potvrdit"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr ""
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Displej"
|
msgstr "Displej"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "Stáhnout"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "Přetáhněte odkaz na lištu záložek"
|
msgstr "Přetáhněte odkaz na lištu záložek"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "E-mailová adresa"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Upravit uživatele"
|
msgstr "Upravit uživatele"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Povoleno"
|
msgstr "Povoleno"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "Rozbaleno"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "Exportujte svá předplatná a kategorie jako soubor OPML, který lze importovat do jiných služeb čtení kanálů"
|
msgstr "Exportujte svá předplatná a kategorie jako soubor OPML, který lze importovat do jiných služeb čtení kanálů"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr ""
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "Název zdroje"
|
msgstr "Název zdroje"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "URL zdroje"
|
msgstr "URL zdroje"
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr ""
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Zapomněli jste heslo?"
|
msgstr "Zapomněli jste heslo?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "Nejprve ve svém profilu vygenerujte klíč API."
|
msgstr "Nejprve ve svém profilu vygenerujte klíč API."
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "Nejprve ve svém profilu vygenerujte klíč API."
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "Vygenerujte nový klíč API"
|
msgstr "Vygenerujte nový klíč API"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "Generovaná adresa URL zdroje"
|
msgstr "Generovaná adresa URL zdroje"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -440,13 +440,13 @@ msgstr ""
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "V rozšířeném zobrazení je procházením označíte jako přečtené"
|
msgstr "V rozšířeném zobrazení je procházením označíte jako přečtené"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Ponechat nepřečtené"
|
msgstr "Ponechat nepřečtené"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Klávesové zkratky"
|
msgstr "Klávesové zkratky"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "Poslední obnovovací zpráva"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "Odkaz"
|
msgstr "Odkaz"
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "Načítání odběrů..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "Načítání značek..."
|
msgstr "Načítání značek..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Přihlaste se"
|
msgstr "Přihlaste se"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "Odhlášení"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Spravujte uživatele"
|
msgstr "Spravujte uživatele"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "Spravujte uživatele"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "Označit vše jako přečtené"
|
msgstr "Označit vše jako přečtené"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "Označte všechny položky jako přečtené"
|
msgstr "Označte všechny položky jako přečtené"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Označit jako přečtené"
|
msgstr "Označit jako přečtené"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "Označit jako přečtené až sem"
|
msgstr "Označit jako přečtené až sem"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "Přesuňte stránku dolů"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "Přesuňte stránku nahoru"
|
msgstr "Přesuňte stránku nahoru"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Jméno"
|
msgstr "Jméno"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "Nové heslo"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Nejnovější jako první"
|
msgstr "Nejnovější jako první"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Další"
|
msgstr "Další"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "Rodič"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "Rodičovská kategorie"
|
msgstr "Rodičovská kategorie"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Heslo"
|
msgstr "Heslo"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "Obnovení hesla"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Hesla se neshodují"
|
msgstr "Hesla se neshodují"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Pozice"
|
msgstr "Pozice"
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "Profil"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Obnovte heslo"
|
msgstr "Obnovte heslo"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Obnovit"
|
msgstr "Obnovit"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr ""
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Uložit"
|
msgstr "Uložit"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "Posouvejte plynule při navigaci mezi položkami"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Hledej"
|
msgstr "Hledej"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "Hledej"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "Hledání vyžaduje alespoň 3 znaky"
|
msgstr "Hledání vyžaduje alespoň 3 znaky"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "Zaměřte se na další položku, aniž byste ji otevřeli"
|
msgstr "Zaměřte se na další položku, aniž byste ji otevřeli"
|
||||||
@@ -850,9 +858,9 @@ msgstr ""
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "Zaregistrujte se"
|
msgstr "Zaregistrujte se"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "Právě se stalo něco špatného..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Vesmír"
|
msgstr "Vesmír"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "Hvězda"
|
msgstr "Hvězda"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "S hvězdičkou"
|
msgstr "S hvězdičkou"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "Přihlaste se"
|
msgstr "Přihlaste se"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr ""
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Nepřečteno"
|
msgstr "Nepřečteno"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "Odstranit hvězdu"
|
msgstr "Odstranit hvězdu"
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr ""
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>Angen cyfrif?</0><1>Ymunwch!</1>"
|
msgstr "<0>Angen cyfrif?</0><1>Ymunwch!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Ynghylch"
|
msgstr "Ynghylch"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "Ychwanegu categori"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Ychwanegu defnyddiwr"
|
msgstr "Ychwanegu defnyddiwr"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Gweinyddol"
|
msgstr "Gweinyddol"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Pawb"
|
msgstr "Pawb"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr ""
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Diddymu"
|
msgstr "Diddymu"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "categori"
|
msgstr "categori"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr ""
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "cryno"
|
msgstr "cryno"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Cadarnhau"
|
msgstr "Cadarnhau"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr "Rhag"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Arddangos"
|
msgstr "Arddangos"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "Lawrlwytho"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "Llusgwch y ddolen i'r bar nod tudalen"
|
msgstr "Llusgwch y ddolen i'r bar nod tudalen"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "E-bost"
|
msgstr "E-bost"
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "cyfeiriad e-bost"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Golygu defnyddiwr"
|
msgstr "Golygu defnyddiwr"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Wedi'i alluogi"
|
msgstr "Wedi'i alluogi"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "Ehangu"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "Allforio eich tanysgrifiadau a'ch categorïau fel ffeil OPML y gellir ei mewnforio i wasanaethau darllen porthiant eraill"
|
msgstr "Allforio eich tanysgrifiadau a'ch categorïau fel ffeil OPML y gellir ei mewnforio i wasanaethau darllen porthiant eraill"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr ""
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "Enw porthiant"
|
msgstr "Enw porthiant"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "URL porthiant"
|
msgstr "URL porthiant"
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr ""
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Wedi anghofio cyfrinair?"
|
msgstr "Wedi anghofio cyfrinair?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "Cynhyrchu allwedd API yn eich proffil yn gyntaf."
|
msgstr "Cynhyrchu allwedd API yn eich proffil yn gyntaf."
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "Cynhyrchu allwedd API yn eich proffil yn gyntaf."
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "Cynhyrchu allwedd API newydd"
|
msgstr "Cynhyrchu allwedd API newydd"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "url porthiant a gynhyrchir"
|
msgstr "url porthiant a gynhyrchir"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -440,13 +440,13 @@ msgstr "Mewnforio"
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "Mewn gwedd estynedig, mae sgrolio trwy gofnodion yn nodi eu bod wedi'u darllen"
|
msgstr "Mewn gwedd estynedig, mae sgrolio trwy gofnodion yn nodi eu bod wedi'u darllen"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Cadwch heb ei ddarllen"
|
msgstr "Cadwch heb ei ddarllen"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "llwybrau byr bysellfwrdd"
|
msgstr "llwybrau byr bysellfwrdd"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "Neges adnewyddu ddiwethaf"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "Cyswllt"
|
msgstr "Cyswllt"
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "Yn llwytho tanysgrifiadau..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "Wrthi'n llwytho tagiau..."
|
msgstr "Wrthi'n llwytho tagiau..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Mewngofnodi"
|
msgstr "Mewngofnodi"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "Allgofnodi"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Rheoli defnyddwyr"
|
msgstr "Rheoli defnyddwyr"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "Rheoli defnyddwyr"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "Marciwch y cyfan wedi'i ddarllen"
|
msgstr "Marciwch y cyfan wedi'i ddarllen"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "Marciwch bob cofnod wedi'i ddarllen"
|
msgstr "Marciwch bob cofnod wedi'i ddarllen"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Marciwch ei fod wedi'i ddarllen"
|
msgstr "Marciwch ei fod wedi'i ddarllen"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "Marciwch fel y darllenwyd hyd yma"
|
msgstr "Marciwch fel y darllenwyd hyd yma"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "Symudwch y dudalen i lawr"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "Symudwch y dudalen i fyny"
|
msgstr "Symudwch y dudalen i fyny"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr "Amh"
|
msgstr "Amh"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Enw"
|
msgstr "Enw"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "Cyfrinair newydd"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Y diweddaraf yn gyntaf"
|
msgstr "Y diweddaraf yn gyntaf"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Nesaf"
|
msgstr "Nesaf"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "rhiant"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "Categori Rhiant"
|
msgstr "Categori Rhiant"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "cyfrinair"
|
msgstr "cyfrinair"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "Adfer Cyfrinair"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Nid yw cyfrineiriau yn cyfateb"
|
msgstr "Nid yw cyfrineiriau yn cyfateb"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Swydd"
|
msgstr "Swydd"
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "Proffil"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Adfer cyfrinair"
|
msgstr "Adfer cyfrinair"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Adnewyddu"
|
msgstr "Adnewyddu"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr ""
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Arbed"
|
msgstr "Arbed"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "Sgroliwch yn esmwyth wrth lywio rhwng cofnodion"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Chwilio"
|
msgstr "Chwilio"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "Chwilio"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "Mae angen o leiaf 3 nod ar gyfer chwilio"
|
msgstr "Mae angen o leiaf 3 nod ar gyfer chwilio"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "Gosodwch ffocws ar y cofnod nesaf heb ei agor"
|
msgstr "Gosodwch ffocws ar y cofnod nesaf heb ei agor"
|
||||||
@@ -850,9 +858,9 @@ msgstr ""
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "Cofrestrwch"
|
msgstr "Cofrestrwch"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "Mae rhywbeth drwg newydd ddigwydd ..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Gofod"
|
msgstr "Gofod"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "seren"
|
msgstr "seren"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "serennog"
|
msgstr "serennog"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "Tanysgrifio"
|
msgstr "Tanysgrifio"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr ""
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Heb ei ddarllen"
|
msgstr "Heb ei ddarllen"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "dad-seren"
|
msgstr "dad-seren"
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr ""
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>Har du brug for en konto?</0><1>Tilmeld dig!</1>"
|
msgstr "<0>Har du brug for en konto?</0><1>Tilmeld dig!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Omkring"
|
msgstr "Omkring"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "Tilføj kategori"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Tilføj bruger"
|
msgstr "Tilføj bruger"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Alle"
|
msgstr "Alle"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr ""
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Annuller"
|
msgstr "Annuller"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Kategori"
|
msgstr "Kategori"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr ""
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Kompakt"
|
msgstr "Kompakt"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Bekræft"
|
msgstr "Bekræft"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr ""
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Skærm"
|
msgstr "Skærm"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr ""
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "Træk linket til bogmærkelinjen"
|
msgstr "Træk linket til bogmærkelinjen"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "E-mailadresse"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Rediger bruger"
|
msgstr "Rediger bruger"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Aktiveret"
|
msgstr "Aktiveret"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "Udvidet"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "Eksporter dine abonnementer og kategorier som en OPML-fil, der kan importeres i andre feed-læsningstjenester"
|
msgstr "Eksporter dine abonnementer og kategorier som en OPML-fil, der kan importeres i andre feed-læsningstjenester"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr ""
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "Feednavn"
|
msgstr "Feednavn"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr ""
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Glemt adgangskode?"
|
msgstr "Glemt adgangskode?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "Generer først en API-nøgle i din profil."
|
msgstr "Generer først en API-nøgle i din profil."
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "Generer først en API-nøgle i din profil."
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "Generer ny API-nøgle"
|
msgstr "Generer ny API-nøgle"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "Genereret feed-url"
|
msgstr "Genereret feed-url"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -440,13 +440,13 @@ msgstr ""
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "I udvidet visning markerer du dem som læst, når du ruller gennem poster"
|
msgstr "I udvidet visning markerer du dem som læst, når du ruller gennem poster"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Forbehold ulæst"
|
msgstr "Forbehold ulæst"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Tastaturgenveje"
|
msgstr "Tastaturgenveje"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "Sidste opdateringsmeddelelse"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "Indlæser abonnementer..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "Indlæser tags..."
|
msgstr "Indlæser tags..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Log ind"
|
msgstr "Log ind"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "Log ud"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Administrer brugere"
|
msgstr "Administrer brugere"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "Administrer brugere"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "Marker alle som læst"
|
msgstr "Marker alle som læst"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "Marker alle poster som læst"
|
msgstr "Marker alle poster som læst"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Markér som læst"
|
msgstr "Markér som læst"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "Markér som læst indtil her"
|
msgstr "Markér som læst indtil her"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "Flyt siden ned"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "Flyt siden op"
|
msgstr "Flyt siden op"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Navn"
|
msgstr "Navn"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "Ny adgangskode"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Nyeste først"
|
msgstr "Nyeste først"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Næste"
|
msgstr "Næste"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "Forælder"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "Forældrekategori"
|
msgstr "Forældrekategori"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Adgangskode"
|
msgstr "Adgangskode"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "Gendannelse af adgangskode"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Adgangskoder stemmer ikke overens"
|
msgstr "Adgangskoder stemmer ikke overens"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "Profil"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Gendan adgangskode"
|
msgstr "Gendan adgangskode"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Opdater"
|
msgstr "Opdater"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr ""
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Gem"
|
msgstr "Gem"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "Rul jævnt, når du navigerer mellem poster"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Søg"
|
msgstr "Søg"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "Søg"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "Søgning kræver mindst 3 tegn"
|
msgstr "Søgning kræver mindst 3 tegn"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "Sæt fokus på næste post uden at åbne den"
|
msgstr "Sæt fokus på næste post uden at åbne den"
|
||||||
@@ -850,9 +858,9 @@ msgstr ""
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "Tilmeld dig"
|
msgstr "Tilmeld dig"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "Der er lige sket noget slemt..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Rum"
|
msgstr "Rum"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "Stjerne"
|
msgstr "Stjerne"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "Medvirkende"
|
msgstr "Medvirkende"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "Tilmeld"
|
msgstr "Tilmeld"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr ""
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Ulæst"
|
msgstr "Ulæst"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr "<0>Hey,</0><1>Ich bin Jérémie aus Belgien und arbeite seit über 10 Ja
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>Benötigen Sie ein Konto?</0><1>Hier geht's zur Registrierung!</1>"
|
msgstr "<0>Benötigen Sie ein Konto?</0><1>Hier geht's zur Registrierung!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Über"
|
msgstr "Über"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "Kategorie hinzufügen"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Benutzer hinzufügen"
|
msgstr "Benutzer hinzufügen"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Verwaltung"
|
msgstr "Verwaltung"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Alle"
|
msgstr "Alle"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr "Browser-Erweiterung"
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Abbrechen"
|
msgstr "Abbrechen"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Kategorie"
|
msgstr "Kategorie"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr "CommaFeed version {version} ({revision})."
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Kompakt"
|
msgstr "Kompakt"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Bestätigen"
|
msgstr "Bestätigen"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr "Beschr"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr "Detailliert"
|
msgstr "Detailliert"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Anzeige"
|
msgstr "Anzeige"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr "Spenden"
|
msgstr "Spenden"
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "Herunterladen"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "Link in Lesezeichenleiste ziehen"
|
msgstr "Link in Lesezeichenleiste ziehen"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "E-Mail"
|
msgstr "E-Mail"
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "E-Mail-Adresse"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Benutzer bearbeiten"
|
msgstr "Benutzer bearbeiten"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Aktiviert"
|
msgstr "Aktiviert"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "Erweitert"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "Exportieren Sie Ihre Abonnements und Kategorien als OPML-Datei, die in andere Feed-Lesedienste importiert werden kann"
|
msgstr "Exportieren Sie Ihre Abonnements und Kategorien als OPML-Datei, die in andere Feed-Lesedienste importiert werden kann"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr "Erweiterungsoptionen"
|
msgstr "Erweiterungsoptionen"
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr "Erweiterungsoptionen"
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "Feedname"
|
msgstr "Feedname"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "Feed-URL"
|
msgstr "Feed-URL"
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr ""
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Passwort vergessen?"
|
msgstr "Passwort vergessen?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "Generieren Sie zuerst einen API-Schlüssel in Ihrem Profil."
|
msgstr "Generieren Sie zuerst einen API-Schlüssel in Ihrem Profil."
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "Generieren Sie zuerst einen API-Schlüssel in Ihrem Profil."
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "Neuen API-Schlüssel generieren"
|
msgstr "Neuen API-Schlüssel generieren"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "Generierte Feed-URL"
|
msgstr "Generierte Feed-URL"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr "Gehe zu {0}"
|
msgstr "Gehe zu {0}"
|
||||||
@@ -440,13 +440,13 @@ msgstr "Importieren"
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "In der erweiterten Ansicht werden Einträge beim Scrollen als gelesen markiert"
|
msgstr "In der erweiterten Ansicht werden Einträge beim Scrollen als gelesen markiert"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Ungelesen lassen"
|
msgstr "Ungelesen lassen"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Tastaturkürzel"
|
msgstr "Tastaturkürzel"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "Letzte Aktualisierungsmeldung"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr "Hell"
|
msgstr "Hell"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "Verbindung"
|
msgstr "Verbindung"
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "Abonnements werden geladen..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "Tags werden geladen..."
|
msgstr "Tags werden geladen..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Einloggen"
|
msgstr "Einloggen"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "Abmelden"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr "Langer Tastendruck"
|
msgstr "Langer Tastendruck"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Benutzer verwalten"
|
msgstr "Benutzer verwalten"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "Benutzer verwalten"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "Alle als gelesen markieren"
|
msgstr "Alle als gelesen markieren"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "Alle Einträge als gelesen markieren"
|
msgstr "Alle Einträge als gelesen markieren"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Als gelesen markieren"
|
msgstr "Als gelesen markieren"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "Bis hierhin als gelesen markieren"
|
msgstr "Bis hierhin als gelesen markieren"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "Seite nach unten verschieben"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "Bewege die Seite nach oben"
|
msgstr "Bewege die Seite nach oben"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr "n.v."
|
msgstr "n.v."
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "Neues Passwort"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Neueste zuerst"
|
msgstr "Neueste zuerst"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Weiter"
|
msgstr "Weiter"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "Übergeordnet"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "Übergeordnete Kategorie"
|
msgstr "Übergeordnete Kategorie"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Passwort"
|
msgstr "Passwort"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "Passwortwiederherstellung"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Passwörter stimmen nicht überein"
|
msgstr "Passwörter stimmen nicht überein"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Position"
|
msgstr "Position"
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "Profil"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Kennwort wiederherstellen"
|
msgstr "Kennwort wiederherstellen"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Aktualisieren"
|
msgstr "Aktualisieren"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr "REST-API"
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr "Rechtsklick"
|
msgstr "Rechtsklick"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Speichern"
|
msgstr "Speichern"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "Schnelles Scrollen beim Navigieren zwischen Einträgen"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr "Scrollen"
|
msgstr "Scrollen"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Suche"
|
msgstr "Suche"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "Suche"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "Suche erfordert mindestens 3 Zeichen"
|
msgstr "Suche erfordert mindestens 3 Zeichen"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "Fokus auf den nächsten Eintrag setzen, ohne ihn zu öffnen"
|
msgstr "Fokus auf den nächsten Eintrag setzen, ohne ihn zu öffnen"
|
||||||
@@ -850,9 +858,9 @@ msgstr ""
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "Melden Sie sich an"
|
msgstr "Melden Sie sich an"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "Etwas Schlimmes ist gerade passiert..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Raum"
|
msgstr "Raum"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "Stern"
|
msgstr "Stern"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "Markiert"
|
msgstr "Markiert"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "Abonnieren"
|
msgstr "Abonnieren"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr "Testen Sie die Demo!"
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Ungelesen"
|
msgstr "Ungelesen"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "Stern entfernen"
|
msgstr "Stern entfernen"
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr "<0>Hey,</0><1>I'm Jérémie from Belgium and I've been working on CommaF
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>Need an account?</0><1>Sign up!</1>"
|
msgstr "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "About"
|
msgstr "About"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "Add category"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Add user"
|
msgstr "Add user"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Admin"
|
msgstr "Admin"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "All"
|
msgstr "All"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr "Browser extention"
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr "Browser tab"
|
msgstr "Browser tab"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Cancel"
|
msgstr "Cancel"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Category"
|
msgstr "Category"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr "CommaFeed version {version} ({revision})."
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Compact"
|
msgstr "Compact"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Confirm"
|
msgstr "Confirm"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr "Desc"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr "Detailed"
|
msgstr "Detailed"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Display"
|
msgstr "Display"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr "Donate"
|
msgstr "Donate"
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "Download"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "Drag link to bookmark bar"
|
msgstr "Drag link to bookmark bar"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "E-mail"
|
msgstr "E-mail"
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "E-mail address"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Edit user"
|
msgstr "Edit user"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Enabled"
|
msgstr "Enabled"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "Expanded"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgstr "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr "Extension options"
|
msgstr "Extension options"
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr "Extension options"
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "Feed name"
|
msgstr "Feed name"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "Feed URL"
|
msgstr "Feed URL"
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr "Force fetching feeds is not yet available."
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Forgot password?"
|
msgstr "Forgot password?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "Generate an API key in your profile first."
|
msgstr "Generate an API key in your profile first."
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "Generate an API key in your profile first."
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "Generate new API key"
|
msgstr "Generate new API key"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "Generated feed url"
|
msgstr "Generated feed url"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr "Go to {0}"
|
msgstr "Go to {0}"
|
||||||
@@ -440,13 +440,13 @@ msgstr "Import"
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "In expanded view, scrolling through entries mark them as read"
|
msgstr "In expanded view, scrolling through entries mark them as read"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Keep unread"
|
msgstr "Keep unread"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Keyboard shortcuts"
|
msgstr "Keyboard shortcuts"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "Last refresh message"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr "Light"
|
msgstr "Light"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "Link"
|
msgstr "Link"
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "Loading subscriptions..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "Loading tags..."
|
msgstr "Loading tags..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Log in"
|
msgstr "Log in"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "Logout"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr "Long press"
|
msgstr "Long press"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Manage users"
|
msgstr "Manage users"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "Manage users"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "Mark all as read"
|
msgstr "Mark all as read"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "Mark all entries as read"
|
msgstr "Mark all entries as read"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Mark as read"
|
msgstr "Mark as read"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "Mark as read up to here"
|
msgstr "Mark as read up to here"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "Move the page down"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "Move the page up"
|
msgstr "Move the page up"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr "N/A"
|
msgstr "N/A"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Name"
|
msgstr "Name"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "New password"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Newest first"
|
msgstr "Newest first"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Next"
|
msgstr "Next"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "Parent"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "Parent Category"
|
msgstr "Parent Category"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Password"
|
msgstr "Password"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "Password Recovery"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Passwords do not match"
|
msgstr "Passwords do not match"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Position"
|
msgstr "Position"
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "Profile"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Recover password"
|
msgstr "Recover password"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Refresh"
|
msgstr "Refresh"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr "REST API"
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr "Right click"
|
msgstr "Right click"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Save"
|
msgstr "Save"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "Scroll smoothly when navigating between entries"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr "Scrolling"
|
msgstr "Scrolling"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Search"
|
msgstr "Search"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "Search"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "Search requires at least 3 characters"
|
msgstr "Search requires at least 3 characters"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr "Select next unread feed/category"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr "Select previous unread feed/category"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "Set focus on next entry without opening it"
|
msgstr "Set focus on next entry without opening it"
|
||||||
@@ -850,9 +858,9 @@ msgstr "Show unread count in tab favicon"
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr "Show unread count in tab title"
|
msgstr "Show unread count in tab title"
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "Sign up"
|
msgstr "Sign up"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "Something bad just happened..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Space"
|
msgstr "Space"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "Star"
|
msgstr "Star"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "Starred"
|
msgstr "Starred"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "Subscribe"
|
msgstr "Subscribe"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr "Try the demo!"
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Unread"
|
msgstr "Unread"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "Unstar"
|
msgstr "Unstar"
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ msgstr "<0>Hola,</0><1>Soy Jérémie de Bélgica y he estado trabajando en Comma
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>¿Necesitas una cuenta?</0><1>¡Regístrate!</1>"
|
msgstr "<0>¿Necesitas una cuenta?</0><1>¡Regístrate!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Acerca de"
|
msgstr "Acerca de"
|
||||||
|
|
||||||
@@ -55,16 +55,15 @@ msgstr "Añadir categoría"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Añadir usuario"
|
msgstr "Añadir usuario"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Administrador"
|
msgstr "Administrador"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Todo"
|
msgstr "Todo"
|
||||||
|
|
||||||
@@ -145,27 +144,27 @@ msgstr "Extensión del navegador"
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr "Pestaña del navegador"
|
msgstr "Pestaña del navegador"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Cancelar"
|
msgstr "Cancelar"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Categoría"
|
msgstr "Categoría"
|
||||||
|
|
||||||
@@ -205,11 +204,11 @@ msgstr "Versión de CommaFeed {version} ({revision})."
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Compacto"
|
msgstr "Compacto"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Confirmar"
|
msgstr "Confirmar"
|
||||||
|
|
||||||
@@ -274,13 +273,13 @@ msgstr "Desc"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr "Detallado"
|
msgstr "Detallado"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Mostrar"
|
msgstr "Mostrar"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr "Donar"
|
msgstr "Donar"
|
||||||
|
|
||||||
@@ -292,11 +291,11 @@ msgstr "Descargar"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "Arrastra el enlace a la barra de marcadores"
|
msgstr "Arrastra el enlace a la barra de marcadores"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "Correo electrónico"
|
msgstr "Correo electrónico"
|
||||||
|
|
||||||
@@ -309,8 +308,8 @@ msgstr "Dirección de correo electrónico"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Editar usuario"
|
msgstr "Editar usuario"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Habilitado"
|
msgstr "Habilitado"
|
||||||
|
|
||||||
@@ -346,8 +345,8 @@ msgstr "Expandido"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "Exporta tus suscripciones y categorías como un archivo OPML que se puede importar en otros servicios de lectura de feeds"
|
msgstr "Exporta tus suscripciones y categorías como un archivo OPML que se puede importar en otros servicios de lectura de feeds"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr "Opciones de la extensión"
|
msgstr "Opciones de la extensión"
|
||||||
|
|
||||||
@@ -355,9 +354,9 @@ msgstr "Opciones de la extensión"
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "Nombre del feed"
|
msgstr "Nombre del feed"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "URL del feed"
|
msgstr "URL del feed"
|
||||||
|
|
||||||
@@ -385,9 +384,9 @@ msgstr ""
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "¿Olvidaste la contraseña?"
|
msgstr "¿Olvidaste la contraseña?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "Primero genere una clave API en su perfil."
|
msgstr "Primero genere una clave API en su perfil."
|
||||||
|
|
||||||
@@ -395,12 +394,13 @@ msgstr "Primero genere una clave API en su perfil."
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "Generar nueva clave API"
|
msgstr "Generar nueva clave API"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "URL del feed generado"
|
msgstr "URL del feed generado"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr "Ir a {0}"
|
msgstr "Ir a {0}"
|
||||||
@@ -441,13 +441,13 @@ msgstr "Importar"
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "En la vista ampliada, al desplazarse por las entradas marcarlas como leídas"
|
msgstr "En la vista ampliada, al desplazarse por las entradas marcarlas como leídas"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Mantener sin leer"
|
msgstr "Mantener sin leer"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Atajos de teclado"
|
msgstr "Atajos de teclado"
|
||||||
|
|
||||||
@@ -471,9 +471,9 @@ msgstr "Último mensaje de actualización"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr "Claro"
|
msgstr "Claro"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "Enlace"
|
msgstr "Enlace"
|
||||||
|
|
||||||
@@ -493,9 +493,9 @@ msgstr "Cargando suscripciones..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "Cargando etiquetas..."
|
msgstr "Cargando etiquetas..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Iniciar sesión"
|
msgstr "Iniciar sesión"
|
||||||
|
|
||||||
@@ -507,8 +507,8 @@ msgstr "Cerrar sesión"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr "Pulsación larga"
|
msgstr "Pulsación larga"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Administrar usuarios"
|
msgstr "Administrar usuarios"
|
||||||
|
|
||||||
@@ -516,18 +516,18 @@ msgstr "Administrar usuarios"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "Marcar todo como leído"
|
msgstr "Marcar todo como leído"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "Marcar todas las entradas como leídas"
|
msgstr "Marcar todas las entradas como leídas"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Marcar como leído"
|
msgstr "Marcar como leído"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "Marcar como leído hasta aquí"
|
msgstr "Marcar como leído hasta aquí"
|
||||||
|
|
||||||
@@ -547,15 +547,15 @@ msgstr "Mover la página hacia abajo"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "Mover la página hacia arriba"
|
msgstr "Mover la página hacia arriba"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr "N/D"
|
msgstr "N/D"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nombre"
|
msgstr "Nombre"
|
||||||
|
|
||||||
@@ -576,8 +576,8 @@ msgstr "Nueva contraseña"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Las más recientes primero"
|
msgstr "Las más recientes primero"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Siguiente"
|
msgstr "Siguiente"
|
||||||
|
|
||||||
@@ -695,11 +695,11 @@ msgstr "Padre"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "Categoría principal"
|
msgstr "Categoría principal"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Contraseña"
|
msgstr "Contraseña"
|
||||||
|
|
||||||
@@ -711,8 +711,8 @@ msgstr "Recuperación de contraseña"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Las contraseñas no coinciden"
|
msgstr "Las contraseñas no coinciden"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Posición"
|
msgstr "Posición"
|
||||||
|
|
||||||
@@ -728,8 +728,8 @@ msgstr "Perfil"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Recuperar contraseña"
|
msgstr "Recuperar contraseña"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Actualizar"
|
msgstr "Actualizar"
|
||||||
|
|
||||||
@@ -746,11 +746,11 @@ msgstr "API REST"
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr "Clic derecho"
|
msgstr "Clic derecho"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Guardar"
|
msgstr "Guardar"
|
||||||
|
|
||||||
@@ -766,10 +766,10 @@ msgstr "Desplazarse suavemente al navegar entre entradas"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr "Desplazarse"
|
msgstr "Desplazarse"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Buscar"
|
msgstr "Buscar"
|
||||||
|
|
||||||
@@ -777,6 +777,14 @@ msgstr "Buscar"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "La búsqueda requiere al menos 3 caracteres"
|
msgstr "La búsqueda requiere al menos 3 caracteres"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "Establecer el foco en la siguiente entrada sin abrirla"
|
msgstr "Establecer el foco en la siguiente entrada sin abrirla"
|
||||||
@@ -851,9 +859,9 @@ msgstr "Mostrar recuento de no leídos en la pestaña favicon"
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr "Mostrar recuento de no leídos en el título de la pestaña"
|
msgstr "Mostrar recuento de no leídos en el título de la pestaña"
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "Registrarse"
|
msgstr "Registrarse"
|
||||||
|
|
||||||
@@ -866,20 +874,20 @@ msgstr "Algo malo acaba de pasar..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Espacio"
|
msgstr "Espacio"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "Estrella"
|
msgstr "Estrella"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "Destacado"
|
msgstr "Destacado"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "Suscribirse"
|
msgstr "Suscribirse"
|
||||||
|
|
||||||
@@ -952,8 +960,8 @@ msgstr "¡Prueba la demostración!"
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "No leído"
|
msgstr "No leído"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "Desmarcar"
|
msgstr "Desmarcar"
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr ""
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>به یک حساب نیاز دارید؟</0><1>ثبت نام کنید!</1>"
|
msgstr "<0>به یک حساب نیاز دارید؟</0><1>ثبت نام کنید!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "در مورد"
|
msgstr "در مورد"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "اضافه کردن دسته"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "افزودن کاربر"
|
msgstr "افزودن کاربر"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "مدیر"
|
msgstr "مدیر"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "همه"
|
msgstr "همه"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr ""
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "لغو"
|
msgstr "لغو"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "مقوله"
|
msgstr "مقوله"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr ""
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "فشرده"
|
msgstr "فشرده"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "تأیید کنید"
|
msgstr "تأیید کنید"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr "توصیف"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "نمایش"
|
msgstr "نمایش"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "دانلود"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "پیوند را به نوار نشانک بکشید"
|
msgstr "پیوند را به نوار نشانک بکشید"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "ایمیل"
|
msgstr "ایمیل"
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "آدرس ایمیل"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "ویرایش کاربر"
|
msgstr "ویرایش کاربر"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "فعال"
|
msgstr "فعال"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "گسترش یافت"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "اشتراک ها و دسته های خود را به عنوان یک فایل OPML صادر کنید که می تواند در سایر خدمات خواندن فید وارد شود"
|
msgstr "اشتراک ها و دسته های خود را به عنوان یک فایل OPML صادر کنید که می تواند در سایر خدمات خواندن فید وارد شود"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr ""
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "نام فید"
|
msgstr "نام فید"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "URL فید"
|
msgstr "URL فید"
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr ""
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "رمز عبور را فراموش کرده اید؟"
|
msgstr "رمز عبور را فراموش کرده اید؟"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "ابتدا یک کلید API در نمایه خود ایجاد کنید."
|
msgstr "ابتدا یک کلید API در نمایه خود ایجاد کنید."
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "ابتدا یک کلید API در نمایه خود ایجاد کنید.
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "کلید API جدید ایجاد کنید"
|
msgstr "کلید API جدید ایجاد کنید"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "آدرس اینترنتی فید تولید شده"
|
msgstr "آدرس اینترنتی فید تولید شده"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -440,13 +440,13 @@ msgstr "واردات"
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "در نمای بازشده، پیمایش در ورودیها، آنها را به عنوان خوانده شده علامتگذاری میکند"
|
msgstr "در نمای بازشده، پیمایش در ورودیها، آنها را به عنوان خوانده شده علامتگذاری میکند"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "خوانده نشده نگه دارید"
|
msgstr "خوانده نشده نگه دارید"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "میانبرهای صفحه کلید"
|
msgstr "میانبرهای صفحه کلید"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "آخرین پیام تازه کردن"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "پیوند"
|
msgstr "پیوند"
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "بارگیری اشتراک ها..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "بارگیری برچسب ها..."
|
msgstr "بارگیری برچسب ها..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "وارد شوید"
|
msgstr "وارد شوید"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "خروج"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "کاربران را مدیریت کنید"
|
msgstr "کاربران را مدیریت کنید"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "کاربران را مدیریت کنید"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "همه را به عنوان خوانده شده علامت گذاری کنید"
|
msgstr "همه را به عنوان خوانده شده علامت گذاری کنید"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "همه ورودی ها را به عنوان خوانده شده علامت گذاری کنید"
|
msgstr "همه ورودی ها را به عنوان خوانده شده علامت گذاری کنید"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "علامت گذاری به عنوان خوانده شده"
|
msgstr "علامت گذاری به عنوان خوانده شده"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "تا اینجا به عنوان خوانده شده علامت بزنید"
|
msgstr "تا اینجا به عنوان خوانده شده علامت بزنید"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "صفحه را به پایین ببرید"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "صفحه را به بالا ببرید"
|
msgstr "صفحه را به بالا ببرید"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "نام"
|
msgstr "نام"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "رمز عبور جدید"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "ابتدا جدیدترین"
|
msgstr "ابتدا جدیدترین"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "بعد"
|
msgstr "بعد"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "پدر و مادر"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "دسته والد"
|
msgstr "دسته والد"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "رمز عبور"
|
msgstr "رمز عبور"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "بازیابی رمز عبور"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "گذرواژه ها مطابقت ندارند"
|
msgstr "گذرواژه ها مطابقت ندارند"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "موقعیت"
|
msgstr "موقعیت"
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "نمایه"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "بازیابی رمز عبور"
|
msgstr "بازیابی رمز عبور"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "تازه کردن"
|
msgstr "تازه کردن"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr ""
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "ذخیره کنید"
|
msgstr "ذخیره کنید"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "هنگام پیمایش بین ورودیها به آرامی حرک
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "جستجو"
|
msgstr "جستجو"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "جستجو"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "جستجو به حداقل 3 کاراکتر نیاز دارد"
|
msgstr "جستجو به حداقل 3 کاراکتر نیاز دارد"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "فوکوس را روی ورودی بعدی بدون باز کردن آن تنظیم کنید"
|
msgstr "فوکوس را روی ورودی بعدی بدون باز کردن آن تنظیم کنید"
|
||||||
@@ -850,9 +858,9 @@ msgstr ""
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "ثبت نام کنید"
|
msgstr "ثبت نام کنید"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "اتفاق بدی افتاد..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "فضا"
|
msgstr "فضا"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "ستاره"
|
msgstr "ستاره"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "ستاره دار"
|
msgstr "ستاره دار"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "مشترک شوید"
|
msgstr "مشترک شوید"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr ""
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "خوانده نشده"
|
msgstr "خوانده نشده"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr ""
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>Tarvitsetko tilin?</0><1>Rekisteröidy!</1>"
|
msgstr "<0>Tarvitsetko tilin?</0><1>Rekisteröidy!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Noin"
|
msgstr "Noin"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "Lisää luokka"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Lisää käyttäjä"
|
msgstr "Lisää käyttäjä"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Järjestelmänvalvoja"
|
msgstr "Järjestelmänvalvoja"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Kaikki"
|
msgstr "Kaikki"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr ""
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Peruuta"
|
msgstr "Peruuta"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Luokka"
|
msgstr "Luokka"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr ""
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Kompakti"
|
msgstr "Kompakti"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Vahvista"
|
msgstr "Vahvista"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr ""
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Näyttö"
|
msgstr "Näyttö"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "Lataa"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "Vedä linkki kirjanmerkkipalkkiin"
|
msgstr "Vedä linkki kirjanmerkkipalkkiin"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "Sähköposti"
|
msgstr "Sähköposti"
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "Sähköpostiosoite"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Muokkaa käyttäjää"
|
msgstr "Muokkaa käyttäjää"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Käytössä"
|
msgstr "Käytössä"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "Laajennettu"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "Vie tilauksesi ja luokat OPML-tiedostona, joka voidaan tuoda muihin syötteiden lukupalveluihin"
|
msgstr "Vie tilauksesi ja luokat OPML-tiedostona, joka voidaan tuoda muihin syötteiden lukupalveluihin"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr ""
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "Syötteen nimi"
|
msgstr "Syötteen nimi"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "Syötteen URL-osoite"
|
msgstr "Syötteen URL-osoite"
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr ""
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Unohditko salasanan?"
|
msgstr "Unohditko salasanan?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "Luo ensin API-avain profiiliisi."
|
msgstr "Luo ensin API-avain profiiliisi."
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "Luo ensin API-avain profiiliisi."
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "Luo uusi API-avain"
|
msgstr "Luo uusi API-avain"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "Luotu syötteen URL-osoite"
|
msgstr "Luotu syötteen URL-osoite"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -440,13 +440,13 @@ msgstr "Tuo"
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "Merkitse ne luetuiksi laajennetussa näkymässä vierittämällä merkintöjä"
|
msgstr "Merkitse ne luetuiksi laajennetussa näkymässä vierittämällä merkintöjä"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Pidä lukematta"
|
msgstr "Pidä lukematta"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Pikanäppäimet"
|
msgstr "Pikanäppäimet"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "Viimeinen päivitysviesti"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "Linkki"
|
msgstr "Linkki"
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "Ladataan tilauksia..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "Ladataan tunnisteita..."
|
msgstr "Ladataan tunnisteita..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Kirjaudu sisään"
|
msgstr "Kirjaudu sisään"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "Uloskirjautuminen"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Hallitse käyttäjiä"
|
msgstr "Hallitse käyttäjiä"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "Hallitse käyttäjiä"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "Merkitse kaikki luetuiksi"
|
msgstr "Merkitse kaikki luetuiksi"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "Merkitse kaikki merkinnät luetuiksi"
|
msgstr "Merkitse kaikki merkinnät luetuiksi"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Merkitse luetuksi"
|
msgstr "Merkitse luetuksi"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "Merkitse luetuksi tähän asti"
|
msgstr "Merkitse luetuksi tähän asti"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "Siirrä sivua alaspäin"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "Siirrä sivua ylöspäin"
|
msgstr "Siirrä sivua ylöspäin"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nimi"
|
msgstr "Nimi"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "Uusi salasana"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Uusin ensin"
|
msgstr "Uusin ensin"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Seuraava"
|
msgstr "Seuraava"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "Vanhempi"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "Pääluokka"
|
msgstr "Pääluokka"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Salasana"
|
msgstr "Salasana"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "Salasanan palautus"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Salasanat eivät täsmää"
|
msgstr "Salasanat eivät täsmää"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Sijainti"
|
msgstr "Sijainti"
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "Profiili"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Palauta salasana"
|
msgstr "Palauta salasana"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Päivitä"
|
msgstr "Päivitä"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr ""
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Tallenna"
|
msgstr "Tallenna"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "Selaa sujuvasti navigoidessasi merkintöjen välillä"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Etsi"
|
msgstr "Etsi"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "Etsi"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "Haku vaatii vähintään 3 merkkiä"
|
msgstr "Haku vaatii vähintään 3 merkkiä"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "Keskitä seuraavaan merkintään avaamatta sitä"
|
msgstr "Keskitä seuraavaan merkintään avaamatta sitä"
|
||||||
@@ -850,9 +858,9 @@ msgstr ""
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "Rekisteröidy"
|
msgstr "Rekisteröidy"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "Jotain pahaa tapahtui juuri..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Avaruus"
|
msgstr "Avaruus"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "Tähti"
|
msgstr "Tähti"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "Tähdellä merkitty"
|
msgstr "Tähdellä merkitty"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "Tilaa"
|
msgstr "Tilaa"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr ""
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Lukematon"
|
msgstr "Lukematon"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "Poista tähti"
|
msgstr "Poista tähti"
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr "<0>Salut,</0><1>Je m'appelle Jérémie, je suis belge, et je développe
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>Besoin d'un compte ?</0><1>Enregistrez-vous !</1>"
|
msgstr "<0>Besoin d'un compte ?</0><1>Enregistrez-vous !</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "À propos"
|
msgstr "À propos"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "Ajouter une catégorie"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Ajouter un utilisateur"
|
msgstr "Ajouter un utilisateur"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Administrateur"
|
msgstr "Administrateur"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Tout"
|
msgstr "Tout"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr "Extension navigateur"
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr "Onglet navigateur"
|
msgstr "Onglet navigateur"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Annuler"
|
msgstr "Annuler"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Catégorie"
|
msgstr "Catégorie"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr "CommaFeed version {version} ({revision})."
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Compact"
|
msgstr "Compact"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Confirmer"
|
msgstr "Confirmer"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr "Descendant"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr "Vue détaillée"
|
msgstr "Vue détaillée"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Affichage"
|
msgstr "Affichage"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr "Faire un don"
|
msgstr "Faire un don"
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "Télécharger"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "Déplacez le lien vers la barre de favoris"
|
msgstr "Déplacez le lien vers la barre de favoris"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "E-mail"
|
msgstr "E-mail"
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "Adresse e-mail"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Modifier un utilisateur"
|
msgstr "Modifier un utilisateur"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Actif"
|
msgstr "Actif"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "Vue étendue"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "Exporter vos abonnements et catégories en tant que fichier OPML qui peut être importé dans d'autres services de lecture de flux"
|
msgstr "Exporter vos abonnements et catégories en tant que fichier OPML qui peut être importé dans d'autres services de lecture de flux"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr "Options de l'extension"
|
msgstr "Options de l'extension"
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr "Options de l'extension"
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "Nom du flux"
|
msgstr "Nom du flux"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "URL du flux"
|
msgstr "URL du flux"
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr "La récupération forcée des flux n'est pas encore disponible."
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Mot de passe oublié ?"
|
msgstr "Mot de passe oublié ?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "Générez d'abord une clé API dans votre profil."
|
msgstr "Générez d'abord une clé API dans votre profil."
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "Générez d'abord une clé API dans votre profil."
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "Générer une nouvelle clé API"
|
msgstr "Générer une nouvelle clé API"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "URL du flux généré"
|
msgstr "URL du flux généré"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr "Aller à {0}"
|
msgstr "Aller à {0}"
|
||||||
@@ -440,13 +440,13 @@ msgstr "Importer"
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "En mode de lecture étendu, marquer les éléments comme lus lorsque la fenêtre descend."
|
msgstr "En mode de lecture étendu, marquer les éléments comme lus lorsque la fenêtre descend."
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Garder non lu"
|
msgstr "Garder non lu"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Raccourcis clavier"
|
msgstr "Raccourcis clavier"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "Dernier message de mise à jour"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr "Clair"
|
msgstr "Clair"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "Lien"
|
msgstr "Lien"
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "Chargement des abonnements..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "Chargement des marqueurs..."
|
msgstr "Chargement des marqueurs..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Connexion"
|
msgstr "Connexion"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "Déconnexion"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr "Appui long"
|
msgstr "Appui long"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Gestion des utilisateurs"
|
msgstr "Gestion des utilisateurs"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "Gestion des utilisateurs"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "Tout marquer comme lu"
|
msgstr "Tout marquer comme lu"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "Marquer toutes les entrées comme lues"
|
msgstr "Marquer toutes les entrées comme lues"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Marquer comme lu"
|
msgstr "Marquer comme lu"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "Marquer comme lu jusqu'ici"
|
msgstr "Marquer comme lu jusqu'ici"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "Faites défiler la page vers le bas"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "Faites défiler la page vers le haut"
|
msgstr "Faites défiler la page vers le haut"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr "N/A"
|
msgstr "N/A"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nom"
|
msgstr "Nom"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "Nouveau mot de passe"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Plus récent en premier"
|
msgstr "Plus récent en premier"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Suivant"
|
msgstr "Suivant"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "Parent"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "Catégorie parente"
|
msgstr "Catégorie parente"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Mot de passe"
|
msgstr "Mot de passe"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "Récupération de mot de passe"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Les mots de passe ne correspondent pas"
|
msgstr "Les mots de passe ne correspondent pas"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Position"
|
msgstr "Position"
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "Profil"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Récupérer le mot de passe"
|
msgstr "Récupérer le mot de passe"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Rafraîchir"
|
msgstr "Rafraîchir"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr "API REST"
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr "Clic droit"
|
msgstr "Clic droit"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Enregistrer"
|
msgstr "Enregistrer"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "Défilement animé lors de la navigation entre les entrées"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr "Défilement"
|
msgstr "Défilement"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Rechercher"
|
msgstr "Rechercher"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "Rechercher"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "La recherche requiert au moins 3 caractères"
|
msgstr "La recherche requiert au moins 3 caractères"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "Sélectionner l'article suivant sans l'ouvrir"
|
msgstr "Sélectionner l'article suivant sans l'ouvrir"
|
||||||
@@ -850,9 +858,9 @@ msgstr "Afficher le nombre d'entrées non lues dans la favicône de l'onglet"
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr "Afficher le nombre d'entrées non lues dans le titre de l'onglet"
|
msgstr "Afficher le nombre d'entrées non lues dans le titre de l'onglet"
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "Créer un compte"
|
msgstr "Créer un compte"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "Quelque chose s'est mal passé..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Espace"
|
msgstr "Espace"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "Ajouter aux favoris"
|
msgstr "Ajouter aux favoris"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "Favoris"
|
msgstr "Favoris"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "S'abonner"
|
msgstr "S'abonner"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr "Essayez la version de démonstration !"
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Non lu"
|
msgstr "Non lu"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "Retirer des favoris"
|
msgstr "Retirer des favoris"
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr ""
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>Necesitas unha conta?</0><1>Rexístrate!</1>"
|
msgstr "<0>Necesitas unha conta?</0><1>Rexístrate!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Sobre"
|
msgstr "Sobre"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "Engadir categoría"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Engadir usuario"
|
msgstr "Engadir usuario"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Administración"
|
msgstr "Administración"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Todos"
|
msgstr "Todos"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr ""
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Cancelar"
|
msgstr "Cancelar"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Categoría"
|
msgstr "Categoría"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr ""
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Compacto"
|
msgstr "Compacto"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Confirmar"
|
msgstr "Confirmar"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr ""
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Exhibición"
|
msgstr "Exhibición"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "Descargar"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "Arrastra a ligazón á barra de marcadores"
|
msgstr "Arrastra a ligazón á barra de marcadores"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "Correo electrónico"
|
msgstr "Correo electrónico"
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "Enderezo de correo electrónico"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Editar usuario"
|
msgstr "Editar usuario"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Activado"
|
msgstr "Activado"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "Ampliado"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "Exporta as túas subscricións e categorías como ficheiro OPML que se pode importar noutros servizos de lectura de feeds"
|
msgstr "Exporta as túas subscricións e categorías como ficheiro OPML que se pode importar noutros servizos de lectura de feeds"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr ""
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "Nome do feed"
|
msgstr "Nome do feed"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "URL da fonte"
|
msgstr "URL da fonte"
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr ""
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Esqueceches o contrasinal?"
|
msgstr "Esqueceches o contrasinal?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "Xera primeiro unha clave API no teu perfil."
|
msgstr "Xera primeiro unha clave API no teu perfil."
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "Xera primeiro unha clave API no teu perfil."
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "Xerar nova clave de API"
|
msgstr "Xerar nova clave de API"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "URL da fonte xerada"
|
msgstr "URL da fonte xerada"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -440,13 +440,13 @@ msgstr "Importación"
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "Na vista ampliada, ao desprazarse polas entradas márcaas como lidas"
|
msgstr "Na vista ampliada, ao desprazarse polas entradas márcaas como lidas"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Manter sen ler"
|
msgstr "Manter sen ler"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "atallos de teclado"
|
msgstr "atallos de teclado"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "Última mensaxe de actualización"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "Ligazón"
|
msgstr "Ligazón"
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "Cargando subscricións..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "Cargando etiquetas..."
|
msgstr "Cargando etiquetas..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Iniciar sesión"
|
msgstr "Iniciar sesión"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "Pechar sesión"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Xestionar usuarios"
|
msgstr "Xestionar usuarios"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "Xestionar usuarios"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "Marcar todo como lido"
|
msgstr "Marcar todo como lido"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "Marcar todas as entradas como lidas"
|
msgstr "Marcar todas as entradas como lidas"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Marcar como lido"
|
msgstr "Marcar como lido"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "Marcar como lido ata aquí"
|
msgstr "Marcar como lido ata aquí"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "Move a páxina cara abaixo"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "Move a páxina cara arriba"
|
msgstr "Move a páxina cara arriba"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nome"
|
msgstr "Nome"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "novo contrasinal"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "o máis novo primeiro"
|
msgstr "o máis novo primeiro"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Seguinte"
|
msgstr "Seguinte"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "Pai"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "Categoría de pais"
|
msgstr "Categoría de pais"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Contrasinal"
|
msgstr "Contrasinal"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "Recuperación de contrasinal"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Os contrasinais non coinciden"
|
msgstr "Os contrasinais non coinciden"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Posición"
|
msgstr "Posición"
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "Perfil"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Recuperar o contrasinal"
|
msgstr "Recuperar o contrasinal"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Actualizar"
|
msgstr "Actualizar"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr "API REST"
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Gardar"
|
msgstr "Gardar"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "Desprácese suavemente ao navegar entre as entradas"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Busca"
|
msgstr "Busca"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "Busca"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "A busca require polo menos 3 caracteres"
|
msgstr "A busca require polo menos 3 caracteres"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "Establece o foco na seguinte entrada sen abrila"
|
msgstr "Establece o foco na seguinte entrada sen abrila"
|
||||||
@@ -850,9 +858,9 @@ msgstr ""
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "Rexístrese"
|
msgstr "Rexístrese"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "Algo malo pasou..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Espazo"
|
msgstr "Espazo"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "estrela"
|
msgstr "estrela"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "estrela"
|
msgstr "estrela"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "Subscríbete"
|
msgstr "Subscríbete"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr ""
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Sen ler"
|
msgstr "Sen ler"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "Desestrela"
|
msgstr "Desestrela"
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr ""
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>Fiókra van szüksége?</0><1>Regisztráljon!</1>"
|
msgstr "<0>Fiókra van szüksége?</0><1>Regisztráljon!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Kb"
|
msgstr "Kb"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "Kategória hozzáadása"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Felhasználó hozzáadása"
|
msgstr "Felhasználó hozzáadása"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Mind"
|
msgstr "Mind"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr ""
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Mégse"
|
msgstr "Mégse"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Kategória"
|
msgstr "Kategória"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr ""
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Kompakt"
|
msgstr "Kompakt"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Erősítse meg"
|
msgstr "Erősítse meg"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr ""
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Kijelző"
|
msgstr "Kijelző"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "Letöltés"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "Húzza a hivatkozást a könyvjelzősávra"
|
msgstr "Húzza a hivatkozást a könyvjelzősávra"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "E-mail cím"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Felhasználó szerkesztése"
|
msgstr "Felhasználó szerkesztése"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Engedélyezve"
|
msgstr "Engedélyezve"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "Kiterjesztve"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "Exportálja előfizetéseit és kategóriáit OPML-fájlként, amely importálható más feedolvasó szolgáltatásokba"
|
msgstr "Exportálja előfizetéseit és kategóriáit OPML-fájlként, amely importálható más feedolvasó szolgáltatásokba"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr ""
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "Hírcsatorna neve"
|
msgstr "Hírcsatorna neve"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr ""
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Elfelejtette a jelszavát?"
|
msgstr "Elfelejtette a jelszavát?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "Először generáljon API-kulcsot a profiljában."
|
msgstr "Először generáljon API-kulcsot a profiljában."
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "Először generáljon API-kulcsot a profiljában."
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "Új API-kulcs létrehozása"
|
msgstr "Új API-kulcs létrehozása"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "Hírcsatorna generált URL-je"
|
msgstr "Hírcsatorna generált URL-je"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -440,13 +440,13 @@ msgstr "Importálás"
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "Kibontott nézetben a bejegyzések görgetése olvasottként jelöli meg őket"
|
msgstr "Kibontott nézetben a bejegyzések görgetése olvasottként jelöli meg őket"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Olvasatlan marad"
|
msgstr "Olvasatlan marad"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Billentyűparancsok"
|
msgstr "Billentyűparancsok"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "Utolsó frissítési üzenet"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "Előfizetések betöltése..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "Címkék betöltése..."
|
msgstr "Címkék betöltése..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Jelentkezzen be"
|
msgstr "Jelentkezzen be"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "Kijelentkezés"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Felhasználók kezelése"
|
msgstr "Felhasználók kezelése"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "Felhasználók kezelése"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "Minden megjelölése olvasottként"
|
msgstr "Minden megjelölése olvasottként"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "Minden bejegyzés megjelölése olvasottként"
|
msgstr "Minden bejegyzés megjelölése olvasottként"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Megjelölés olvasottként"
|
msgstr "Megjelölés olvasottként"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "Megjelölés idáig olvasottként"
|
msgstr "Megjelölés idáig olvasottként"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "Mozgassa le az oldalt"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "Mozgassa felfelé az oldalt"
|
msgstr "Mozgassa felfelé az oldalt"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Név"
|
msgstr "Név"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "Új jelszó"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "A legújabbak először"
|
msgstr "A legújabbak először"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Következő"
|
msgstr "Következő"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "Szülő"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "Szülő kategória"
|
msgstr "Szülő kategória"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Jelszó"
|
msgstr "Jelszó"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "Jelszó helyreállítás"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "A jelszavak nem egyeznek"
|
msgstr "A jelszavak nem egyeznek"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Pozíció"
|
msgstr "Pozíció"
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "Profil"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Jelszó helyreállítása"
|
msgstr "Jelszó helyreállítása"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Frissítés"
|
msgstr "Frissítés"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr ""
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Mentés"
|
msgstr "Mentés"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "Sima görgetés, amikor a bejegyzések között navigál"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Keresés"
|
msgstr "Keresés"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "Keresés"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "A kereséshez legalább 3 karakter szükséges"
|
msgstr "A kereséshez legalább 3 karakter szükséges"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "Állítsa a fókuszt a következő bejegyzésre anélkül, hogy megnyitná azt"
|
msgstr "Állítsa a fókuszt a következő bejegyzésre anélkül, hogy megnyitná azt"
|
||||||
@@ -850,9 +858,9 @@ msgstr ""
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "Regisztráljon"
|
msgstr "Regisztráljon"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "Valami rossz történt..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "Csillag"
|
msgstr "Csillag"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "Csillaggal megjelölve"
|
msgstr "Csillaggal megjelölve"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "Feliratkozás"
|
msgstr "Feliratkozás"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr ""
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Olvasatlan"
|
msgstr "Olvasatlan"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr ""
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>Butuh akun?</0><1>Daftar!</1>"
|
msgstr "<0>Butuh akun?</0><1>Daftar!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Tentang"
|
msgstr "Tentang"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "Tambahkan kategori"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Tambahkan pengguna"
|
msgstr "Tambahkan pengguna"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Semua"
|
msgstr "Semua"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr ""
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Batal"
|
msgstr "Batal"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Kategori"
|
msgstr "Kategori"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr ""
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Ringkas"
|
msgstr "Ringkas"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Konfirmasi"
|
msgstr "Konfirmasi"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr ""
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Tampilan"
|
msgstr "Tampilan"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "Unduh"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "Seret tautan ke bilah bookmark"
|
msgstr "Seret tautan ke bilah bookmark"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "Email"
|
msgstr "Email"
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "Alamat email"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Edit pengguna"
|
msgstr "Edit pengguna"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Diaktifkan"
|
msgstr "Diaktifkan"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "Diperluas"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "Ekspor langganan dan kategori Anda sebagai file OPML yang dapat diimpor ke layanan membaca feed lainnya"
|
msgstr "Ekspor langganan dan kategori Anda sebagai file OPML yang dapat diimpor ke layanan membaca feed lainnya"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr ""
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "Nama umpan"
|
msgstr "Nama umpan"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "URL Umpan"
|
msgstr "URL Umpan"
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr ""
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Lupa kata sandi?"
|
msgstr "Lupa kata sandi?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "Buat kunci API di profil Anda terlebih dahulu."
|
msgstr "Buat kunci API di profil Anda terlebih dahulu."
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "Buat kunci API di profil Anda terlebih dahulu."
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "Buat kunci API baru"
|
msgstr "Buat kunci API baru"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "Url umpan yang dihasilkan"
|
msgstr "Url umpan yang dihasilkan"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -440,13 +440,13 @@ msgstr "Impor"
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "Dalam tampilan yang diperluas, menggulir entri menandainya sebagai telah dibaca"
|
msgstr "Dalam tampilan yang diperluas, menggulir entri menandainya sebagai telah dibaca"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Tetap belum dibaca"
|
msgstr "Tetap belum dibaca"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Pintasan keyboard"
|
msgstr "Pintasan keyboard"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "Pesan penyegaran terakhir"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "Tautan"
|
msgstr "Tautan"
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "Memuat langganan..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "Memuat tag..."
|
msgstr "Memuat tag..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Masuk"
|
msgstr "Masuk"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "Keluar"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Kelola pengguna"
|
msgstr "Kelola pengguna"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "Kelola pengguna"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "Tandai semua sebagai telah dibaca"
|
msgstr "Tandai semua sebagai telah dibaca"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "Tandai semua entri sebagai telah dibaca"
|
msgstr "Tandai semua entri sebagai telah dibaca"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Tandai sebagai telah dibaca"
|
msgstr "Tandai sebagai telah dibaca"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "Tandai sebagai telah dibaca sampai di sini"
|
msgstr "Tandai sebagai telah dibaca sampai di sini"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "Pindahkan halaman ke bawah"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "Pindahkan halaman ke atas"
|
msgstr "Pindahkan halaman ke atas"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr "T/A"
|
msgstr "T/A"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nama"
|
msgstr "Nama"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "Kata sandi baru"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Terbaru dulu"
|
msgstr "Terbaru dulu"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Selanjutnya"
|
msgstr "Selanjutnya"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "Orang tua"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "Kategori Induk"
|
msgstr "Kategori Induk"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Kata Sandi"
|
msgstr "Kata Sandi"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "Pemulihan Kata Sandi"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Kata sandi tidak cocok"
|
msgstr "Kata sandi tidak cocok"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Posisi"
|
msgstr "Posisi"
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "Profil"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Pulihkan kata sandi"
|
msgstr "Pulihkan kata sandi"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Segarkan"
|
msgstr "Segarkan"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr ""
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Simpan"
|
msgstr "Simpan"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "Gulir dengan lancar saat menavigasi antar entri"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Pencarian"
|
msgstr "Pencarian"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "Pencarian"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "Pencarian membutuhkan setidaknya 3 karakter"
|
msgstr "Pencarian membutuhkan setidaknya 3 karakter"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "Tetapkan fokus pada entri berikutnya tanpa membukanya"
|
msgstr "Tetapkan fokus pada entri berikutnya tanpa membukanya"
|
||||||
@@ -850,9 +858,9 @@ msgstr ""
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "Daftar"
|
msgstr "Daftar"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "Sesuatu yang buruk baru saja terjadi..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Luar Angkasa"
|
msgstr "Luar Angkasa"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "Bintang"
|
msgstr "Bintang"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "Berbintang"
|
msgstr "Berbintang"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "Berlangganan"
|
msgstr "Berlangganan"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr ""
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Belum Dibaca"
|
msgstr "Belum Dibaca"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "Hapus bintang"
|
msgstr "Hapus bintang"
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr ""
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>Hai bisogno di un account?</0><1>Registrati!</1>"
|
msgstr "<0>Hai bisogno di un account?</0><1>Registrati!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Circa"
|
msgstr "Circa"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "Aggiungi categoria"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Aggiungi utente"
|
msgstr "Aggiungi utente"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Ammin"
|
msgstr "Ammin"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Tutto"
|
msgstr "Tutto"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr ""
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Annulla"
|
msgstr "Annulla"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Categoria"
|
msgstr "Categoria"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr ""
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Compatto"
|
msgstr "Compatto"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Conferma"
|
msgstr "Conferma"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr ""
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Visualizzazione"
|
msgstr "Visualizzazione"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "Scarica"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "Trascina il collegamento sulla barra dei preferiti"
|
msgstr "Trascina il collegamento sulla barra dei preferiti"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "Indirizzo e-mail"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Modifica utente"
|
msgstr "Modifica utente"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Abilitato"
|
msgstr "Abilitato"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "Espanso"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "Esporta le tue iscrizioni e categorie come file OPML che può essere importato in altri servizi di lettura feed"
|
msgstr "Esporta le tue iscrizioni e categorie come file OPML che può essere importato in altri servizi di lettura feed"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr ""
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "Nome del feed"
|
msgstr "Nome del feed"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "URL feed"
|
msgstr "URL feed"
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr ""
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Password dimenticata?"
|
msgstr "Password dimenticata?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "Genera prima una chiave API nel tuo profilo."
|
msgstr "Genera prima una chiave API nel tuo profilo."
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "Genera prima una chiave API nel tuo profilo."
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "Genera nuova chiave API"
|
msgstr "Genera nuova chiave API"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "URL feed generato"
|
msgstr "URL feed generato"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -440,13 +440,13 @@ msgstr "Importa"
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "Nella vista espansa, scorrendo le voci contrassegnale come lette"
|
msgstr "Nella vista espansa, scorrendo le voci contrassegnale come lette"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Mantieni non letto"
|
msgstr "Mantieni non letto"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Scorciatoie da tastiera"
|
msgstr "Scorciatoie da tastiera"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "Ultimo messaggio di aggiornamento"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "Collegamento"
|
msgstr "Collegamento"
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "Caricamento abbonamenti..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "Caricamento tag..."
|
msgstr "Caricamento tag..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Accedi"
|
msgstr "Accedi"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "Disconnessione"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Gestisci utenti"
|
msgstr "Gestisci utenti"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "Gestisci utenti"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "Contrassegna tutto come letto"
|
msgstr "Contrassegna tutto come letto"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "Contrassegna tutte le voci come lette"
|
msgstr "Contrassegna tutte le voci come lette"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Contrassegna come letto"
|
msgstr "Contrassegna come letto"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "Contrassegna come letto fino a qui"
|
msgstr "Contrassegna come letto fino a qui"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "Sposta la pagina in basso"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "Sposta la pagina in alto"
|
msgstr "Sposta la pagina in alto"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nome"
|
msgstr "Nome"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "Nuova password"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Il più recente prima"
|
msgstr "Il più recente prima"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Avanti"
|
msgstr "Avanti"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "Genitore"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "Categoria padre"
|
msgstr "Categoria padre"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "Recupero password"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Le password non corrispondono"
|
msgstr "Le password non corrispondono"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Posizione"
|
msgstr "Posizione"
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "Profilo"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Recupera password"
|
msgstr "Recupera password"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Aggiorna"
|
msgstr "Aggiorna"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr "API REST"
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Salva"
|
msgstr "Salva"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "Scorrere senza problemi durante la navigazione tra le voci"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Cerca"
|
msgstr "Cerca"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "Cerca"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "La ricerca richiede almeno 3 caratteri"
|
msgstr "La ricerca richiede almeno 3 caratteri"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "Imposta il focus sulla voce successiva senza aprirla"
|
msgstr "Imposta il focus sulla voce successiva senza aprirla"
|
||||||
@@ -850,9 +858,9 @@ msgstr ""
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "Iscriviti"
|
msgstr "Iscriviti"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "È appena successo qualcosa di brutto..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Spazio"
|
msgstr "Spazio"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "Stella"
|
msgstr "Stella"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "Speciali"
|
msgstr "Speciali"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "Iscriviti"
|
msgstr "Iscriviti"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr ""
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Non letto"
|
msgstr "Non letto"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "Elimina le stelle"
|
msgstr "Elimina le stelle"
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr "<0>こんにちは、</0><1>私はベルギーのジェレミーです
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>アカウントが必要ですか?</0><1>サインアップ!</1>"
|
msgstr "<0>アカウントが必要ですか?</0><1>サインアップ!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "About"
|
msgstr "About"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "カテゴリを追加"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "ユーザー追加"
|
msgstr "ユーザー追加"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "管理者"
|
msgstr "管理者"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "すべて"
|
msgstr "すべて"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr "ブラウザー拡張"
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr "ブラウザータブ"
|
msgstr "ブラウザータブ"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "キャンセル"
|
msgstr "キャンセル"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "カテゴリー"
|
msgstr "カテゴリー"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr "CommaFeed バージョン {version} ({revision})。"
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "コンパクト"
|
msgstr "コンパクト"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "確認"
|
msgstr "確認"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr "説明"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr "詳細"
|
msgstr "詳細"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "ディスプレイ"
|
msgstr "ディスプレイ"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr "寄付"
|
msgstr "寄付"
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "ダウンロード"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "リンクをブックマークバーにドラッグ"
|
msgstr "リンクをブックマークバーにドラッグ"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "メール"
|
msgstr "メール"
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "メールアドレス"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "ユーザーの編集"
|
msgstr "ユーザーの編集"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "有効"
|
msgstr "有効"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "拡張"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "サブスクリプションとカテゴリを、他のフィード読み取りサービスにインポートできる OPML ファイルとしてエクスポートします"
|
msgstr "サブスクリプションとカテゴリを、他のフィード読み取りサービスにインポートできる OPML ファイルとしてエクスポートします"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr "拡張機能オプション"
|
msgstr "拡張機能オプション"
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr "拡張機能オプション"
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "フィード名"
|
msgstr "フィード名"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "フィード URL"
|
msgstr "フィード URL"
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr "フィードの強制フェッチはまだ利用できません。"
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "パスワードをお忘れですか?"
|
msgstr "パスワードをお忘れですか?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "最初にプロファイルでAPIキーを生成します。"
|
msgstr "最初にプロファイルでAPIキーを生成します。"
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "最初にプロファイルでAPIキーを生成します。"
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "新しいAPIキーを生成する"
|
msgstr "新しいAPIキーを生成する"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "生成されたフィードURL"
|
msgstr "生成されたフィードURL"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr "{0} に移動"
|
msgstr "{0} に移動"
|
||||||
@@ -440,13 +440,13 @@ msgstr "インポート"
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "展開ビューでエントリーをスクロールすると、それらが既読としてマークされます"
|
msgstr "展開ビューでエントリーをスクロールすると、それらが既読としてマークされます"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "未読のままにする"
|
msgstr "未読のままにする"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "キーボードショートカット"
|
msgstr "キーボードショートカット"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "最終更新メッセージ"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr "ライト"
|
msgstr "ライト"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "リンク"
|
msgstr "リンク"
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "サブスクリプションを読み込んでいます..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "タグを読み込んでいます..."
|
msgstr "タグを読み込んでいます..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "ログイン"
|
msgstr "ログイン"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "ログアウト"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr "長押し"
|
msgstr "長押し"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "ユーザーの管理"
|
msgstr "ユーザーの管理"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "ユーザーの管理"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "すべて既読にする"
|
msgstr "すべて既読にする"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "すべてのエントリーを既読にする"
|
msgstr "すべてのエントリーを既読にする"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "既読にする"
|
msgstr "既読にする"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "ここまで既読にする"
|
msgstr "ここまで既読にする"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "ページを下に移動"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "ページを上に移動"
|
msgstr "ページを上に移動"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr "該当なし"
|
msgstr "該当なし"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "名前"
|
msgstr "名前"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "新しいパスワード"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "最新順"
|
msgstr "最新順"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "次へ"
|
msgstr "次へ"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "親"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "親カテゴリ"
|
msgstr "親カテゴリ"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "パスワード"
|
msgstr "パスワード"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "パスワード回復"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "パスワードが一致しません"
|
msgstr "パスワードが一致しません"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "位置"
|
msgstr "位置"
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "プロフィール"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "パスワードの回復"
|
msgstr "パスワードの回復"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "リフレッシュ"
|
msgstr "リフレッシュ"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr "REST API"
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr "右クリック"
|
msgstr "右クリック"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "保存"
|
msgstr "保存"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "エントリー間を移動するときにスムーズにスクロール
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr "スクロール"
|
msgstr "スクロール"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "検索"
|
msgstr "検索"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "検索"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "検索には少なくとも3文字が必要です"
|
msgstr "検索には少なくとも3文字が必要です"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "次のエントリーを開かずにフォーカスする"
|
msgstr "次のエントリーを開かずにフォーカスする"
|
||||||
@@ -850,9 +858,9 @@ msgstr "未読数をタブのアイコンに表示する"
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr "未読数をタブのタイトルに表示する"
|
msgstr "未読数をタブのタイトルに表示する"
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "サインアップ"
|
msgstr "サインアップ"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "何か悪いことが起きました..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Space"
|
msgstr "Space"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "スター"
|
msgstr "スター"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "スター付き"
|
msgstr "スター付き"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "購読する"
|
msgstr "購読する"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr "デモを試す!"
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "未読"
|
msgstr "未読"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "スターを外す"
|
msgstr "スターを外す"
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr ""
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>계정이 필요하십니까?</0><1>가입하세요!</1>"
|
msgstr "<0>계정이 필요하십니까?</0><1>가입하세요!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "정보"
|
msgstr "정보"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "카테고리 추가"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "사용자 추가"
|
msgstr "사용자 추가"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "관리자"
|
msgstr "관리자"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "전체"
|
msgstr "전체"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr ""
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "취소"
|
msgstr "취소"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "카테고리"
|
msgstr "카테고리"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr ""
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "컴팩트"
|
msgstr "컴팩트"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "확인"
|
msgstr "확인"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr "설명"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "디스플레이"
|
msgstr "디스플레이"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "다운로드"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "링크를 북마크바로 드래그"
|
msgstr "링크를 북마크바로 드래그"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "이메일"
|
msgstr "이메일"
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "이메일 주소"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "사용자 편집"
|
msgstr "사용자 편집"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "활성화"
|
msgstr "활성화"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "확장"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "구독 및 카테고리를 다른 피드 읽기 서비스에서 가져올 수 있는 OPML 파일로 내보내기"
|
msgstr "구독 및 카테고리를 다른 피드 읽기 서비스에서 가져올 수 있는 OPML 파일로 내보내기"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr ""
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "피드 이름"
|
msgstr "피드 이름"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "피드 URL"
|
msgstr "피드 URL"
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr ""
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "비밀번호를 잊으셨나요?"
|
msgstr "비밀번호를 잊으셨나요?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "먼저 프로필에서 API 키를 생성하십시오."
|
msgstr "먼저 프로필에서 API 키를 생성하십시오."
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "먼저 프로필에서 API 키를 생성하십시오."
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "새 API 키 생성"
|
msgstr "새 API 키 생성"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "생성된 피드 URL"
|
msgstr "생성된 피드 URL"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -440,13 +440,13 @@ msgstr "가져오기"
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "확장 보기에서 항목을 스크롤하면 읽은 것으로 표시됩니다."
|
msgstr "확장 보기에서 항목을 스크롤하면 읽은 것으로 표시됩니다."
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "읽지 않은 상태로 유지"
|
msgstr "읽지 않은 상태로 유지"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "키보드 단축키"
|
msgstr "키보드 단축키"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "마지막 새로고침 메시지"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "링크"
|
msgstr "링크"
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "구독 로드 중..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "태그 로드 중..."
|
msgstr "태그 로드 중..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "로그인"
|
msgstr "로그인"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "로그아웃"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "사용자 관리"
|
msgstr "사용자 관리"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "사용자 관리"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "모두 읽은 상태로 표시"
|
msgstr "모두 읽은 상태로 표시"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "모든 항목을 읽은 상태로 표시"
|
msgstr "모든 항목을 읽은 상태로 표시"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "읽은 상태로 표시"
|
msgstr "읽은 상태로 표시"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "여기까지 읽은 것으로 표시"
|
msgstr "여기까지 읽은 것으로 표시"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "페이지를 아래로 이동"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "페이지를 위로 이동"
|
msgstr "페이지를 위로 이동"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr "해당 없음"
|
msgstr "해당 없음"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "이름"
|
msgstr "이름"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "새 비밀번호"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "최신순"
|
msgstr "최신순"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "다음"
|
msgstr "다음"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "부모"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "부모 카테고리"
|
msgstr "부모 카테고리"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "비밀번호"
|
msgstr "비밀번호"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "비밀번호 복구"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "비밀번호가 일치하지 않습니다"
|
msgstr "비밀번호가 일치하지 않습니다"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "위치"
|
msgstr "위치"
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "프로필"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "비밀번호 복구"
|
msgstr "비밀번호 복구"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "새로 고침"
|
msgstr "새로 고침"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr ""
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "저장"
|
msgstr "저장"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "항목 간 탐색 시 부드럽게 스크롤"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "검색"
|
msgstr "검색"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "검색"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "검색에 최소 3자가 필요합니다."
|
msgstr "검색에 최소 3자가 필요합니다."
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "열지 않고 다음 항목에 포커스 설정"
|
msgstr "열지 않고 다음 항목에 포커스 설정"
|
||||||
@@ -850,9 +858,9 @@ msgstr ""
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "가입"
|
msgstr "가입"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "뭔가 안 좋은 일이 일어났어..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "우주"
|
msgstr "우주"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "스타"
|
msgstr "스타"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "별표"
|
msgstr "별표"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "구독"
|
msgstr "구독"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr ""
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "읽지 않음"
|
msgstr "읽지 않음"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "별표 제거"
|
msgstr "별표 제거"
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr ""
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>Perlukan akaun?</0><1>Daftar!</1>"
|
msgstr "<0>Perlukan akaun?</0><1>Daftar!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Mengenai"
|
msgstr "Mengenai"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "Tambah kategori"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Tambah pengguna"
|
msgstr "Tambah pengguna"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Pentadbir"
|
msgstr "Pentadbir"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Semua"
|
msgstr "Semua"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr ""
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Batal"
|
msgstr "Batal"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Kategori"
|
msgstr "Kategori"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr ""
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Padat"
|
msgstr "Padat"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Sahkan"
|
msgstr "Sahkan"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr "Dec"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Paparan"
|
msgstr "Paparan"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "Muat turun"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "Seret pautan ke bar penanda halaman"
|
msgstr "Seret pautan ke bar penanda halaman"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "E-mel"
|
msgstr "E-mel"
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "Alamat e-mel"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Edit pengguna"
|
msgstr "Edit pengguna"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Didayakan"
|
msgstr "Didayakan"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "Dikembangkan"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "Eksport langganan dan kategori anda sebagai fail OPML yang boleh diimport dalam perkhidmatan membaca suapan lain"
|
msgstr "Eksport langganan dan kategori anda sebagai fail OPML yang boleh diimport dalam perkhidmatan membaca suapan lain"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr ""
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "Nama suapan"
|
msgstr "Nama suapan"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "URL Suapan"
|
msgstr "URL Suapan"
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr ""
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Lupa kata laluan?"
|
msgstr "Lupa kata laluan?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "Jana kunci API dalam profil anda dahulu."
|
msgstr "Jana kunci API dalam profil anda dahulu."
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "Jana kunci API dalam profil anda dahulu."
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "Jana kunci API baharu"
|
msgstr "Jana kunci API baharu"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "Url suapan yang dijana"
|
msgstr "Url suapan yang dijana"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -440,13 +440,13 @@ msgstr ""
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "Dalam paparan yang diperluas, menatal melalui entri menandakannya sebagai dibaca"
|
msgstr "Dalam paparan yang diperluas, menatal melalui entri menandakannya sebagai dibaca"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Teruskan tidak dibaca"
|
msgstr "Teruskan tidak dibaca"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Pintasan papan kekunci"
|
msgstr "Pintasan papan kekunci"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "Mesej muat semula terakhir"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "Pautan"
|
msgstr "Pautan"
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "Memuatkan langganan..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "Memuatkan tag..."
|
msgstr "Memuatkan tag..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Log masuk"
|
msgstr "Log masuk"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "Log Keluar"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Urus pengguna"
|
msgstr "Urus pengguna"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "Urus pengguna"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "Tandai semua sebagai dibaca"
|
msgstr "Tandai semua sebagai dibaca"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "Tandai semua entri sebagai dibaca"
|
msgstr "Tandai semua entri sebagai dibaca"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Tandakan sebagai dibaca"
|
msgstr "Tandakan sebagai dibaca"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "Tandai sebagai dibaca sehingga di sini"
|
msgstr "Tandai sebagai dibaca sehingga di sini"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "Gerakkan halaman ke bawah"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "Alih halaman ke atas"
|
msgstr "Alih halaman ke atas"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr "T/A"
|
msgstr "T/A"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nama"
|
msgstr "Nama"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "Kata laluan baharu"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Terbaharu dahulu"
|
msgstr "Terbaharu dahulu"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Seterusnya"
|
msgstr "Seterusnya"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "Ibu bapa"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "Kategori Induk"
|
msgstr "Kategori Induk"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Kata Laluan"
|
msgstr "Kata Laluan"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "Pemulihan Kata Laluan"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Kata laluan tidak sepadan"
|
msgstr "Kata laluan tidak sepadan"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Kedudukan"
|
msgstr "Kedudukan"
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "Profil"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Pulihkan kata laluan"
|
msgstr "Pulihkan kata laluan"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Muat semula"
|
msgstr "Muat semula"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr "REHAT API"
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Jimat"
|
msgstr "Jimat"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "Tatal dengan lancar apabila menavigasi antara entri"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Cari"
|
msgstr "Cari"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "Cari"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "Cari memerlukan sekurang-kurangnya 3 aksara"
|
msgstr "Cari memerlukan sekurang-kurangnya 3 aksara"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "Tetapkan fokus pada entri seterusnya tanpa membukanya"
|
msgstr "Tetapkan fokus pada entri seterusnya tanpa membukanya"
|
||||||
@@ -850,9 +858,9 @@ msgstr ""
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "Daftar"
|
msgstr "Daftar"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "Sesuatu yang buruk baru saja berlaku..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Angkasa"
|
msgstr "Angkasa"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "Bintang"
|
msgstr "Bintang"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "Dibintangi"
|
msgstr "Dibintangi"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "Langgan"
|
msgstr "Langgan"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr ""
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Belum dibaca"
|
msgstr "Belum dibaca"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "Nyahbintang"
|
msgstr "Nyahbintang"
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr ""
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>Trenger du en konto?</0><1>Registrer deg!</1>"
|
msgstr "<0>Trenger du en konto?</0><1>Registrer deg!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Omtrent"
|
msgstr "Omtrent"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "Legg til kategori"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Legg til bruker"
|
msgstr "Legg til bruker"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Alle"
|
msgstr "Alle"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr ""
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Avbryt"
|
msgstr "Avbryt"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Kategori"
|
msgstr "Kategori"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr ""
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Kompakt"
|
msgstr "Kompakt"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Bekreft"
|
msgstr "Bekreft"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr ""
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Visning"
|
msgstr "Visning"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "Last ned"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "Dra lenken til bokmerkelinjen"
|
msgstr "Dra lenken til bokmerkelinjen"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "E-post"
|
msgstr "E-post"
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "E-postadresse"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Rediger bruker"
|
msgstr "Rediger bruker"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Aktivert"
|
msgstr "Aktivert"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "Utvidet"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "Eksporter abonnementene og kategoriene dine som en OPML-fil som kan importeres i andre feedlesetjenester"
|
msgstr "Eksporter abonnementene og kategoriene dine som en OPML-fil som kan importeres i andre feedlesetjenester"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr ""
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "Feednavn"
|
msgstr "Feednavn"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "Feed-URL"
|
msgstr "Feed-URL"
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr ""
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Glemt passord?"
|
msgstr "Glemt passord?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "Generer en API-nøkkel i profilen din først."
|
msgstr "Generer en API-nøkkel i profilen din først."
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "Generer en API-nøkkel i profilen din først."
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "Generer ny API-nøkkel"
|
msgstr "Generer ny API-nøkkel"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "Generert feed-url"
|
msgstr "Generert feed-url"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -440,13 +440,13 @@ msgstr ""
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "I utvidet visning merker du dem som lest ved å rulle gjennom oppføringer"
|
msgstr "I utvidet visning merker du dem som lest ved å rulle gjennom oppføringer"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Behold ulest"
|
msgstr "Behold ulest"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Tastatursnarveier"
|
msgstr "Tastatursnarveier"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "Siste oppdateringsmelding"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "Laster abonnementer..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "Laster tagger..."
|
msgstr "Laster tagger..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Logg inn"
|
msgstr "Logg inn"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "Logg ut"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Administrer brukere"
|
msgstr "Administrer brukere"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "Administrer brukere"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "Merk alle som lest"
|
msgstr "Merk alle som lest"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "Merk alle oppføringer som lest"
|
msgstr "Merk alle oppføringer som lest"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Merk som lest"
|
msgstr "Merk som lest"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "Merk som lest frem til her"
|
msgstr "Merk som lest frem til her"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "Flytt siden ned"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "Flytt siden opp"
|
msgstr "Flytt siden opp"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Navn"
|
msgstr "Navn"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "Nytt passord"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Nyeste først"
|
msgstr "Nyeste først"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Neste"
|
msgstr "Neste"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "Foreldre"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "Overordnet kategori"
|
msgstr "Overordnet kategori"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Passord"
|
msgstr "Passord"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "Passordgjenoppretting"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Passordene samsvarer ikke"
|
msgstr "Passordene samsvarer ikke"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Posisjon"
|
msgstr "Posisjon"
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "Profil"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Gjenopprett passord"
|
msgstr "Gjenopprett passord"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Oppdater"
|
msgstr "Oppdater"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr ""
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Lagre"
|
msgstr "Lagre"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "Rull jevnt når du navigerer mellom oppføringer"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Søk"
|
msgstr "Søk"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "Søk"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "Søk krever minst 3 tegn"
|
msgstr "Søk krever minst 3 tegn"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "Sett fokus på neste oppføring uten å åpne den"
|
msgstr "Sett fokus på neste oppføring uten å åpne den"
|
||||||
@@ -850,9 +858,9 @@ msgstr ""
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "Meld deg på"
|
msgstr "Meld deg på"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "Noe ille skjedde akkurat..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "Stjerne"
|
msgstr "Stjerne"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "Stjerne"
|
msgstr "Stjerne"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "Abonner"
|
msgstr "Abonner"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr ""
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Ulest"
|
msgstr "Ulest"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "Fjern stjerne"
|
msgstr "Fjern stjerne"
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr ""
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>Een account nodig?</0><1>Meld je aan!</1>"
|
msgstr "<0>Een account nodig?</0><1>Meld je aan!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Over"
|
msgstr "Over"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "Categorie toevoegen"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Gebruiker toevoegen"
|
msgstr "Gebruiker toevoegen"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Beheerder"
|
msgstr "Beheerder"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Alles"
|
msgstr "Alles"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr ""
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Annuleren"
|
msgstr "Annuleren"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Categorie"
|
msgstr "Categorie"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr ""
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Bevestigen"
|
msgstr "Bevestigen"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr "Beschrijving"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Weergave"
|
msgstr "Weergave"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "Downloaden"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "Link naar bladwijzerbalk slepen"
|
msgstr "Link naar bladwijzerbalk slepen"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "E-mailadres"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Gebruiker bewerken"
|
msgstr "Gebruiker bewerken"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Ingeschakeld"
|
msgstr "Ingeschakeld"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "Uitgebreid"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "Exporteer uw abonnementen en categorieën als een OPML-bestand dat kan worden geïmporteerd in andere feedleesservices"
|
msgstr "Exporteer uw abonnementen en categorieën als een OPML-bestand dat kan worden geïmporteerd in andere feedleesservices"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr ""
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "Feednaam"
|
msgstr "Feednaam"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "Feed-URL"
|
msgstr "Feed-URL"
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr ""
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Wachtwoord vergeten?"
|
msgstr "Wachtwoord vergeten?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "Genereer eerst een API-sleutel in uw profiel."
|
msgstr "Genereer eerst een API-sleutel in uw profiel."
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "Genereer eerst een API-sleutel in uw profiel."
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "Nieuwe API-sleutel genereren"
|
msgstr "Nieuwe API-sleutel genereren"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "Gegenereerde feed-url"
|
msgstr "Gegenereerde feed-url"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -440,13 +440,13 @@ msgstr ""
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "In de uitgevouwen weergave markeert het scrollen door items ze als gelezen"
|
msgstr "In de uitgevouwen weergave markeert het scrollen door items ze als gelezen"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Ongelezen houden"
|
msgstr "Ongelezen houden"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "sneltoetsen"
|
msgstr "sneltoetsen"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "Laatste verversingsbericht"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "Abonnementen laden..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "Tags laden..."
|
msgstr "Tags laden..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Inloggen"
|
msgstr "Inloggen"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "Uitloggen"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Gebruikers beheren"
|
msgstr "Gebruikers beheren"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "Gebruikers beheren"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "Alles markeren als gelezen"
|
msgstr "Alles markeren als gelezen"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "Markeer alle vermeldingen als gelezen"
|
msgstr "Markeer alle vermeldingen als gelezen"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Markeren als gelezen"
|
msgstr "Markeren als gelezen"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "Markeer als gelezen tot hier"
|
msgstr "Markeer als gelezen tot hier"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "Verplaats de pagina naar beneden"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "Verplaats de pagina omhoog"
|
msgstr "Verplaats de pagina omhoog"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Naam"
|
msgstr "Naam"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "Nieuw wachtwoord"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Nieuwste eerst"
|
msgstr "Nieuwste eerst"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Volgende"
|
msgstr "Volgende"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "Ouder"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "Oudercategorie"
|
msgstr "Oudercategorie"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Wachtwoord"
|
msgstr "Wachtwoord"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "Wachtwoordherstel"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Wachtwoorden komen niet overeen"
|
msgstr "Wachtwoorden komen niet overeen"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Positie"
|
msgstr "Positie"
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "Profiel"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "wachtwoord herstellen"
|
msgstr "wachtwoord herstellen"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Vernieuwen"
|
msgstr "Vernieuwen"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr "REST-API"
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Opslaan"
|
msgstr "Opslaan"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "Vloeiend scrollen bij het navigeren tussen items"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Zoeken"
|
msgstr "Zoeken"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "Zoeken"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "Zoeken vereist minimaal 3 tekens"
|
msgstr "Zoeken vereist minimaal 3 tekens"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "Stel de focus in op het volgende item zonder het te openen"
|
msgstr "Stel de focus in op het volgende item zonder het te openen"
|
||||||
@@ -850,9 +858,9 @@ msgstr ""
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "Aanmelden"
|
msgstr "Aanmelden"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "Er is net iets ergs gebeurd..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Ruimte"
|
msgstr "Ruimte"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "Ster"
|
msgstr "Ster"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "Met ster"
|
msgstr "Met ster"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "Abonneren"
|
msgstr "Abonneren"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr ""
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Ongelezen"
|
msgstr "Ongelezen"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "Sterren uit"
|
msgstr "Sterren uit"
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr ""
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>Trenger du en konto?</0><1>Registrer deg!</1>"
|
msgstr "<0>Trenger du en konto?</0><1>Registrer deg!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Omtrent"
|
msgstr "Omtrent"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "Legg til kategori"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Legg til bruker"
|
msgstr "Legg til bruker"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Alle"
|
msgstr "Alle"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr ""
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Avbryt"
|
msgstr "Avbryt"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Kategori"
|
msgstr "Kategori"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr ""
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Kompakt"
|
msgstr "Kompakt"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Bekreft"
|
msgstr "Bekreft"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr ""
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Visning"
|
msgstr "Visning"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "Last ned"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "Dra lenken til bokmerkelinjen"
|
msgstr "Dra lenken til bokmerkelinjen"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "E-post"
|
msgstr "E-post"
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "E-postadresse"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Rediger bruker"
|
msgstr "Rediger bruker"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Aktivert"
|
msgstr "Aktivert"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "Utvidet"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "Eksporter abonnementene og kategoriene dine som en OPML-fil som kan importeres i andre feedlesetjenester"
|
msgstr "Eksporter abonnementene og kategoriene dine som en OPML-fil som kan importeres i andre feedlesetjenester"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr ""
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "Feednavn"
|
msgstr "Feednavn"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "Feed-URL"
|
msgstr "Feed-URL"
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr ""
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Glemt passord?"
|
msgstr "Glemt passord?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "Generer en API-nøkkel i profilen din først."
|
msgstr "Generer en API-nøkkel i profilen din først."
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "Generer en API-nøkkel i profilen din først."
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "Generer ny API-nøkkel"
|
msgstr "Generer ny API-nøkkel"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "Generert feed-url"
|
msgstr "Generert feed-url"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -440,13 +440,13 @@ msgstr ""
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "I utvidet visning merker du dem som lest ved å rulle gjennom oppføringer"
|
msgstr "I utvidet visning merker du dem som lest ved å rulle gjennom oppføringer"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Behold ulest"
|
msgstr "Behold ulest"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Tastatursnarveier"
|
msgstr "Tastatursnarveier"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "Siste oppdateringsmelding"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "Laster abonnementer..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "Laster tagger..."
|
msgstr "Laster tagger..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Logg inn"
|
msgstr "Logg inn"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "Logg ut"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Administrer brukere"
|
msgstr "Administrer brukere"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "Administrer brukere"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "Merk alle som lest"
|
msgstr "Merk alle som lest"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "Merk alle oppføringer som lest"
|
msgstr "Merk alle oppføringer som lest"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Merk som lest"
|
msgstr "Merk som lest"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "Merk som lest frem til her"
|
msgstr "Merk som lest frem til her"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "Flytt siden ned"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "Flytt siden opp"
|
msgstr "Flytt siden opp"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Navn"
|
msgstr "Navn"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "Nytt passord"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Nyeste først"
|
msgstr "Nyeste først"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Neste"
|
msgstr "Neste"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "Foreldre"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "Overordnet kategori"
|
msgstr "Overordnet kategori"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Passord"
|
msgstr "Passord"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "Passordgjenoppretting"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Passordene samsvarer ikke"
|
msgstr "Passordene samsvarer ikke"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Posisjon"
|
msgstr "Posisjon"
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "Profil"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Gjenopprett passord"
|
msgstr "Gjenopprett passord"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Oppdater"
|
msgstr "Oppdater"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr ""
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Lagre"
|
msgstr "Lagre"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "Rull jevnt når du navigerer mellom oppføringer"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Søk"
|
msgstr "Søk"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "Søk"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "Søk krever minst 3 tegn"
|
msgstr "Søk krever minst 3 tegn"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "Sett fokus på neste oppføring uten å åpne den"
|
msgstr "Sett fokus på neste oppføring uten å åpne den"
|
||||||
@@ -850,9 +858,9 @@ msgstr ""
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "Meld deg på"
|
msgstr "Meld deg på"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "Noe ille skjedde akkurat..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "Stjerne"
|
msgstr "Stjerne"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "Stjerne"
|
msgstr "Stjerne"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "Abonner"
|
msgstr "Abonner"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr ""
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Ulest"
|
msgstr "Ulest"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "Fjern stjerne"
|
msgstr "Fjern stjerne"
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr ""
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>Potrzebujesz konta?</0><1>Zarejestruj się!</1>"
|
msgstr "<0>Potrzebujesz konta?</0><1>Zarejestruj się!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "O"
|
msgstr "O"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "Dodaj kategorię"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Dodaj użytkownika"
|
msgstr "Dodaj użytkownika"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Administracja"
|
msgstr "Administracja"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Wszystkie"
|
msgstr "Wszystkie"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr ""
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Anuluj"
|
msgstr "Anuluj"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Kategoria"
|
msgstr "Kategoria"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr ""
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Kompaktowy"
|
msgstr "Kompaktowy"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Potwierdź"
|
msgstr "Potwierdź"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr "Opis"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Wyświetlacz"
|
msgstr "Wyświetlacz"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "Pobierz"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "Przeciągnij link do paska zakładek"
|
msgstr "Przeciągnij link do paska zakładek"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "Adres e-mail"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Edytuj użytkownika"
|
msgstr "Edytuj użytkownika"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "włączone"
|
msgstr "włączone"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "Rozszerzony"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "Eksportuj swoje subskrypcje i kategorie jako plik OPML, który można zaimportować do innych usług odczytu kanałów"
|
msgstr "Eksportuj swoje subskrypcje i kategorie jako plik OPML, który można zaimportować do innych usług odczytu kanałów"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr ""
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "nazwa kanału"
|
msgstr "nazwa kanału"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "URL kanału"
|
msgstr "URL kanału"
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr ""
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Zapomniałeś hasła?"
|
msgstr "Zapomniałeś hasła?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "Najpierw wygeneruj klucz API w swoim profilu."
|
msgstr "Najpierw wygeneruj klucz API w swoim profilu."
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "Najpierw wygeneruj klucz API w swoim profilu."
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "Wygeneruj nowy klucz API"
|
msgstr "Wygeneruj nowy klucz API"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "Wygenerowany adres URL kanału"
|
msgstr "Wygenerowany adres URL kanału"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -440,13 +440,13 @@ msgstr ""
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "W widoku rozszerzonym przewijanie wpisów oznacza je jako przeczytane"
|
msgstr "W widoku rozszerzonym przewijanie wpisów oznacza je jako przeczytane"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Nie przeczytaj"
|
msgstr "Nie przeczytaj"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Skróty klawiaturowe"
|
msgstr "Skróty klawiaturowe"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "wiadomość o ostatnim odświeżeniu"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "Ładowanie subskrypcji..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "Ładowanie tagów..."
|
msgstr "Ładowanie tagów..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Zaloguj się"
|
msgstr "Zaloguj się"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "Wyloguj"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Zarządzaj użytkownikami"
|
msgstr "Zarządzaj użytkownikami"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "Zarządzaj użytkownikami"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "Oznacz wszystko jako przeczytane"
|
msgstr "Oznacz wszystko jako przeczytane"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "Oznacz wszystkie wpisy jako przeczytane"
|
msgstr "Oznacz wszystkie wpisy jako przeczytane"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Oznacz jako przeczytane"
|
msgstr "Oznacz jako przeczytane"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "Oznacz jako przeczytane do tej pory"
|
msgstr "Oznacz jako przeczytane do tej pory"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "Przesuń stronę w dół"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "Przesuń stronę w górę"
|
msgstr "Przesuń stronę w górę"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr "nie dotyczy"
|
msgstr "nie dotyczy"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nazwa"
|
msgstr "Nazwa"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "Nowe hasło"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Najnowsze jako pierwsze"
|
msgstr "Najnowsze jako pierwsze"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Dalej"
|
msgstr "Dalej"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "Rodzic"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "Kategoria nadrzędna"
|
msgstr "Kategoria nadrzędna"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Hasło"
|
msgstr "Hasło"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "Odzyskiwanie hasła"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Hasła nie pasują"
|
msgstr "Hasła nie pasują"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Pozycja"
|
msgstr "Pozycja"
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "Profil"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Odzyskaj hasło"
|
msgstr "Odzyskaj hasło"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Odśwież"
|
msgstr "Odśwież"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr ""
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Zapisz"
|
msgstr "Zapisz"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "Przewijaj płynnie podczas nawigowania między wpisami"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Szukaj"
|
msgstr "Szukaj"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "Szukaj"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "Wyszukiwanie wymaga co najmniej 3 znaków"
|
msgstr "Wyszukiwanie wymaga co najmniej 3 znaków"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "Ustaw fokus na następnym wpisie bez otwierania go"
|
msgstr "Ustaw fokus na następnym wpisie bez otwierania go"
|
||||||
@@ -850,9 +858,9 @@ msgstr ""
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "Zarejestruj się"
|
msgstr "Zarejestruj się"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "Coś złego właśnie się stało..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Przestrzeń"
|
msgstr "Przestrzeń"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "Gwiazda"
|
msgstr "Gwiazda"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "Oznaczone gwiazdką"
|
msgstr "Oznaczone gwiazdką"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "Subskrybuj"
|
msgstr "Subskrybuj"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr ""
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Nieprzeczytane"
|
msgstr "Nieprzeczytane"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr ""
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>Precisa de uma conta?</0><1>Inscreva-se!</1>"
|
msgstr "<0>Precisa de uma conta?</0><1>Inscreva-se!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Sobre"
|
msgstr "Sobre"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "Adicionar categoria"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Adicionar usuário"
|
msgstr "Adicionar usuário"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Administrador"
|
msgstr "Administrador"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Todos"
|
msgstr "Todos"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr ""
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Cancelar"
|
msgstr "Cancelar"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Categoria"
|
msgstr "Categoria"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr ""
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Compacto"
|
msgstr "Compacto"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Confirmar"
|
msgstr "Confirmar"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr "Descrição"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Exibir"
|
msgstr "Exibir"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "Baixar"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "Arraste o link para a barra de favoritos"
|
msgstr "Arraste o link para a barra de favoritos"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "Endereço de e-mail"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Editar usuário"
|
msgstr "Editar usuário"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Ativado"
|
msgstr "Ativado"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "Expandido"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "Exporte suas inscrições e categorias como um arquivo OPML que pode ser importado em outros serviços de leitura de feed"
|
msgstr "Exporte suas inscrições e categorias como um arquivo OPML que pode ser importado em outros serviços de leitura de feed"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr ""
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "Nome do feed"
|
msgstr "Nome do feed"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "URL do feed"
|
msgstr "URL do feed"
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr ""
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Esqueceu a senha?"
|
msgstr "Esqueceu a senha?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "Gere uma chave de API em seu perfil primeiro."
|
msgstr "Gere uma chave de API em seu perfil primeiro."
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "Gere uma chave de API em seu perfil primeiro."
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "Gerar nova chave de API"
|
msgstr "Gerar nova chave de API"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "URL do feed gerado"
|
msgstr "URL do feed gerado"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -440,13 +440,13 @@ msgstr "Importar"
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "Na visualização expandida, rolar pelas entradas marca-as como lidas"
|
msgstr "Na visualização expandida, rolar pelas entradas marca-as como lidas"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Manter não lido"
|
msgstr "Manter não lido"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Atalhos de teclado"
|
msgstr "Atalhos de teclado"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "Última mensagem de atualização"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "Carregando assinaturas..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "Carregando tags..."
|
msgstr "Carregando tags..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Entrar"
|
msgstr "Entrar"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "Sair"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Gerenciar usuários"
|
msgstr "Gerenciar usuários"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "Gerenciar usuários"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "Marcar todos como lidos"
|
msgstr "Marcar todos como lidos"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "Marcar todas as entradas como lidas"
|
msgstr "Marcar todas as entradas como lidas"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Marcar como lido"
|
msgstr "Marcar como lido"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "Marcar como lido até aqui"
|
msgstr "Marcar como lido até aqui"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "Mova a página para baixo"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "Mover a página para cima"
|
msgstr "Mover a página para cima"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr "N/D"
|
msgstr "N/D"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nome"
|
msgstr "Nome"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "Nova senha"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Mais novo primeiro"
|
msgstr "Mais novo primeiro"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Próximo"
|
msgstr "Próximo"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "Pai"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "Categoria Pai"
|
msgstr "Categoria Pai"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Senha"
|
msgstr "Senha"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "Recuperação de Senha"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Senhas não coincidem"
|
msgstr "Senhas não coincidem"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Posição"
|
msgstr "Posição"
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "Perfil"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Recuperar senha"
|
msgstr "Recuperar senha"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Atualizar"
|
msgstr "Atualizar"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr "API REST"
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Salvar"
|
msgstr "Salvar"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "Rolar suavemente ao navegar entre as entradas"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Pesquisar"
|
msgstr "Pesquisar"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "Pesquisar"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "Pesquisa requer pelo menos 3 caracteres"
|
msgstr "Pesquisa requer pelo menos 3 caracteres"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "Definir o foco na próxima entrada sem abri-la"
|
msgstr "Definir o foco na próxima entrada sem abri-la"
|
||||||
@@ -850,9 +858,9 @@ msgstr ""
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "Inscreva-se"
|
msgstr "Inscreva-se"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "Algo ruim acabou de acontecer..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Espaço"
|
msgstr "Espaço"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "Estrela"
|
msgstr "Estrela"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "Com estrela"
|
msgstr "Com estrela"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "Assinar"
|
msgstr "Assinar"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr ""
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Não lido"
|
msgstr "Não lido"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "Desestrelar"
|
msgstr "Desestrelar"
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr "<0>Здравствуйте,</0><1>Я Жереми из Бельгии,
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>Нужен аккаунт?</0><1>Зарегистрируйтесь!</1>"
|
msgstr "<0>Нужен аккаунт?</0><1>Зарегистрируйтесь!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "О CommaFeed"
|
msgstr "О CommaFeed"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "Добавить категорию"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Добавить пользователя"
|
msgstr "Добавить пользователя"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Админ"
|
msgstr "Админ"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Все"
|
msgstr "Все"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr "Расширение для браузера"
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Отмена"
|
msgstr "Отмена"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Категория"
|
msgstr "Категория"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr "CommaFeed версии {version} ({revision})."
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Компактный"
|
msgstr "Компактный"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Подтвердить"
|
msgstr "Подтвердить"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr "По убыванию"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr "Подробно"
|
msgstr "Подробно"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Отображение"
|
msgstr "Отображение"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr "Пожертвование"
|
msgstr "Пожертвование"
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "Скачать"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "Перетащите ссылку на панель закладок"
|
msgstr "Перетащите ссылку на панель закладок"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "Электронная почта"
|
msgstr "Электронная почта"
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "Адрес электронной почты"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Редактировать пользователя"
|
msgstr "Редактировать пользователя"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Включено"
|
msgstr "Включено"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "Расширенный"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "Экспортируйте свои подписки и категории в виде файла OPML, который можно импортировать в другие службы чтения каналов."
|
msgstr "Экспортируйте свои подписки и категории в виде файла OPML, который можно импортировать в другие службы чтения каналов."
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr "Параметры расширения"
|
msgstr "Параметры расширения"
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr "Параметры расширения"
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "Имя фида"
|
msgstr "Имя фида"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "URL-адрес фида"
|
msgstr "URL-адрес фида"
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr ""
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Забыли пароль?"
|
msgstr "Забыли пароль?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "Сначала сгенерируйте ключ API в своем профиле."
|
msgstr "Сначала сгенерируйте ключ API в своем профиле."
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "Сначала сгенерируйте ключ API в своем пр
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "Создать новый ключ API"
|
msgstr "Создать новый ключ API"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "Сгенерированный URL фида"
|
msgstr "Сгенерированный URL фида"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr "Перейти к {0}"
|
msgstr "Перейти к {0}"
|
||||||
@@ -440,13 +440,13 @@ msgstr "Импорт"
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "В развернутом виде прокрутка записей помечает их как прочитанные."
|
msgstr "В развернутом виде прокрутка записей помечает их как прочитанные."
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Оставить непрочитанным"
|
msgstr "Оставить непрочитанным"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Сочетания клавиш"
|
msgstr "Сочетания клавиш"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "Последнее сообщение об обновлении"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr "Светлая"
|
msgstr "Светлая"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "Ссылка"
|
msgstr "Ссылка"
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "Загрузка подписок..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "Загрузка тегов..."
|
msgstr "Загрузка тегов..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Войти"
|
msgstr "Войти"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "Выйти"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr "Долгое нажатие"
|
msgstr "Долгое нажатие"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Управление пользователями"
|
msgstr "Управление пользователями"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "Управление пользователями"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "Отметить все как прочитанное"
|
msgstr "Отметить все как прочитанное"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "Отметить все записи как прочитанные"
|
msgstr "Отметить все записи как прочитанные"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Отметить как прочитанное"
|
msgstr "Отметить как прочитанное"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "Отметить как прочитанное до этого места"
|
msgstr "Отметить как прочитанное до этого места"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "Переместить страницу вниз"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "Переместить страницу вверх"
|
msgstr "Переместить страницу вверх"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr "Н/Д"
|
msgstr "Н/Д"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Имя"
|
msgstr "Имя"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "Новый пароль"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Сначала новые"
|
msgstr "Сначала новые"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Следующий"
|
msgstr "Следующий"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "Родительский"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "Родительская категория"
|
msgstr "Родительская категория"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Пароль"
|
msgstr "Пароль"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "Восстановление пароля"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Пароли не совпадают"
|
msgstr "Пароли не совпадают"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Позиция"
|
msgstr "Позиция"
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "Профиль"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Восстановить пароль"
|
msgstr "Восстановить пароль"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Обновить"
|
msgstr "Обновить"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr "REST API"
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr "Правый клик"
|
msgstr "Правый клик"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Сохранить"
|
msgstr "Сохранить"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "Плавная прокрутка при переходе между з
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr "Прокрутка"
|
msgstr "Прокрутка"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Поиск"
|
msgstr "Поиск"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "Поиск"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "Для поиска требуется не менее 3 символов"
|
msgstr "Для поиска требуется не менее 3 символов"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "Установить фокус на следующую запись, не открывая ее."
|
msgstr "Установить фокус на следующую запись, не открывая ее."
|
||||||
@@ -850,9 +858,9 @@ msgstr ""
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "Зарегистрироваться"
|
msgstr "Зарегистрироваться"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "Только что случилось что-то плохое..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Пробел"
|
msgstr "Пробел"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "В избранное"
|
msgstr "В избранное"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "Избранное"
|
msgstr "Избранное"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "Подписаться"
|
msgstr "Подписаться"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr "Попробуйте демо-версию!"
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Не прочитано"
|
msgstr "Не прочитано"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "Удалить из избранного"
|
msgstr "Удалить из избранного"
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr ""
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>Potrebujete účet?</0><1>Zaregistrujte sa!</1>"
|
msgstr "<0>Potrebujete účet?</0><1>Zaregistrujte sa!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Asi"
|
msgstr "Asi"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "Pridať kategóriu"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Pridať užívateľa"
|
msgstr "Pridať užívateľa"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Správca"
|
msgstr "Správca"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Všetky"
|
msgstr "Všetky"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr ""
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Zrušiť"
|
msgstr "Zrušiť"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Kategória"
|
msgstr "Kategória"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr ""
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Kompaktný"
|
msgstr "Kompaktný"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Potvrdiť"
|
msgstr "Potvrdiť"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr ""
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Displej"
|
msgstr "Displej"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "Stiahnuť"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "Presuňte odkaz na lištu so záložkami"
|
msgstr "Presuňte odkaz na lištu so záložkami"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "E-mailová adresa"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Upravte používateľa"
|
msgstr "Upravte používateľa"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Povolené"
|
msgstr "Povolené"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "Rozšírené"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "Exportujte svoje odbery a kategórie ako súbor OPML, ktorý je možné importovať do iných služieb na čítanie informačných kanálov"
|
msgstr "Exportujte svoje odbery a kategórie ako súbor OPML, ktorý je možné importovať do iných služieb na čítanie informačných kanálov"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr ""
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "Názov informačného kanála"
|
msgstr "Názov informačného kanála"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "URL informačného kanála"
|
msgstr "URL informačného kanála"
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr ""
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Zabudli ste heslo?"
|
msgstr "Zabudli ste heslo?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "Najprv si vo svojom profile vygenerujte kľúč API."
|
msgstr "Najprv si vo svojom profile vygenerujte kľúč API."
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "Najprv si vo svojom profile vygenerujte kľúč API."
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "Vygenerujte nový kľúč API"
|
msgstr "Vygenerujte nový kľúč API"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "Generovaná adresa URL informačného kanála"
|
msgstr "Generovaná adresa URL informačného kanála"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -440,13 +440,13 @@ msgstr ""
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "V rozšírenom zobrazení ich rolovanie cez položky označí ako prečítané"
|
msgstr "V rozšírenom zobrazení ich rolovanie cez položky označí ako prečítané"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Ponechať neprečítané"
|
msgstr "Ponechať neprečítané"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Klávesové skratky"
|
msgstr "Klávesové skratky"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "Posledná obnovovacia správa"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "Odkaz"
|
msgstr "Odkaz"
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "Načítavam odbery..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "Načítavam značky..."
|
msgstr "Načítavam značky..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Prihláste sa"
|
msgstr "Prihláste sa"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "Odhlásenie"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Správa používateľov"
|
msgstr "Správa používateľov"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "Správa používateľov"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "Označiť všetko ako prečítané"
|
msgstr "Označiť všetko ako prečítané"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "Označte všetky položky ako prečítané"
|
msgstr "Označte všetky položky ako prečítané"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Označiť ako prečítané"
|
msgstr "Označiť ako prečítané"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "Označiť ako prečítané až sem"
|
msgstr "Označiť ako prečítané až sem"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "Posuňte stránku nadol"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "Posuňte stránku nahor"
|
msgstr "Posuňte stránku nahor"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Meno"
|
msgstr "Meno"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "Nové heslo"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Najnovšie ako prvé"
|
msgstr "Najnovšie ako prvé"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Ďalej"
|
msgstr "Ďalej"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "Rodič"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "Rodičovská kategória"
|
msgstr "Rodičovská kategória"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Heslo"
|
msgstr "Heslo"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "Obnovenie hesla"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Heslá sa nezhodujú"
|
msgstr "Heslá sa nezhodujú"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Pozícia"
|
msgstr "Pozícia"
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "Profil"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Obnoviť heslo"
|
msgstr "Obnoviť heslo"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Obnoviť"
|
msgstr "Obnoviť"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr ""
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Uložiť"
|
msgstr "Uložiť"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "Pri navigácii medzi položkami plynulo rolujte"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Hľadaj"
|
msgstr "Hľadaj"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "Hľadaj"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "Hľadanie vyžaduje aspoň 3 znaky"
|
msgstr "Hľadanie vyžaduje aspoň 3 znaky"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "Nastavte zameranie na ďalší záznam bez toho, aby ste ho otvorili"
|
msgstr "Nastavte zameranie na ďalší záznam bez toho, aby ste ho otvorili"
|
||||||
@@ -850,9 +858,9 @@ msgstr ""
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "Zaregistrujte sa"
|
msgstr "Zaregistrujte sa"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "Práve sa stalo niečo zlé..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Vesmír"
|
msgstr "Vesmír"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "Hviezda"
|
msgstr "Hviezda"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "S hviezdičkou"
|
msgstr "S hviezdičkou"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "Prihlásiť sa"
|
msgstr "Prihlásiť sa"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr ""
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Neprečítané"
|
msgstr "Neprečítané"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "Odobrať hviezdičku"
|
msgstr "Odobrať hviezdičku"
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr ""
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>Behöver du ett konto?</0><1>Registrera dig!</1>"
|
msgstr "<0>Behöver du ett konto?</0><1>Registrera dig!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Ungefär"
|
msgstr "Ungefär"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "Lägg till kategori"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Lägg till användare"
|
msgstr "Lägg till användare"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Alla"
|
msgstr "Alla"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr ""
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Avbryt"
|
msgstr "Avbryt"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Kategori"
|
msgstr "Kategori"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr ""
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Kompakt"
|
msgstr "Kompakt"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Bekräfta"
|
msgstr "Bekräfta"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr ""
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Visa"
|
msgstr "Visa"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "Ladda ner"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "Dra länken till bokmärkesfältet"
|
msgstr "Dra länken till bokmärkesfältet"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "E-post"
|
msgstr "E-post"
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "E-postadress"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Redigera användare"
|
msgstr "Redigera användare"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Aktiverad"
|
msgstr "Aktiverad"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "Utökad"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "Exportera dina prenumerationer och kategorier som en OPML-fil som kan importeras i andra flödesläsningstjänster"
|
msgstr "Exportera dina prenumerationer och kategorier som en OPML-fil som kan importeras i andra flödesläsningstjänster"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr ""
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "Flödesnamn"
|
msgstr "Flödesnamn"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "Flödes-URL"
|
msgstr "Flödes-URL"
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr ""
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Glömt lösenord?"
|
msgstr "Glömt lösenord?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "Generera en API-nyckel i din profil först."
|
msgstr "Generera en API-nyckel i din profil först."
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "Generera en API-nyckel i din profil först."
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "Generera ny API-nyckel"
|
msgstr "Generera ny API-nyckel"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "Genererad feed-url"
|
msgstr "Genererad feed-url"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -440,13 +440,13 @@ msgstr ""
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "I utökad vy, rullning genom poster markerar dem som lästa"
|
msgstr "I utökad vy, rullning genom poster markerar dem som lästa"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Behåll oläst"
|
msgstr "Behåll oläst"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Kortkommandon"
|
msgstr "Kortkommandon"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "Senaste uppdateringsmeddelande"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "Länk"
|
msgstr "Länk"
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "Laddar prenumerationer..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "Laddar taggar..."
|
msgstr "Laddar taggar..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Logga in"
|
msgstr "Logga in"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "Logga ut"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Hantera användare"
|
msgstr "Hantera användare"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "Hantera användare"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "Markera alla som lästa"
|
msgstr "Markera alla som lästa"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "Markera alla poster som lästa"
|
msgstr "Markera alla poster som lästa"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Markera som läst"
|
msgstr "Markera som läst"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "Markera som läst hit"
|
msgstr "Markera som läst hit"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "Flytta sidan nedåt"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "Flytta sidan uppåt"
|
msgstr "Flytta sidan uppåt"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Namn"
|
msgstr "Namn"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "Nytt lösenord"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Nyast först"
|
msgstr "Nyast först"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Nästa"
|
msgstr "Nästa"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "Förälder"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "Föräldrakategori"
|
msgstr "Föräldrakategori"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Lösenord"
|
msgstr "Lösenord"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "Lösenordsåterställning"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Lösenorden matchar inte"
|
msgstr "Lösenorden matchar inte"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "Profil"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Återställ lösenord"
|
msgstr "Återställ lösenord"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Uppdatera"
|
msgstr "Uppdatera"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr ""
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Spara"
|
msgstr "Spara"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "Bläddra mjukt när du navigerar mellan poster"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Sök"
|
msgstr "Sök"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "Sök"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "Sökning kräver minst 3 tecken"
|
msgstr "Sökning kräver minst 3 tecken"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "Sätt fokus på nästa post utan att öppna den"
|
msgstr "Sätt fokus på nästa post utan att öppna den"
|
||||||
@@ -850,9 +858,9 @@ msgstr ""
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "Anmäl dig"
|
msgstr "Anmäl dig"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "Något dåligt hände precis..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Rymden"
|
msgstr "Rymden"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "Stjärna"
|
msgstr "Stjärna"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "Starmed"
|
msgstr "Starmed"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "Prenumerera"
|
msgstr "Prenumerera"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr ""
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Oläst"
|
msgstr "Oläst"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr "<0>Merhaba,</0><1>Ben Belçika'dan Jérémie ve 10 yıldır boş zamanla
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>Bir hesaba mı ihtiyacınız var?</0><1>Kaydolun!</1>"
|
msgstr "<0>Bir hesaba mı ihtiyacınız var?</0><1>Kaydolun!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Hakkında"
|
msgstr "Hakkında"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "Kategori ekle"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Kullanıcı ekle"
|
msgstr "Kullanıcı ekle"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Yönetici"
|
msgstr "Yönetici"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Tümü"
|
msgstr "Tümü"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr "Tarayıcı eklentisi"
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "İptal"
|
msgstr "İptal"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Kategori"
|
msgstr "Kategori"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr "CommaFeed sürüm {version} ({revision})."
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Kompakt"
|
msgstr "Kompakt"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Onayla"
|
msgstr "Onayla"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr "Açılış"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Ekran"
|
msgstr "Ekran"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "İndir"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "Bağlantıyı yer işareti çubuğuna sürükleyin"
|
msgstr "Bağlantıyı yer işareti çubuğuna sürükleyin"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "E-posta"
|
msgstr "E-posta"
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "E-posta adresi"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Kullanıcıyı düzenle"
|
msgstr "Kullanıcıyı düzenle"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Etkin"
|
msgstr "Etkin"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "Genişletilmiş"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "Aboneliklerinizi ve kategorilerinizi diğer besleme okuma hizmetlerinde içe aktarılabilen bir OPML dosyası olarak dışa aktarın"
|
msgstr "Aboneliklerinizi ve kategorilerinizi diğer besleme okuma hizmetlerinde içe aktarılabilen bir OPML dosyası olarak dışa aktarın"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr "Eklenti ayarları"
|
msgstr "Eklenti ayarları"
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr "Eklenti ayarları"
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "Yayın adı"
|
msgstr "Yayın adı"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "Feed URL'si"
|
msgstr "Feed URL'si"
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr ""
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Parolanızı mı unuttunuz?"
|
msgstr "Parolanızı mı unuttunuz?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "Önce profilinizde bir API anahtarı oluşturun."
|
msgstr "Önce profilinizde bir API anahtarı oluşturun."
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "Önce profilinizde bir API anahtarı oluşturun."
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "Yeni API anahtarı oluştur"
|
msgstr "Yeni API anahtarı oluştur"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "Oluşturulan besleme url'si"
|
msgstr "Oluşturulan besleme url'si"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr "{0}'a git"
|
msgstr "{0}'a git"
|
||||||
@@ -440,13 +440,13 @@ msgstr "İçe Aktar"
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "Genişletilmiş görünümde, girişler arasında gezinmek onları okundu olarak işaretler"
|
msgstr "Genişletilmiş görünümde, girişler arasında gezinmek onları okundu olarak işaretler"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Okunmadan sakla"
|
msgstr "Okunmadan sakla"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Klavye kısayolları"
|
msgstr "Klavye kısayolları"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "Son yenileme mesajı"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "Bağlantı"
|
msgstr "Bağlantı"
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "Abonelikler yükleniyor..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "Etiketler yükleniyor..."
|
msgstr "Etiketler yükleniyor..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "Giriş"
|
msgstr "Giriş"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "Çıkış"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr "Uzun bas"
|
msgstr "Uzun bas"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Kullanıcıları yönet"
|
msgstr "Kullanıcıları yönet"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "Kullanıcıları yönet"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "Tümünü okundu olarak işaretle"
|
msgstr "Tümünü okundu olarak işaretle"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "Tüm girişleri okundu olarak işaretle"
|
msgstr "Tüm girişleri okundu olarak işaretle"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Okundu olarak işaretle"
|
msgstr "Okundu olarak işaretle"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "Buraya kadar okundu olarak işaretle"
|
msgstr "Buraya kadar okundu olarak işaretle"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "Sayfayı aşağı taşı"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "Sayfayı yukarı taşı"
|
msgstr "Sayfayı yukarı taşı"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr "Yok"
|
msgstr "Yok"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "İsim"
|
msgstr "İsim"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "Yeni şifre"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Önce en yenisi"
|
msgstr "Önce en yenisi"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Sonraki"
|
msgstr "Sonraki"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "Ebeveyn"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "Üst Kategori"
|
msgstr "Üst Kategori"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "Şifre"
|
msgstr "Şifre"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "Parola Kurtarma"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Parolalar eşleşmiyor"
|
msgstr "Parolalar eşleşmiyor"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Konum"
|
msgstr "Konum"
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "Profil"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Şifreyi kurtar"
|
msgstr "Şifreyi kurtar"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Yenile"
|
msgstr "Yenile"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr "REST API"
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr "Sağ tık"
|
msgstr "Sağ tık"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Kaydet"
|
msgstr "Kaydet"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "Girişler arasında gezinirken sorunsuz ilerleyin"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Ara"
|
msgstr "Ara"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "Ara"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "Arama için en az 3 karakter gerekiyor"
|
msgstr "Arama için en az 3 karakter gerekiyor"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "Odağı açmadan sonraki girişe ayarlayın"
|
msgstr "Odağı açmadan sonraki girişe ayarlayın"
|
||||||
@@ -850,9 +858,9 @@ msgstr ""
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "Kaydolun"
|
msgstr "Kaydolun"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "Az önce kötü bir şey oldu..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Uzay"
|
msgstr "Uzay"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "Yıldız"
|
msgstr "Yıldız"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "Yıldızlı"
|
msgstr "Yıldızlı"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "Abone ol"
|
msgstr "Abone ol"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr "Demo'yu deneyin!"
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Okunmamış"
|
msgstr "Okunmamış"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "Yıldızı kaldır"
|
msgstr "Yıldızı kaldır"
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ msgstr "<0>您好,</0><1>我是来自比利时的Jérémie,已经在业余时
|
|||||||
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
msgid "<0>Need an account?</0><1>Sign up!</1>"
|
||||||
msgstr "<0>需要一个帐户?</0><1>注册!</1>"
|
msgstr "<0>需要一个帐户?</0><1>注册!</1>"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "关于"
|
msgstr "关于"
|
||||||
|
|
||||||
@@ -54,16 +54,15 @@ msgstr "添加类别"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "添加用户"
|
msgstr "添加用户"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "管理员"
|
msgstr "管理员"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "全部"
|
msgstr "全部"
|
||||||
|
|
||||||
@@ -144,27 +143,27 @@ msgstr "浏览器扩展"
|
|||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr "浏览器标签页"
|
msgstr "浏览器标签页"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "取消"
|
msgstr "取消"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "类别"
|
msgstr "类别"
|
||||||
|
|
||||||
@@ -204,11 +203,11 @@ msgstr "CommaFeed版本:{version} ({revision})"
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "紧凑"
|
msgstr "紧凑"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "确认"
|
msgstr "确认"
|
||||||
|
|
||||||
@@ -273,13 +272,13 @@ msgstr "降序"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr "详细"
|
msgstr "详细"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "显示"
|
msgstr "显示"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
#: src/pages/app/DonatePage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr "捐赠"
|
msgstr "捐赠"
|
||||||
|
|
||||||
@@ -291,11 +290,11 @@ msgstr "下载"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "拖动链接到书签栏"
|
msgstr "拖动链接到书签栏"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "电子邮件"
|
msgstr "电子邮件"
|
||||||
|
|
||||||
@@ -308,8 +307,8 @@ msgstr "电子邮件地址"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "编辑用户"
|
msgstr "编辑用户"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "已启用"
|
msgstr "已启用"
|
||||||
|
|
||||||
@@ -345,8 +344,8 @@ msgstr "展开"
|
|||||||
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
msgid "Export your subscriptions and categories as an OPML file that can be imported in other feed reading services"
|
||||||
msgstr "将您的订阅和类别导出为 OPML 文件,可以在其它信息流阅读服务中导入"
|
msgstr "将您的订阅和类别导出为 OPML 文件,可以在其它信息流阅读服务中导入"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr "扩展选项"
|
msgstr "扩展选项"
|
||||||
|
|
||||||
@@ -354,9 +353,9 @@ msgstr "扩展选项"
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "信息流名称"
|
msgstr "信息流名称"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Feed URL"
|
msgid "Feed URL"
|
||||||
msgstr "信息流网址"
|
msgstr "信息流网址"
|
||||||
|
|
||||||
@@ -384,9 +383,9 @@ msgstr "强制获取订阅源功能不可用。"
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "忘记密码?"
|
msgstr "忘记密码?"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "首先在您的配置文件中生成一个 API 密钥。"
|
msgstr "首先在您的配置文件中生成一个 API 密钥。"
|
||||||
|
|
||||||
@@ -394,12 +393,13 @@ msgstr "首先在您的配置文件中生成一个 API 密钥。"
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "生成新的 API 密钥"
|
msgstr "生成新的 API 密钥"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "生成信息流网址"
|
msgstr "生成信息流网址"
|
||||||
|
|
||||||
|
#. placeholder {0}: truncate(props.entry.feedName, 30)
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Go to {0}"
|
msgid "Go to {0}"
|
||||||
msgstr "转到 {0}"
|
msgstr "转到 {0}"
|
||||||
@@ -440,13 +440,13 @@ msgstr "导入"
|
|||||||
msgid "In expanded view, scrolling through entries mark them as read"
|
msgid "In expanded view, scrolling through entries mark them as read"
|
||||||
msgstr "在展开视图中,滚动条目将它们标记为已读"
|
msgstr "在展开视图中,滚动条目将它们标记为已读"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "保持未读状态"
|
msgstr "保持未读状态"
|
||||||
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
#: src/components/content/FeedEntries.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "键盘快捷键"
|
msgstr "键盘快捷键"
|
||||||
|
|
||||||
@@ -470,9 +470,9 @@ msgstr "上次刷新消息"
|
|||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr "浅色"
|
msgstr "浅色"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "链接"
|
msgstr "链接"
|
||||||
|
|
||||||
@@ -492,9 +492,9 @@ msgstr "正在加载订阅..."
|
|||||||
msgid "Loading tags..."
|
msgid "Loading tags..."
|
||||||
msgstr "正在加载标签..."
|
msgstr "正在加载标签..."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Log in"
|
msgid "Log in"
|
||||||
msgstr "登录"
|
msgstr "登录"
|
||||||
|
|
||||||
@@ -506,8 +506,8 @@ msgstr "注销"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr "长按"
|
msgstr "长按"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "管理用户"
|
msgstr "管理用户"
|
||||||
|
|
||||||
@@ -515,18 +515,18 @@ msgstr "管理用户"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "全部标记为已读"
|
msgstr "全部标记为已读"
|
||||||
|
|
||||||
#: src/components/header/MarkAllAsReadButton.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/MarkAllAsReadButton.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "将所有条目标记为已读"
|
msgstr "将所有条目标记为已读"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "标记为已读"
|
msgstr "标记为已读"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "标记为已读到这里"
|
msgstr "标记为已读到这里"
|
||||||
|
|
||||||
@@ -546,15 +546,15 @@ msgstr "下移页面"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "上移页面"
|
msgstr "上移页面"
|
||||||
|
|
||||||
#: src/components/RelativeDate.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/components/RelativeDate.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr "不适用"
|
msgstr "不适用"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "名称"
|
msgstr "名称"
|
||||||
|
|
||||||
@@ -575,8 +575,8 @@ msgstr "新密码"
|
|||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "最新的优先"
|
msgstr "最新的优先"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "下一个"
|
msgstr "下一个"
|
||||||
|
|
||||||
@@ -694,11 +694,11 @@ msgstr "父类别"
|
|||||||
msgid "Parent Category"
|
msgid "Parent Category"
|
||||||
msgstr "父类别"
|
msgstr "父类别"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
|
#: src/pages/auth/LoginPage.tsx
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
msgid "Password"
|
msgid "Password"
|
||||||
msgstr "密码"
|
msgstr "密码"
|
||||||
|
|
||||||
@@ -710,8 +710,8 @@ msgstr "密码恢复"
|
|||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "密码不匹配"
|
msgstr "密码不匹配"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "位置"
|
msgstr "位置"
|
||||||
|
|
||||||
@@ -727,8 +727,8 @@ msgstr "配置文件"
|
|||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "找回密码"
|
msgstr "找回密码"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "刷新"
|
msgstr "刷新"
|
||||||
|
|
||||||
@@ -745,11 +745,11 @@ msgstr "REST API"
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr "右键单击"
|
msgstr "右键单击"
|
||||||
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/admin/UserEdit.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "保存"
|
msgstr "保存"
|
||||||
|
|
||||||
@@ -765,10 +765,10 @@ msgstr "在条目之间导航时平滑滚动"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr "滚动"
|
msgstr "滚动"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "搜索"
|
msgstr "搜索"
|
||||||
|
|
||||||
@@ -776,6 +776,14 @@ msgstr "搜索"
|
|||||||
msgid "Search requires at least 3 characters"
|
msgid "Search requires at least 3 characters"
|
||||||
msgstr "搜索至少需要 3 个字符"
|
msgstr "搜索至少需要 3 个字符"
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select next unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
msgid "Select previous unread feed/category"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Set focus on next entry without opening it"
|
msgid "Set focus on next entry without opening it"
|
||||||
msgstr "将焦点放在下一个条目而不打开它"
|
msgstr "将焦点放在下一个条目而不打开它"
|
||||||
@@ -850,9 +858,9 @@ msgstr "在标签页图标上显示未读数量"
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr "在标签页标题中显示未读数量"
|
msgstr "在标签页标题中显示未读数量"
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "Sign up"
|
msgid "Sign up"
|
||||||
msgstr "注册"
|
msgstr "注册"
|
||||||
|
|
||||||
@@ -865,20 +873,20 @@ msgstr "刚刚发生了不好的事情……"
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "空格"
|
msgstr "空格"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "星标"
|
msgstr "星标"
|
||||||
|
|
||||||
#: src/app/constants.ts
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
msgid "Starred"
|
msgid "Starred"
|
||||||
msgstr "已加星标"
|
msgstr "已加星标"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Subscribe"
|
msgid "Subscribe"
|
||||||
msgstr "订阅"
|
msgstr "订阅"
|
||||||
|
|
||||||
@@ -951,8 +959,8 @@ msgstr "尝试 demo!"
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "未读"
|
msgstr "未读"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "取消星标"
|
msgstr "取消星标"
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ function NextUnreadBookmarklet() {
|
|||||||
const { _ } = useLingui()
|
const { _ } = useLingui()
|
||||||
|
|
||||||
const baseUrl = window.location.href.substring(0, window.location.href.lastIndexOf("#"))
|
const baseUrl = window.location.href.substring(0, window.location.href.lastIndexOf("#"))
|
||||||
const href = `javascript:window.location.href='${baseUrl}next?category=${categoryId}&order=${order}&t='+new Date().getTime();`
|
const href = `${baseUrl}next?category=${categoryId}&order=${order}`
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
|
|||||||
22
commafeed-client/src/setupTests.ts
Normal file
22
commafeed-client/src/setupTests.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import "@testing-library/jest-dom"
|
||||||
|
import { Constants } from "app/constants"
|
||||||
|
import { vi } from "vitest"
|
||||||
|
|
||||||
|
// reduce delay for faster tests
|
||||||
|
Constants.tooltip.delay = 10
|
||||||
|
|
||||||
|
// jsdom doesn't mock matchMedia
|
||||||
|
// https://stackoverflow.com/a/53449595/
|
||||||
|
Object.defineProperty(window, "matchMedia", {
|
||||||
|
writable: true,
|
||||||
|
value: vi.fn().mockImplementation(query => ({
|
||||||
|
matches: false,
|
||||||
|
media: query,
|
||||||
|
onchange: null,
|
||||||
|
addListener: vi.fn(), // deprecated
|
||||||
|
removeListener: vi.fn(), // deprecated
|
||||||
|
addEventListener: vi.fn(),
|
||||||
|
removeEventListener: vi.fn(),
|
||||||
|
dispatchEvent: vi.fn(),
|
||||||
|
})),
|
||||||
|
})
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { lingui } from "@lingui/vite-plugin"
|
import { lingui } from "@lingui/vite-plugin"
|
||||||
import react from "@vitejs/plugin-react"
|
import react from "@vitejs/plugin-react"
|
||||||
import { visualizer } from "rollup-plugin-visualizer"
|
import { visualizer } from "rollup-plugin-visualizer"
|
||||||
import { defineConfig } from "vite"
|
import { type PluginOption, defineConfig } from "vite"
|
||||||
import checker from "vite-plugin-checker"
|
import checker from "vite-plugin-checker"
|
||||||
import tsconfigPaths from "vite-tsconfig-paths"
|
import tsconfigPaths from "vite-tsconfig-paths"
|
||||||
|
|
||||||
@@ -52,5 +52,7 @@ export default defineConfig(() => ({
|
|||||||
},
|
},
|
||||||
test: {
|
test: {
|
||||||
environment: "jsdom",
|
environment: "jsdom",
|
||||||
|
globals: true,
|
||||||
|
setupFiles: "./src/setupTests.ts",
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
|||||||
@@ -1,401 +1,401 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<profiles version="23">
|
<profiles version="23">
|
||||||
<profile kind="CodeFormatterProfile" name="CommaFeed" version="23">
|
<profile kind="CodeFormatterProfile" name="CommaFeed" version="23">
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="common_lines"/>
|
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="common_lines"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
|
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration" value="common_lines"/>
|
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration" value="common_lines"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.align_with_spaces" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.align_with_spaces" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
|
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="48"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="48"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
|
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_record_components" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_record_components" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_logical_operator" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_logical_operator" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line" value="one_line_never"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line" value="one_line_never"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method" value="1"/>
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method" value="1"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line" value="one_line_never"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line" value="one_line_never"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/>
|
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line" value="one_line_never"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line" value="one_line_never"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_shift_operator" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_shift_operator" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_loops" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_loops" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_switch_case_arrow_operator" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_switch_case_arrow_operator" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="common_lines"/>
|
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="common_lines"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enum_constant" value="49"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enum_constant" value="49"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.text_block_indentation" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.text_block_indentation" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line" value="one_line_never"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line" value="one_line_never"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_permitted_types" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_permitted_types" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_annotations" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_annotations" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="2147483647"/>
|
<setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="2147483647"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="80"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="80"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_not_operator" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_not_operator" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration" value="common_lines"/>
|
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration" value="common_lines"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="48"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="48"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package" value="49"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package" value="49"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_permitted_types_in_type_declaration" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_permitted_types_in_type_declaration" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.javadoc_do_not_separate_block_tags" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.javadoc_do_not_separate_block_tags" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_tag_description" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.indent_tag_description" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_constructor" value="end_of_line"/>
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_constructor" value="end_of_line"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_string_concatenation" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_string_concatenation" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_shift_operator" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_shift_operator" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_shift_operator" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_shift_operator" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_additive_operator" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_additive_operator" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_relational_operator" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_relational_operator" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_logical_operator" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_logical_operator" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/>
|
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration" value="common_lines"/>
|
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration" value="common_lines"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
|
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
|
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="48"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="48"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
|
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_switch_body_block_on_one_line" value="one_line_never"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_switch_body_block_on_one_line" value="one_line_never"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_arrow" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_arrow" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="140"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="140"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_method_body_on_one_line" value="one_line_never"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_method_body_on_one_line" value="one_line_never"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line" value="one_line_never"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line" value="one_line_never"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line" value="one_line_never"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line" value="one_line_never"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_additive_operator" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_additive_operator" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_relational_operator" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_relational_operator" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line" value="one_line_never"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line" value="one_line_never"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_relational_operator" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_relational_operator" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
|
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_additive_operator" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_additive_operator" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.align_selector_in_method_invocation_on_expression_first_line" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.align_selector_in_method_invocation_on_expression_first_line" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_declaration" value="end_of_line"/>
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_declaration" value="end_of_line"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_switch_case_with_arrow_on_one_line" value="one_line_never"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_switch_case_with_arrow_on_one_line" value="one_line_never"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_colon" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_colon" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type" value="49"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type" value="49"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable" value="49"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable" value="49"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_additive_operator" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_additive_operator" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field" value="49"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field" value="49"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_shift_operator" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_shift_operator" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines"/>
|
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_code_block_on_one_line" value="one_line_never"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_code_block_on_one_line" value="one_line_never"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
|
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
|
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="48"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="48"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_switch_case_with_arrow" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_switch_case_with_arrow" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line" value="one_line_never"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line" value="one_line_never"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method" value="49"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method" value="49"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line" value="one_line_never"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line" value="one_line_never"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assertion_message" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assertion_message" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_logical_operator" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_logical_operator" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_relational_operator" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_relational_operator" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line" value="false"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line" value="false"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_logical_operator" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_logical_operator" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="common_lines"/>
|
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="common_lines"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_permitted_types" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_permitted_types" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line" value="one_line_never"/>
|
<setting id="org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line" value="one_line_never"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block" value="0"/>
|
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block" value="0"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="tab"/>
|
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="tab"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_string_concatenation" value="true"/>
|
<setting id="org.eclipse.jdt.core.formatter.wrap_before_string_concatenation" value="true"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="140"/>
|
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="140"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
|
||||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
|
||||||
</profile>
|
</profile>
|
||||||
</profiles>
|
</profiles>
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
<module name="AvoidStaticImport" />
|
<module name="AvoidStaticImport" />
|
||||||
<module name="IllegalImport" />
|
<module name="IllegalImport" />
|
||||||
<module name="ImportOrder">
|
<module name="ImportOrder">
|
||||||
<property name="groups" value="/^java\./,javax,org,com" />
|
<property name="groups" value="/^java\./,javax,jakarta,org,com" />
|
||||||
<property name="ordered" value="true" />
|
<property name="ordered" value="true" />
|
||||||
<property name="separated" value="true" />
|
<property name="separated" value="true" />
|
||||||
</module>
|
</module>
|
||||||
|
|||||||
7
commafeed-server/dev/eclipse.importorder
Normal file
7
commafeed-server/dev/eclipse.importorder
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#Organize Import Order
|
||||||
|
#Wed Jan 29 15:15:04 CET 2025
|
||||||
|
0=java
|
||||||
|
1=javax
|
||||||
|
2=jakarta
|
||||||
|
3=org
|
||||||
|
4=com
|
||||||
@@ -1,894 +0,0 @@
|
|||||||
🔒: Configuration property fixed at build time - All other configuration properties are overridable at runtime
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th align="left">Configuration property</th>
|
|
||||||
<th>Type</th>
|
|
||||||
<th>Default</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.hide-from-web-crawlers`
|
|
||||||
|
|
||||||
Whether to expose a robots.txt file that disallows web crawlers and search engine indexers.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_HIDE_FROM_WEB_CRAWLERS`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
boolean
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`true`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.image-proxy-enabled`
|
|
||||||
|
|
||||||
If enabled, images in feed entries will be proxied through the server instead of accessed directly by the browser.
|
|
||||||
|
|
||||||
This is useful if commafeed is accessed through a restricting proxy that blocks some feeds that are followed.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_IMAGE_PROXY_ENABLED`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
boolean
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`false`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.password-recovery-enabled`
|
|
||||||
|
|
||||||
Enable password recovery via email.
|
|
||||||
|
|
||||||
Quarkus mailer will need to be configured.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_PASSWORD_RECOVERY_ENABLED`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
boolean
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`false`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.announcement`
|
|
||||||
|
|
||||||
Message displayed in a notification at the bottom of the page.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_ANNOUNCEMENT`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
string
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.google-analytics-tracking-code`
|
|
||||||
|
|
||||||
Google Analytics tracking code.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_GOOGLE_ANALYTICS_TRACKING_CODE`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
string
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.google-auth-key`
|
|
||||||
|
|
||||||
Google Auth key for fetching Youtube channel favicons.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_GOOGLE_AUTH_KEY`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
string
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th align="left" colspan="3">
|
|
||||||
HTTP client configuration
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.http-client.user-agent`
|
|
||||||
|
|
||||||
User-Agent string that will be used by the http client, leave empty for the default one.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_HTTP_CLIENT_USER_AGENT`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
string
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.http-client.connect-timeout`
|
|
||||||
|
|
||||||
Time to wait for a connection to be established.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_HTTP_CLIENT_CONNECT_TIMEOUT`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
[Duration](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html) [🛈](#duration-note-anchor)
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`5S`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.http-client.ssl-handshake-timeout`
|
|
||||||
|
|
||||||
Time to wait for SSL handshake to complete.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_HTTP_CLIENT_SSL_HANDSHAKE_TIMEOUT`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
[Duration](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html) [🛈](#duration-note-anchor)
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`5S`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.http-client.socket-timeout`
|
|
||||||
|
|
||||||
Time to wait between two packets before timeout.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_HTTP_CLIENT_SOCKET_TIMEOUT`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
[Duration](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html) [🛈](#duration-note-anchor)
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`10S`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.http-client.response-timeout`
|
|
||||||
|
|
||||||
Time to wait for the full response to be received.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_HTTP_CLIENT_RESPONSE_TIMEOUT`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
[Duration](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html) [🛈](#duration-note-anchor)
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`10S`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.http-client.connection-time-to-live`
|
|
||||||
|
|
||||||
Time to live for a connection in the pool.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_HTTP_CLIENT_CONNECTION_TIME_TO_LIVE`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
[Duration](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html) [🛈](#duration-note-anchor)
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`30S`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.http-client.idle-connections-eviction-interval`
|
|
||||||
|
|
||||||
Time between eviction runs for idle connections.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_HTTP_CLIENT_IDLE_CONNECTIONS_EVICTION_INTERVAL`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
[Duration](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html) [🛈](#duration-note-anchor)
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`1M`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.http-client.max-response-size`
|
|
||||||
|
|
||||||
If a feed is larger than this, it will be discarded to prevent memory issues while parsing the feed.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_HTTP_CLIENT_MAX_RESPONSE_SIZE`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
MemorySize [🛈](#memory-size-note-anchor)
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`5M`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.http-client.block-local-addresses`
|
|
||||||
|
|
||||||
Prevent access to local addresses to mitigate server-side request forgery (SSRF) attacks, which could potentially expose internal
|
|
||||||
resources.
|
|
||||||
|
|
||||||
You may want to disable this if you subscribe to feeds that are only available on your local network and you trust all users of
|
|
||||||
your CommaFeed instance.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_HTTP_CLIENT_BLOCK_LOCAL_ADDRESSES`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
boolean
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`true`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th align="left" colspan="3">
|
|
||||||
HTTP client cache configuration
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.http-client.cache.enabled`
|
|
||||||
|
|
||||||
Whether to enable the cache. This cache is used to avoid spamming feeds in short bursts (e.g. when subscribing to a feed for the
|
|
||||||
first time or when clicking "fetch all my feeds now").
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_HTTP_CLIENT_CACHE_ENABLED`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
boolean
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`true`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.http-client.cache.maximum-memory-size`
|
|
||||||
|
|
||||||
Maximum amount of memory the cache can use.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_HTTP_CLIENT_CACHE_MAXIMUM_MEMORY_SIZE`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
MemorySize [🛈](#memory-size-note-anchor)
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`10M`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.http-client.cache.expiration`
|
|
||||||
|
|
||||||
Duration after which an entry is removed from the cache.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_HTTP_CLIENT_CACHE_EXPIRATION`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
[Duration](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html) [🛈](#duration-note-anchor)
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`1M`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th align="left" colspan="3">
|
|
||||||
Feed refresh engine settings
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.feed-refresh.interval`
|
|
||||||
|
|
||||||
Default amount of time CommaFeed will wait before refreshing a feed.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_FEED_REFRESH_INTERVAL`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
[Duration](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html) [🛈](#duration-note-anchor)
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`5M`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.feed-refresh.max-interval`
|
|
||||||
|
|
||||||
Maximum amount of time CommaFeed will wait before refreshing a feed. This is used as an upper bound when:
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li>an error occurs while refreshing a feed and we're backing off exponentially</li>
|
|
||||||
<li>we receive a Cache-Control header from the feed</li>
|
|
||||||
<li>we receive a Retry-After header from the feed</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_FEED_REFRESH_MAX_INTERVAL`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
[Duration](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html) [🛈](#duration-note-anchor)
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`4H`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.feed-refresh.interval-empirical`
|
|
||||||
|
|
||||||
If enabled, CommaFeed will calculate the next refresh time based on the feed's average time between entries and the time since
|
|
||||||
the last entry was published. The interval will be sometimes between the default refresh interval
|
|
||||||
(`commafeed.feed-refresh.interval`) and the maximum refresh interval (`commafeed.feed-refresh.max-interval`).
|
|
||||||
|
|
||||||
See <code>FeedRefreshIntervalCalculator</code> for details.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_FEED_REFRESH_INTERVAL_EMPIRICAL`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
boolean
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`true`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.feed-refresh.http-threads`
|
|
||||||
|
|
||||||
Amount of http threads used to fetch feeds.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_FEED_REFRESH_HTTP_THREADS`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
int
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`3`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.feed-refresh.database-threads`
|
|
||||||
|
|
||||||
Amount of threads used to insert new entries in the database.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_FEED_REFRESH_DATABASE_THREADS`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
int
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`1`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.feed-refresh.user-inactivity-period`
|
|
||||||
|
|
||||||
Duration after which a user is considered inactive. Feeds for inactive users are not refreshed until they log in again.
|
|
||||||
|
|
||||||
0 to disable.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_FEED_REFRESH_USER_INACTIVITY_PERIOD`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
[Duration](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html) [🛈](#duration-note-anchor)
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`0S`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.feed-refresh.filtering-expression-evaluation-timeout`
|
|
||||||
|
|
||||||
Duration after which the evaluation of a filtering expresion to mark an entry as read is considered to have timed out.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_FEED_REFRESH_FILTERING_EXPRESSION_EVALUATION_TIMEOUT`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
[Duration](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html) [🛈](#duration-note-anchor)
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`500MS`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.feed-refresh.force-refresh-cooldown-duration`
|
|
||||||
|
|
||||||
Duration after which the "Fetch all my feeds now" action is available again after use to avoid spamming feeds.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_FEED_REFRESH_FORCE_REFRESH_COOLDOWN_DURATION`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
[Duration](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html) [🛈](#duration-note-anchor)
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`0S`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th align="left" colspan="3">
|
|
||||||
Feed refresh engine error handling settings
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.feed-refresh.errors.retries-before-backoff`
|
|
||||||
|
|
||||||
Number of retries before backoff is applied.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_FEED_REFRESH_ERRORS_RETRIES_BEFORE_BACKOFF`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
int
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`3`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.feed-refresh.errors.backoff-interval`
|
|
||||||
|
|
||||||
Duration to wait before retrying after an error. Will be multiplied by the number of errors since the last successful fetch.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_FEED_REFRESH_ERRORS_BACKOFF_INTERVAL`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
[Duration](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html) [🛈](#duration-note-anchor)
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`1H`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th align="left" colspan="3">
|
|
||||||
Database settings
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.database.query-timeout`
|
|
||||||
|
|
||||||
Timeout applied to all database queries.
|
|
||||||
|
|
||||||
0 to disable.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_DATABASE_QUERY_TIMEOUT`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
[Duration](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html) [🛈](#duration-note-anchor)
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`0S`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th align="left" colspan="3">
|
|
||||||
Database cleanup settings
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.database.cleanup.entries-max-age`
|
|
||||||
|
|
||||||
Maximum age of feed entries in the database. Older entries will be deleted.
|
|
||||||
|
|
||||||
0 to disable.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_DATABASE_CLEANUP_ENTRIES_MAX_AGE`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
[Duration](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html) [🛈](#duration-note-anchor)
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`365D`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.database.cleanup.statuses-max-age`
|
|
||||||
|
|
||||||
Maximum age of feed entry statuses (read/unread) in the database. Older statuses will be deleted.
|
|
||||||
|
|
||||||
0 to disable.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_DATABASE_CLEANUP_STATUSES_MAX_AGE`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
[Duration](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html) [🛈](#duration-note-anchor)
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`0S`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.database.cleanup.max-feed-capacity`
|
|
||||||
|
|
||||||
Maximum number of entries per feed to keep in the database.
|
|
||||||
|
|
||||||
0 to disable.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_DATABASE_CLEANUP_MAX_FEED_CAPACITY`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
int
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`500`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.database.cleanup.max-feeds-per-user`
|
|
||||||
|
|
||||||
Limit the number of feeds a user can subscribe to.
|
|
||||||
|
|
||||||
0 to disable.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_DATABASE_CLEANUP_MAX_FEEDS_PER_USER`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
int
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`0`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.database.cleanup.batch-size`
|
|
||||||
|
|
||||||
Rows to delete per query while cleaning up old entries.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_DATABASE_CLEANUP_BATCH_SIZE`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
int
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`100`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th align="left" colspan="3">
|
|
||||||
Users settings
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.users.allow-registrations`
|
|
||||||
|
|
||||||
Whether to let users create accounts for themselves.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_USERS_ALLOW_REGISTRATIONS`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
boolean
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`false`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.users.strict-password-policy`
|
|
||||||
|
|
||||||
Whether to enable strict password validation (1 uppercase char, 1 lowercase char, 1 digit, 1 special char).
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_USERS_STRICT_PASSWORD_POLICY`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
boolean
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`true`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.users.create-demo-account`
|
|
||||||
|
|
||||||
Whether to create a demo account the first time the app starts.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_USERS_CREATE_DEMO_ACCOUNT`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
boolean
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`false`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th align="left" colspan="3">
|
|
||||||
Websocket settings
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.websocket.enabled`
|
|
||||||
|
|
||||||
Enable websocket connection so the server can notify web clients that there are new entries for feeds.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_WEBSOCKET_ENABLED`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
boolean
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`true`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.websocket.ping-interval`
|
|
||||||
|
|
||||||
Interval at which the client will send a ping message on the websocket to keep the connection alive.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_WEBSOCKET_PING_INTERVAL`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
[Duration](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html) [🛈](#duration-note-anchor)
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`15M`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`commafeed.websocket.tree-reload-interval`
|
|
||||||
|
|
||||||
If the websocket connection is disabled or the connection is lost, the client will reload the feed tree at this interval.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Environment variable: `COMMAFEED_WEBSOCKET_TREE_RELOAD_INTERVAL`</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
[Duration](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html) [🛈](#duration-note-anchor)
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
`30S`
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<a name="duration-note-anchor"></a>
|
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> ### About the Duration format
|
|
||||||
>
|
|
||||||
> To write duration values, use the standard `java.time.Duration` format.
|
|
||||||
> See the [Duration#parse()](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html#parse(java.lang.CharSequence)) Java API documentation] for more information.
|
|
||||||
>
|
|
||||||
> You can also use a simplified format, starting with a number:
|
|
||||||
>
|
|
||||||
> * If the value is only a number, it represents time in seconds.
|
|
||||||
> * If the value is a number followed by `ms`, it represents time in milliseconds.
|
|
||||||
>
|
|
||||||
> In other cases, the simplified format is translated to the `java.time.Duration` format for parsing:
|
|
||||||
>
|
|
||||||
> * If the value is a number followed by `h`, `m`, or `s`, it is prefixed with `PT`.
|
|
||||||
> * If the value is a number followed by `d`, it is prefixed with `P`.
|
|
||||||
<a name="memory-size-note-anchor"></a>
|
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> ### About the MemorySize format
|
|
||||||
>
|
|
||||||
> A size configuration option recognizes strings in this format (shown as a regular expression): `[0-9]+[KkMmGgTtPpEeZzYy]?`.
|
|
||||||
>
|
|
||||||
> If no suffix is given, assume bytes.
|
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
mvn exec:java -e -Dexec.classpathScope=test -Dexec.mainClass=com.microsoft.playwright.CLI -Dexec.args="codegen localhost:8082"
|
mvn exec:java -e -Dexec.classpathScope=test -Dexec.mainClass=com.microsoft.playwright.CLI -Dexec.args="codegen localhost:8082"
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,21 +1,21 @@
|
|||||||
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.2.0 https://maven.apache.org/xsd/assembly-2.2.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.2.0 https://maven.apache.org/xsd/assembly-2.2.0.xsd">
|
||||||
|
|
||||||
<id>zip-quarkus-app</id>
|
<id>zip-quarkus-app</id>
|
||||||
|
|
||||||
<includeBaseDirectory>true</includeBaseDirectory>
|
<includeBaseDirectory>true</includeBaseDirectory>
|
||||||
<baseDirectory>commafeed-${project.version}-${build.database}</baseDirectory>
|
<baseDirectory>commafeed-${project.version}-${build.database}</baseDirectory>
|
||||||
|
|
||||||
<formats>
|
<formats>
|
||||||
<format>zip</format>
|
<format>zip</format>
|
||||||
</formats>
|
</formats>
|
||||||
<fileSets>
|
<fileSets>
|
||||||
<fileSet>
|
<fileSet>
|
||||||
<directory>${project.build.directory}/quarkus-app</directory>
|
<directory>${project.build.directory}/quarkus-app</directory>
|
||||||
<outputDirectory>/</outputDirectory>
|
<outputDirectory>/</outputDirectory>
|
||||||
<includes>
|
<includes>
|
||||||
<include>**/*</include>
|
<include>**/*</include>
|
||||||
</includes>
|
</includes>
|
||||||
</fileSet>
|
</fileSet>
|
||||||
</fileSets>
|
</fileSets>
|
||||||
</assembly>
|
</assembly>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM ibm-semeru-runtimes:open-21.0.5_11-jre
|
FROM ibm-semeru-runtimes:open-21.0.6_7-jre@sha256:fc0d0c8b2ea5b97bc362e8f90151ed62739cb6f758938203ea0370bc6b9c6659
|
||||||
EXPOSE 8082
|
EXPOSE 8082
|
||||||
|
|
||||||
RUN mkdir -p /commafeed/data
|
RUN mkdir -p /commafeed/data
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM debian:12.9
|
FROM debian:12.10@sha256:18023f131f52fc3ea21973cabffe0b216c60b417fd2478e94d9d59981ebba6af
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
|
|
||||||
EXPOSE 8082
|
EXPOSE 8082
|
||||||
|
|||||||
@@ -1,95 +1,95 @@
|
|||||||
# CommaFeed
|
# CommaFeed
|
||||||
|
|
||||||
Official docker images for https://github.com/Athou/commafeed/
|
Official docker images for https://github.com/Athou/commafeed/
|
||||||
|
|
||||||
## Quickstart
|
## Quickstart
|
||||||
|
|
||||||
Start CommaFeed with a H2 embedded database. Then login as `admin/admin` on http://localhost:8082/
|
Start CommaFeed with a H2 embedded database. Then login as `admin/admin` on http://localhost:8082/
|
||||||
|
|
||||||
### docker
|
### 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/db:/commafeed/data --memory 256M athou/commafeed:latest-h2`
|
||||||
|
|
||||||
### docker-compose
|
### docker-compose
|
||||||
|
|
||||||
```
|
```
|
||||||
services:
|
services:
|
||||||
commafeed:
|
commafeed:
|
||||||
image: athou/commafeed:latest-h2
|
image: athou/commafeed:latest-h2
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
- /path/to/commafeed/db:/commafeed/data
|
- /path/to/commafeed/db:/commafeed/data
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
memory: 256M
|
memory: 256M
|
||||||
ports:
|
ports:
|
||||||
- 8082:8082
|
- 8082:8082
|
||||||
```
|
```
|
||||||
|
|
||||||
## Advanced
|
## Advanced
|
||||||
|
|
||||||
While using the H2 embedded database is perfectly fine for small instances, you may want to have more control over the
|
While using the H2 embedded database is perfectly fine for small instances, you may want to have more control over the
|
||||||
database. Here's an example that uses PostgreSQL (note the image tag change from `latest-h2` to `latest-postgresql`):
|
database. Here's an example that uses PostgreSQL (note the image tag change from `latest-h2` to `latest-postgresql`):
|
||||||
|
|
||||||
```
|
```
|
||||||
services:
|
services:
|
||||||
commafeed:
|
commafeed:
|
||||||
image: athou/commafeed:latest-postgresql
|
image: athou/commafeed:latest-postgresql
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
- QUARKUS_DATASOURCE_JDBC_URL=jdbc:postgresql://postgresql:5432/commafeed
|
- QUARKUS_DATASOURCE_JDBC_URL=jdbc:postgresql://postgresql:5432/commafeed
|
||||||
- QUARKUS_DATASOURCE_USERNAME=commafeed
|
- QUARKUS_DATASOURCE_USERNAME=commafeed
|
||||||
- QUARKUS_DATASOURCE_PASSWORD=commafeed
|
- QUARKUS_DATASOURCE_PASSWORD=commafeed
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
memory: 256M
|
memory: 256M
|
||||||
ports:
|
ports:
|
||||||
- 8082:8082
|
- 8082:8082
|
||||||
|
|
||||||
postgresql:
|
postgresql:
|
||||||
image: postgres:latest
|
image: postgres:latest
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: commafeed
|
POSTGRES_USER: commafeed
|
||||||
POSTGRES_PASSWORD: commafeed
|
POSTGRES_PASSWORD: commafeed
|
||||||
POSTGRES_DB: commafeed
|
POSTGRES_DB: commafeed
|
||||||
volumes:
|
volumes:
|
||||||
- /path/to/commafeed/db:/var/lib/postgresql/data
|
- /path/to/commafeed/db:/var/lib/postgresql/data
|
||||||
```
|
```
|
||||||
|
|
||||||
CommaFeed also supports:
|
CommaFeed also supports:
|
||||||
|
|
||||||
- MySQL:
|
- MySQL:
|
||||||
`QUARKUS_DATASOURCE_JDBC_URL=jdbc:mysql://localhost/commafeed?autoReconnect=true&failOverReadOnly=false&maxReconnects=20&rewriteBatchedStatements=true&timezone=UTC`
|
`QUARKUS_DATASOURCE_JDBC_URL=jdbc:mysql://localhost/commafeed?autoReconnect=true&failOverReadOnly=false&maxReconnects=20&rewriteBatchedStatements=true&timezone=UTC`
|
||||||
- MariaDB:
|
- MariaDB:
|
||||||
`QUARKUS_DATASOURCE_JDBC_URL=jdbc:mariadb://localhost/commafeed?autoReconnect=true&failOverReadOnly=false&maxReconnects=20&rewriteBatchedStatements=true&timezone=UTC`
|
`QUARKUS_DATASOURCE_JDBC_URL=jdbc:mariadb://localhost/commafeed?autoReconnect=true&failOverReadOnly=false&maxReconnects=20&rewriteBatchedStatements=true&timezone=UTC`
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
All [CommaFeed settings](https://github.com/Athou/commafeed/blob/master/commafeed-server/doc/commafeed.md) are
|
All [CommaFeed settings](https://athou.github.io/commafeed/documentation) are
|
||||||
optional and have sensible default values.
|
optional and have sensible default values.
|
||||||
|
|
||||||
Settings are overrideable with environment variables. For instance, `commafeed.feed-refresh.interval-empirical` can be
|
Settings are overrideable with environment variables. For instance, `commafeed.feed-refresh.interval-empirical` can be
|
||||||
set with the `COMMAFEED_FEED_REFRESH_INTERVAL_EMPIRICAL` variable.
|
set with the `COMMAFEED_FEED_REFRESH_INTERVAL_EMPIRICAL` variable.
|
||||||
|
|
||||||
When logging in, credentials are stored in an encrypted cookie. The encryption key is randomly generated at startup,
|
When logging in, credentials are stored in an encrypted cookie. The encryption key is randomly generated at startup,
|
||||||
meaning that you will have to log back in after each restart of the application. To prevent this, you can set the
|
meaning that you will have to log back in after each restart of the application. To prevent this, you can set the
|
||||||
`QUARKUS_HTTP_AUTH_SESSION_ENCRYPTION_KEY` variable to a fixed value (min. 16 characters).
|
`QUARKUS_HTTP_AUTH_SESSION_ENCRYPTION_KEY` variable to a fixed value (min. 16 characters).
|
||||||
All other Quarkus settings can be found [here](https://quarkus.io/guides/all-config).
|
All other Quarkus settings can be found [here](https://quarkus.io/guides/all-config).
|
||||||
|
|
||||||
### Updates
|
### Updates
|
||||||
|
|
||||||
When CommaFeed is up and running, you can subscribe to [this feed](https://github.com/Athou/commafeed/releases.atom) to be notified of new releases.
|
When CommaFeed is up and running, you can subscribe to [this feed](https://github.com/Athou/commafeed/releases.atom) to be notified of new releases.
|
||||||
|
|
||||||
## Docker tags
|
## Docker tags
|
||||||
|
|
||||||
Tags are of the form `<version>-<database>[-jvm]` where:
|
Tags are of the form `<version>-<database>[-jvm]` where:
|
||||||
|
|
||||||
- `<version>` is either:
|
- `<version>` is either:
|
||||||
- a specific CommaFeed version (e.g. `5.0.0`)
|
- a specific CommaFeed version (e.g. `5.0.0`)
|
||||||
- `latest` (always points to the latest version)
|
- `latest` (always points to the latest version)
|
||||||
- `master` (always points to the latest git commit)
|
- `master` (always points to the latest git commit)
|
||||||
- `<database>` is the database to use (`h2`, `postgresql`, `mysql` or `mariadb`)
|
- `<database>` is the database to use (`h2`, `postgresql`, `mysql` or `mariadb`)
|
||||||
- `-jvm` is optional and indicates that CommaFeed is running on a JVM, and not compiled natively.
|
- `-jvm` is optional and indicates that CommaFeed is running on a JVM, and not compiled natively.
|
||||||
|
|||||||
@@ -1,40 +1,41 @@
|
|||||||
package com.commafeed;
|
package com.commafeed;
|
||||||
|
|
||||||
import com.commafeed.backend.feed.FeedRefreshEngine;
|
import jakarta.enterprise.event.Observes;
|
||||||
import com.commafeed.backend.service.db.DatabaseStartupService;
|
import jakarta.inject.Singleton;
|
||||||
import com.commafeed.backend.task.TaskScheduler;
|
|
||||||
import com.commafeed.security.password.PasswordConstraintValidator;
|
import com.commafeed.backend.feed.FeedRefreshEngine;
|
||||||
|
import com.commafeed.backend.service.db.DatabaseStartupService;
|
||||||
import io.quarkus.runtime.ShutdownEvent;
|
import com.commafeed.backend.task.TaskScheduler;
|
||||||
import io.quarkus.runtime.StartupEvent;
|
import com.commafeed.security.password.PasswordConstraintValidator;
|
||||||
import jakarta.enterprise.event.Observes;
|
|
||||||
import jakarta.inject.Singleton;
|
import io.quarkus.runtime.ShutdownEvent;
|
||||||
import lombok.RequiredArgsConstructor;
|
import io.quarkus.runtime.StartupEvent;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
@Singleton
|
|
||||||
@RequiredArgsConstructor
|
@Singleton
|
||||||
public class CommaFeedApplication {
|
@RequiredArgsConstructor
|
||||||
|
public class CommaFeedApplication {
|
||||||
public static final String USERNAME_ADMIN = "admin";
|
|
||||||
public static final String USERNAME_DEMO = "demo";
|
public static final String USERNAME_ADMIN = "admin";
|
||||||
|
public static final String USERNAME_DEMO = "demo";
|
||||||
private final DatabaseStartupService databaseStartupService;
|
|
||||||
private final FeedRefreshEngine feedRefreshEngine;
|
private final DatabaseStartupService databaseStartupService;
|
||||||
private final TaskScheduler taskScheduler;
|
private final FeedRefreshEngine feedRefreshEngine;
|
||||||
private final CommaFeedConfiguration config;
|
private final TaskScheduler taskScheduler;
|
||||||
|
private final CommaFeedConfiguration config;
|
||||||
public void start(@Observes StartupEvent ev) {
|
|
||||||
PasswordConstraintValidator.setStrict(config.users().strictPasswordPolicy());
|
public void start(@Observes StartupEvent ev) {
|
||||||
|
PasswordConstraintValidator.setStrict(config.users().strictPasswordPolicy());
|
||||||
databaseStartupService.populateInitialData();
|
|
||||||
|
databaseStartupService.populateInitialData();
|
||||||
feedRefreshEngine.start();
|
|
||||||
taskScheduler.start();
|
feedRefreshEngine.start();
|
||||||
}
|
taskScheduler.start();
|
||||||
|
}
|
||||||
public void stop(@Observes ShutdownEvent ev) {
|
|
||||||
feedRefreshEngine.stop();
|
public void stop(@Observes ShutdownEvent ev) {
|
||||||
taskScheduler.stop();
|
feedRefreshEngine.stop();
|
||||||
}
|
taskScheduler.stop();
|
||||||
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,365 +1,366 @@
|
|||||||
package com.commafeed;
|
package com.commafeed;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import com.commafeed.backend.feed.FeedRefreshIntervalCalculator;
|
import jakarta.validation.constraints.Min;
|
||||||
|
import jakarta.validation.constraints.Positive;
|
||||||
import io.quarkus.runtime.annotations.ConfigDocSection;
|
|
||||||
import io.quarkus.runtime.annotations.ConfigPhase;
|
import com.commafeed.backend.feed.FeedRefreshIntervalCalculator;
|
||||||
import io.quarkus.runtime.annotations.ConfigRoot;
|
|
||||||
import io.quarkus.runtime.configuration.MemorySize;
|
import io.quarkus.runtime.annotations.ConfigDocSection;
|
||||||
import io.smallrye.config.ConfigMapping;
|
import io.quarkus.runtime.annotations.ConfigPhase;
|
||||||
import io.smallrye.config.WithDefault;
|
import io.quarkus.runtime.annotations.ConfigRoot;
|
||||||
import jakarta.validation.constraints.Min;
|
import io.quarkus.runtime.configuration.MemorySize;
|
||||||
import jakarta.validation.constraints.Positive;
|
import io.smallrye.config.ConfigMapping;
|
||||||
|
import io.smallrye.config.WithDefault;
|
||||||
/**
|
|
||||||
* CommaFeed configuration
|
/**
|
||||||
*
|
* CommaFeed configuration
|
||||||
* Default values are for production, they can be overridden in application.properties for other profiles
|
*
|
||||||
*/
|
* Default values are for production, they can be overridden in application.properties for other profiles
|
||||||
@ConfigMapping(prefix = "commafeed")
|
*/
|
||||||
@ConfigRoot(phase = ConfigPhase.RUN_TIME)
|
@ConfigMapping(prefix = "commafeed")
|
||||||
public interface CommaFeedConfiguration {
|
@ConfigRoot(phase = ConfigPhase.RUN_TIME)
|
||||||
/**
|
public interface CommaFeedConfiguration {
|
||||||
* Whether to expose a robots.txt file that disallows web crawlers and search engine indexers.
|
/**
|
||||||
*/
|
* Whether to expose a robots.txt file that disallows web crawlers and search engine indexers.
|
||||||
@WithDefault("true")
|
*/
|
||||||
boolean hideFromWebCrawlers();
|
@WithDefault("true")
|
||||||
|
boolean hideFromWebCrawlers();
|
||||||
/**
|
|
||||||
* If enabled, images in feed entries will be proxied through the server instead of accessed directly by the browser.
|
/**
|
||||||
*
|
* If enabled, images in feed entries will be proxied through the server instead of accessed directly by the browser.
|
||||||
* This is useful if commafeed is accessed through a restricting proxy that blocks some feeds that are followed.
|
*
|
||||||
*/
|
* This is useful if commafeed is accessed through a restricting proxy that blocks some feeds that are followed.
|
||||||
@WithDefault("false")
|
*/
|
||||||
boolean imageProxyEnabled();
|
@WithDefault("false")
|
||||||
|
boolean imageProxyEnabled();
|
||||||
/**
|
|
||||||
* Enable password recovery via email.
|
/**
|
||||||
*
|
* Enable password recovery via email.
|
||||||
* Quarkus mailer will need to be configured.
|
*
|
||||||
*/
|
* Quarkus mailer will need to be configured.
|
||||||
@WithDefault("false")
|
*/
|
||||||
boolean passwordRecoveryEnabled();
|
@WithDefault("false")
|
||||||
|
boolean passwordRecoveryEnabled();
|
||||||
/**
|
|
||||||
* Message displayed in a notification at the bottom of the page.
|
/**
|
||||||
*/
|
* Message displayed in a notification at the bottom of the page.
|
||||||
Optional<String> announcement();
|
*/
|
||||||
|
Optional<String> announcement();
|
||||||
/**
|
|
||||||
* Google Analytics tracking code.
|
/**
|
||||||
*/
|
* Google Analytics tracking code.
|
||||||
Optional<String> googleAnalyticsTrackingCode();
|
*/
|
||||||
|
Optional<String> googleAnalyticsTrackingCode();
|
||||||
/**
|
|
||||||
* Google Auth key for fetching Youtube channel favicons.
|
/**
|
||||||
*/
|
* Google Auth key for fetching Youtube channel favicons.
|
||||||
Optional<String> googleAuthKey();
|
*/
|
||||||
|
Optional<String> googleAuthKey();
|
||||||
/**
|
|
||||||
* HTTP client configuration
|
/**
|
||||||
*/
|
* HTTP client configuration
|
||||||
@ConfigDocSection
|
*/
|
||||||
HttpClient httpClient();
|
@ConfigDocSection
|
||||||
|
HttpClient httpClient();
|
||||||
/**
|
|
||||||
* Feed refresh engine settings.
|
/**
|
||||||
*/
|
* Feed refresh engine settings.
|
||||||
@ConfigDocSection
|
*/
|
||||||
FeedRefresh feedRefresh();
|
@ConfigDocSection
|
||||||
|
FeedRefresh feedRefresh();
|
||||||
/**
|
|
||||||
* Database settings.
|
/**
|
||||||
*/
|
* Database settings.
|
||||||
@ConfigDocSection
|
*/
|
||||||
Database database();
|
@ConfigDocSection
|
||||||
|
Database database();
|
||||||
/**
|
|
||||||
* Users settings.
|
/**
|
||||||
*/
|
* Users settings.
|
||||||
@ConfigDocSection
|
*/
|
||||||
Users users();
|
@ConfigDocSection
|
||||||
|
Users users();
|
||||||
/**
|
|
||||||
* Websocket settings.
|
/**
|
||||||
*/
|
* Websocket settings.
|
||||||
@ConfigDocSection
|
*/
|
||||||
Websocket websocket();
|
@ConfigDocSection
|
||||||
|
Websocket websocket();
|
||||||
interface HttpClient {
|
|
||||||
/**
|
interface HttpClient {
|
||||||
* User-Agent string that will be used by the http client, leave empty for the default one.
|
/**
|
||||||
*/
|
* User-Agent string that will be used by the http client, leave empty for the default one.
|
||||||
Optional<String> userAgent();
|
*/
|
||||||
|
Optional<String> userAgent();
|
||||||
/**
|
|
||||||
* Time to wait for a connection to be established.
|
/**
|
||||||
*/
|
* Time to wait for a connection to be established.
|
||||||
@WithDefault("5s")
|
*/
|
||||||
Duration connectTimeout();
|
@WithDefault("5s")
|
||||||
|
Duration connectTimeout();
|
||||||
/**
|
|
||||||
* Time to wait for SSL handshake to complete.
|
/**
|
||||||
*/
|
* Time to wait for SSL handshake to complete.
|
||||||
@WithDefault("5s")
|
*/
|
||||||
Duration sslHandshakeTimeout();
|
@WithDefault("5s")
|
||||||
|
Duration sslHandshakeTimeout();
|
||||||
/**
|
|
||||||
* Time to wait between two packets before timeout.
|
/**
|
||||||
*/
|
* Time to wait between two packets before timeout.
|
||||||
@WithDefault("10s")
|
*/
|
||||||
Duration socketTimeout();
|
@WithDefault("10s")
|
||||||
|
Duration socketTimeout();
|
||||||
/**
|
|
||||||
* Time to wait for the full response to be received.
|
/**
|
||||||
*/
|
* Time to wait for the full response to be received.
|
||||||
@WithDefault("10s")
|
*/
|
||||||
Duration responseTimeout();
|
@WithDefault("10s")
|
||||||
|
Duration responseTimeout();
|
||||||
/**
|
|
||||||
* Time to live for a connection in the pool.
|
/**
|
||||||
*/
|
* Time to live for a connection in the pool.
|
||||||
@WithDefault("30s")
|
*/
|
||||||
Duration connectionTimeToLive();
|
@WithDefault("30s")
|
||||||
|
Duration connectionTimeToLive();
|
||||||
/**
|
|
||||||
* Time between eviction runs for idle connections.
|
/**
|
||||||
*/
|
* Time between eviction runs for idle connections.
|
||||||
@WithDefault("1m")
|
*/
|
||||||
Duration idleConnectionsEvictionInterval();
|
@WithDefault("1m")
|
||||||
|
Duration idleConnectionsEvictionInterval();
|
||||||
/**
|
|
||||||
* If a feed is larger than this, it will be discarded to prevent memory issues while parsing the feed.
|
/**
|
||||||
*/
|
* If a feed is larger than this, it will be discarded to prevent memory issues while parsing the feed.
|
||||||
@WithDefault("5M")
|
*/
|
||||||
MemorySize maxResponseSize();
|
@WithDefault("5M")
|
||||||
|
MemorySize maxResponseSize();
|
||||||
/**
|
|
||||||
* Prevent access to local addresses to mitigate server-side request forgery (SSRF) attacks, which could potentially expose internal
|
/**
|
||||||
* resources.
|
* Prevent access to local addresses to mitigate server-side request forgery (SSRF) attacks, which could potentially expose internal
|
||||||
*
|
* resources.
|
||||||
* You may want to disable this if you subscribe to feeds that are only available on your local network and you trust all users of
|
*
|
||||||
* your CommaFeed instance.
|
* You may want to disable this if you subscribe to feeds that are only available on your local network and you trust all users of
|
||||||
*/
|
* your CommaFeed instance.
|
||||||
@WithDefault("true")
|
*/
|
||||||
boolean blockLocalAddresses();
|
@WithDefault("true")
|
||||||
|
boolean blockLocalAddresses();
|
||||||
/**
|
|
||||||
* HTTP client cache configuration
|
/**
|
||||||
*/
|
* HTTP client cache configuration
|
||||||
@ConfigDocSection
|
*/
|
||||||
HttpClientCache cache();
|
@ConfigDocSection
|
||||||
}
|
HttpClientCache cache();
|
||||||
|
}
|
||||||
interface HttpClientCache {
|
|
||||||
/**
|
interface HttpClientCache {
|
||||||
* Whether to enable the cache. This cache is used to avoid spamming feeds in short bursts (e.g. when subscribing to a feed for the
|
/**
|
||||||
* first time or when clicking "fetch all my feeds now").
|
* Whether to enable the cache. This cache is used to avoid spamming feeds in short bursts (e.g. when subscribing to a feed for the
|
||||||
*/
|
* first time or when clicking "fetch all my feeds now").
|
||||||
@WithDefault("true")
|
*/
|
||||||
boolean enabled();
|
@WithDefault("true")
|
||||||
|
boolean enabled();
|
||||||
/**
|
|
||||||
* Maximum amount of memory the cache can use.
|
/**
|
||||||
*/
|
* Maximum amount of memory the cache can use.
|
||||||
@WithDefault("10M")
|
*/
|
||||||
MemorySize maximumMemorySize();
|
@WithDefault("10M")
|
||||||
|
MemorySize maximumMemorySize();
|
||||||
/**
|
|
||||||
* Duration after which an entry is removed from the cache.
|
/**
|
||||||
*/
|
* Duration after which an entry is removed from the cache.
|
||||||
@WithDefault("1m")
|
*/
|
||||||
Duration expiration();
|
@WithDefault("1m")
|
||||||
}
|
Duration expiration();
|
||||||
|
}
|
||||||
interface FeedRefresh {
|
|
||||||
/**
|
interface FeedRefresh {
|
||||||
* Default amount of time CommaFeed will wait before refreshing a feed.
|
/**
|
||||||
*/
|
* Default amount of time CommaFeed will wait before refreshing a feed.
|
||||||
@WithDefault("5m")
|
*/
|
||||||
Duration interval();
|
@WithDefault("5m")
|
||||||
|
Duration interval();
|
||||||
/**
|
|
||||||
* Maximum amount of time CommaFeed will wait before refreshing a feed. This is used as an upper bound when:
|
/**
|
||||||
*
|
* Maximum amount of time CommaFeed will wait before refreshing a feed. This is used as an upper bound when:
|
||||||
* <ul>
|
*
|
||||||
* <li>an error occurs while refreshing a feed and we're backing off exponentially</li>
|
* <ul>
|
||||||
* <li>we receive a Cache-Control header from the feed</li>
|
* <li>an error occurs while refreshing a feed and we're backing off exponentially</li>
|
||||||
* <li>we receive a Retry-After header from the feed</li>
|
* <li>we receive a Cache-Control header from the feed</li>
|
||||||
* </ul>
|
* <li>we receive a Retry-After header from the feed</li>
|
||||||
*/
|
* </ul>
|
||||||
@WithDefault("4h")
|
*/
|
||||||
Duration maxInterval();
|
@WithDefault("4h")
|
||||||
|
Duration maxInterval();
|
||||||
/**
|
|
||||||
* If enabled, CommaFeed will calculate the next refresh time based on the feed's average time between entries and the time since
|
/**
|
||||||
* the last entry was published. The interval will be sometimes between the default refresh interval
|
* If enabled, CommaFeed will calculate the next refresh time based on the feed's average time between entries and the time since
|
||||||
* (`commafeed.feed-refresh.interval`) and the maximum refresh interval (`commafeed.feed-refresh.max-interval`).
|
* the last entry was published. The interval will be sometimes between the default refresh interval
|
||||||
*
|
* (`commafeed.feed-refresh.interval`) and the maximum refresh interval (`commafeed.feed-refresh.max-interval`).
|
||||||
* See {@link FeedRefreshIntervalCalculator} for details.
|
*
|
||||||
*/
|
* See {@link FeedRefreshIntervalCalculator} for details.
|
||||||
@WithDefault("true")
|
*/
|
||||||
boolean intervalEmpirical();
|
@WithDefault("true")
|
||||||
|
boolean intervalEmpirical();
|
||||||
/**
|
|
||||||
* Feed refresh engine error handling settings.
|
/**
|
||||||
*/
|
* Feed refresh engine error handling settings.
|
||||||
@ConfigDocSection
|
*/
|
||||||
FeedRefreshErrorHandling errors();
|
@ConfigDocSection
|
||||||
|
FeedRefreshErrorHandling errors();
|
||||||
/**
|
|
||||||
* Amount of http threads used to fetch feeds.
|
/**
|
||||||
*/
|
* Amount of http threads used to fetch feeds.
|
||||||
@Min(1)
|
*/
|
||||||
@WithDefault("3")
|
@Min(1)
|
||||||
int httpThreads();
|
@WithDefault("3")
|
||||||
|
int httpThreads();
|
||||||
/**
|
|
||||||
* Amount of threads used to insert new entries in the database.
|
/**
|
||||||
*/
|
* Amount of threads used to insert new entries in the database.
|
||||||
@Min(1)
|
*/
|
||||||
@WithDefault("1")
|
@Min(1)
|
||||||
int databaseThreads();
|
@WithDefault("1")
|
||||||
|
int databaseThreads();
|
||||||
/**
|
|
||||||
* Duration after which a user is considered inactive. Feeds for inactive users are not refreshed until they log in again.
|
/**
|
||||||
*
|
* Duration after which a user is considered inactive. Feeds for inactive users are not refreshed until they log in again.
|
||||||
* 0 to disable.
|
*
|
||||||
*/
|
* 0 to disable.
|
||||||
@WithDefault("0")
|
*/
|
||||||
Duration userInactivityPeriod();
|
@WithDefault("0")
|
||||||
|
Duration userInactivityPeriod();
|
||||||
/**
|
|
||||||
* Duration after which the evaluation of a filtering expresion to mark an entry as read is considered to have timed out.
|
/**
|
||||||
*/
|
* Duration after which the evaluation of a filtering expresion to mark an entry as read is considered to have timed out.
|
||||||
@WithDefault("500ms")
|
*/
|
||||||
Duration filteringExpressionEvaluationTimeout();
|
@WithDefault("500ms")
|
||||||
|
Duration filteringExpressionEvaluationTimeout();
|
||||||
/**
|
|
||||||
* Duration after which the "Fetch all my feeds now" action is available again after use to avoid spamming feeds.
|
/**
|
||||||
*/
|
* Duration after which the "Fetch all my feeds now" action is available again after use to avoid spamming feeds.
|
||||||
@WithDefault("0")
|
*/
|
||||||
Duration forceRefreshCooldownDuration();
|
@WithDefault("0")
|
||||||
}
|
Duration forceRefreshCooldownDuration();
|
||||||
|
}
|
||||||
interface FeedRefreshErrorHandling {
|
|
||||||
/**
|
interface FeedRefreshErrorHandling {
|
||||||
* Number of retries before backoff is applied.
|
/**
|
||||||
*/
|
* Number of retries before backoff is applied.
|
||||||
@Min(0)
|
*/
|
||||||
@WithDefault("3")
|
@Min(0)
|
||||||
int retriesBeforeBackoff();
|
@WithDefault("3")
|
||||||
|
int retriesBeforeBackoff();
|
||||||
/**
|
|
||||||
* Duration to wait before retrying after an error. Will be multiplied by the number of errors since the last successful fetch.
|
/**
|
||||||
*/
|
* Duration to wait before retrying after an error. Will be multiplied by the number of errors since the last successful fetch.
|
||||||
@WithDefault("1h")
|
*/
|
||||||
Duration backoffInterval();
|
@WithDefault("1h")
|
||||||
}
|
Duration backoffInterval();
|
||||||
|
}
|
||||||
interface Database {
|
|
||||||
/**
|
interface Database {
|
||||||
* Timeout applied to all database queries.
|
/**
|
||||||
*
|
* Timeout applied to all database queries.
|
||||||
* 0 to disable.
|
*
|
||||||
*/
|
* 0 to disable.
|
||||||
@WithDefault("0")
|
*/
|
||||||
Duration queryTimeout();
|
@WithDefault("0")
|
||||||
|
Duration queryTimeout();
|
||||||
/**
|
|
||||||
* Database cleanup settings.
|
/**
|
||||||
*/
|
* Database cleanup settings.
|
||||||
@ConfigDocSection
|
*/
|
||||||
Cleanup cleanup();
|
@ConfigDocSection
|
||||||
|
Cleanup cleanup();
|
||||||
interface Cleanup {
|
|
||||||
/**
|
interface Cleanup {
|
||||||
* Maximum age of feed entries in the database. Older entries will be deleted.
|
/**
|
||||||
*
|
* Maximum age of feed entries in the database. Older entries will be deleted.
|
||||||
* 0 to disable.
|
*
|
||||||
*/
|
* 0 to disable.
|
||||||
@WithDefault("365d")
|
*/
|
||||||
Duration entriesMaxAge();
|
@WithDefault("365d")
|
||||||
|
Duration entriesMaxAge();
|
||||||
/**
|
|
||||||
* Maximum age of feed entry statuses (read/unread) in the database. Older statuses will be deleted.
|
/**
|
||||||
*
|
* Maximum age of feed entry statuses (read/unread) in the database. Older statuses will be deleted.
|
||||||
* 0 to disable.
|
*
|
||||||
*/
|
* 0 to disable.
|
||||||
@WithDefault("0")
|
*/
|
||||||
Duration statusesMaxAge();
|
@WithDefault("0")
|
||||||
|
Duration statusesMaxAge();
|
||||||
/**
|
|
||||||
* Maximum number of entries per feed to keep in the database.
|
/**
|
||||||
*
|
* Maximum number of entries per feed to keep in the database.
|
||||||
* 0 to disable.
|
*
|
||||||
*/
|
* 0 to disable.
|
||||||
@WithDefault("500")
|
*/
|
||||||
int maxFeedCapacity();
|
@WithDefault("500")
|
||||||
|
int maxFeedCapacity();
|
||||||
/**
|
|
||||||
* Limit the number of feeds a user can subscribe to.
|
/**
|
||||||
*
|
* Limit the number of feeds a user can subscribe to.
|
||||||
* 0 to disable.
|
*
|
||||||
*/
|
* 0 to disable.
|
||||||
@WithDefault("0")
|
*/
|
||||||
int maxFeedsPerUser();
|
@WithDefault("0")
|
||||||
|
int maxFeedsPerUser();
|
||||||
/**
|
|
||||||
* Rows to delete per query while cleaning up old entries.
|
/**
|
||||||
*/
|
* Rows to delete per query while cleaning up old entries.
|
||||||
@Positive
|
*/
|
||||||
@WithDefault("100")
|
@Positive
|
||||||
int batchSize();
|
@WithDefault("100")
|
||||||
|
int batchSize();
|
||||||
default Instant statusesInstantThreshold() {
|
|
||||||
return statusesMaxAge().toMillis() > 0 ? Instant.now().minus(statusesMaxAge()) : null;
|
default Instant statusesInstantThreshold() {
|
||||||
}
|
return statusesMaxAge().toMillis() > 0 ? Instant.now().minus(statusesMaxAge()) : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
interface Users {
|
|
||||||
/**
|
interface Users {
|
||||||
* Whether to let users create accounts for themselves.
|
/**
|
||||||
*/
|
* Whether to let users create accounts for themselves.
|
||||||
@WithDefault("false")
|
*/
|
||||||
boolean allowRegistrations();
|
@WithDefault("false")
|
||||||
|
boolean allowRegistrations();
|
||||||
/**
|
|
||||||
* Whether to enable strict password validation (1 uppercase char, 1 lowercase char, 1 digit, 1 special char).
|
/**
|
||||||
*/
|
* Whether to enable strict password validation (1 uppercase char, 1 lowercase char, 1 digit, 1 special char).
|
||||||
@WithDefault("true")
|
*/
|
||||||
boolean strictPasswordPolicy();
|
@WithDefault("true")
|
||||||
|
boolean strictPasswordPolicy();
|
||||||
/**
|
|
||||||
* Whether to create a demo account the first time the app starts.
|
/**
|
||||||
*/
|
* Whether to create a demo account the first time the app starts.
|
||||||
@WithDefault("false")
|
*/
|
||||||
boolean createDemoAccount();
|
@WithDefault("false")
|
||||||
}
|
boolean createDemoAccount();
|
||||||
|
}
|
||||||
interface Websocket {
|
|
||||||
/**
|
interface Websocket {
|
||||||
* Enable websocket connection so the server can notify web clients that there are new entries for feeds.
|
/**
|
||||||
*/
|
* Enable websocket connection so the server can notify web clients that there are new entries for feeds.
|
||||||
@WithDefault("true")
|
*/
|
||||||
boolean enabled();
|
@WithDefault("true")
|
||||||
|
boolean enabled();
|
||||||
/**
|
|
||||||
* Interval at which the client will send a ping message on the websocket to keep the connection alive.
|
/**
|
||||||
*/
|
* Interval at which the client will send a ping message on the websocket to keep the connection alive.
|
||||||
@WithDefault("15m")
|
*/
|
||||||
Duration pingInterval();
|
@WithDefault("15m")
|
||||||
|
Duration pingInterval();
|
||||||
/**
|
|
||||||
* If the websocket connection is disabled or the connection is lost, the client will reload the feed tree at this interval.
|
/**
|
||||||
*/
|
* If the websocket connection is disabled or the connection is lost, the client will reload the feed tree at this interval.
|
||||||
@WithDefault("30s")
|
*/
|
||||||
Duration treeReloadInterval();
|
@WithDefault("30s")
|
||||||
}
|
Duration treeReloadInterval();
|
||||||
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
package com.commafeed;
|
package com.commafeed;
|
||||||
|
|
||||||
import java.time.InstantSource;
|
import java.time.InstantSource;
|
||||||
|
|
||||||
import com.codahale.metrics.MetricRegistry;
|
import jakarta.enterprise.inject.Produces;
|
||||||
|
import jakarta.inject.Singleton;
|
||||||
import jakarta.enterprise.inject.Produces;
|
|
||||||
import jakarta.inject.Singleton;
|
import com.codahale.metrics.MetricRegistry;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class CommaFeedProducers {
|
public class CommaFeedProducers {
|
||||||
|
|
||||||
@Produces
|
@Produces
|
||||||
@Singleton
|
@Singleton
|
||||||
public InstantSource instantSource() {
|
public InstantSource instantSource() {
|
||||||
return InstantSource.system();
|
return InstantSource.system();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Produces
|
@Produces
|
||||||
@Singleton
|
@Singleton
|
||||||
public MetricRegistry metricRegistry() {
|
public MetricRegistry metricRegistry() {
|
||||||
return new MetricRegistry();
|
return new MetricRegistry();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +1,32 @@
|
|||||||
package com.commafeed;
|
package com.commafeed;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import jakarta.inject.Singleton;
|
import jakarta.inject.Singleton;
|
||||||
import lombok.Getter;
|
|
||||||
|
import lombok.Getter;
|
||||||
@Singleton
|
|
||||||
@Getter
|
@Singleton
|
||||||
public class CommaFeedVersion {
|
@Getter
|
||||||
|
public class CommaFeedVersion {
|
||||||
private final String version;
|
|
||||||
private final String gitCommit;
|
private final String version;
|
||||||
|
private final String gitCommit;
|
||||||
public CommaFeedVersion() {
|
|
||||||
Properties properties = new Properties();
|
public CommaFeedVersion() {
|
||||||
try (InputStream stream = getClass().getResourceAsStream("/git.properties")) {
|
Properties properties = new Properties();
|
||||||
if (stream != null) {
|
try (InputStream stream = getClass().getResourceAsStream("/git.properties")) {
|
||||||
properties.load(stream);
|
if (stream != null) {
|
||||||
}
|
properties.load(stream);
|
||||||
} catch (IOException e) {
|
}
|
||||||
throw new RuntimeException(e);
|
} catch (IOException e) {
|
||||||
}
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
this.version = properties.getProperty("git.build.version", "unknown");
|
|
||||||
this.gitCommit = properties.getProperty("git.commit.id.abbrev", "unknown");
|
this.version = properties.getProperty("git.build.version", "unknown");
|
||||||
}
|
this.gitCommit = properties.getProperty("git.commit.id.abbrev", "unknown");
|
||||||
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,49 +1,50 @@
|
|||||||
package com.commafeed;
|
package com.commafeed;
|
||||||
|
|
||||||
import org.jboss.resteasy.reactive.RestResponse;
|
import jakarta.annotation.Priority;
|
||||||
import org.jboss.resteasy.reactive.RestResponse.Status;
|
import jakarta.validation.ValidationException;
|
||||||
import org.jboss.resteasy.reactive.server.ServerExceptionMapper;
|
import jakarta.ws.rs.ext.Provider;
|
||||||
|
|
||||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
import org.jboss.resteasy.reactive.RestResponse;
|
||||||
import io.quarkus.security.AuthenticationFailedException;
|
import org.jboss.resteasy.reactive.RestResponse.Status;
|
||||||
import io.quarkus.security.UnauthorizedException;
|
import org.jboss.resteasy.reactive.server.ServerExceptionMapper;
|
||||||
import jakarta.annotation.Priority;
|
|
||||||
import jakarta.validation.ValidationException;
|
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||||
import jakarta.ws.rs.ext.Provider;
|
import io.quarkus.security.AuthenticationFailedException;
|
||||||
import lombok.RequiredArgsConstructor;
|
import io.quarkus.security.UnauthorizedException;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Provider
|
@RequiredArgsConstructor
|
||||||
@Priority(1)
|
@Provider
|
||||||
public class ExceptionMappers {
|
@Priority(1)
|
||||||
|
public class ExceptionMappers {
|
||||||
private final CommaFeedConfiguration config;
|
|
||||||
|
private final CommaFeedConfiguration config;
|
||||||
@ServerExceptionMapper(UnauthorizedException.class)
|
|
||||||
public RestResponse<UnauthorizedResponse> unauthorized(UnauthorizedException e) {
|
@ServerExceptionMapper(UnauthorizedException.class)
|
||||||
return RestResponse.status(RestResponse.Status.UNAUTHORIZED,
|
public RestResponse<UnauthorizedResponse> unauthorized(UnauthorizedException e) {
|
||||||
new UnauthorizedResponse(e.getMessage(), config.users().allowRegistrations()));
|
return RestResponse.status(RestResponse.Status.UNAUTHORIZED,
|
||||||
}
|
new UnauthorizedResponse(e.getMessage(), config.users().allowRegistrations()));
|
||||||
|
}
|
||||||
@ServerExceptionMapper(AuthenticationFailedException.class)
|
|
||||||
public RestResponse<AuthenticationFailed> authenticationFailed(AuthenticationFailedException e) {
|
@ServerExceptionMapper(AuthenticationFailedException.class)
|
||||||
return RestResponse.status(RestResponse.Status.UNAUTHORIZED, new AuthenticationFailed(e.getMessage()));
|
public RestResponse<AuthenticationFailed> authenticationFailed(AuthenticationFailedException e) {
|
||||||
}
|
return RestResponse.status(RestResponse.Status.UNAUTHORIZED, new AuthenticationFailed(e.getMessage()));
|
||||||
|
}
|
||||||
@ServerExceptionMapper(ValidationException.class)
|
|
||||||
public RestResponse<ValidationFailed> validationFailed(ValidationException e) {
|
@ServerExceptionMapper(ValidationException.class)
|
||||||
return RestResponse.status(Status.BAD_REQUEST, new ValidationFailed(e.getMessage()));
|
public RestResponse<ValidationFailed> validationFailed(ValidationException e) {
|
||||||
}
|
return RestResponse.status(Status.BAD_REQUEST, new ValidationFailed(e.getMessage()));
|
||||||
|
}
|
||||||
@RegisterForReflection
|
|
||||||
public record UnauthorizedResponse(String message, boolean allowRegistrations) {
|
@RegisterForReflection
|
||||||
}
|
public record UnauthorizedResponse(String message, boolean allowRegistrations) {
|
||||||
|
}
|
||||||
@RegisterForReflection
|
|
||||||
public record AuthenticationFailed(String message) {
|
@RegisterForReflection
|
||||||
}
|
public record AuthenticationFailed(String message) {
|
||||||
|
}
|
||||||
@RegisterForReflection
|
|
||||||
public record ValidationFailed(String message) {
|
@RegisterForReflection
|
||||||
}
|
public record ValidationFailed(String message) {
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,28 +1,29 @@
|
|||||||
package com.commafeed;
|
package com.commafeed;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import com.codahale.metrics.json.MetricsModule;
|
import jakarta.inject.Singleton;
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.codahale.metrics.json.MetricsModule;
|
||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
import io.quarkus.jackson.ObjectMapperCustomizer;
|
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||||
import jakarta.inject.Singleton;
|
|
||||||
|
import io.quarkus.jackson.ObjectMapperCustomizer;
|
||||||
@Singleton
|
|
||||||
public class JacksonCustomizer implements ObjectMapperCustomizer {
|
@Singleton
|
||||||
@Override
|
public class JacksonCustomizer implements ObjectMapperCustomizer {
|
||||||
public void customize(ObjectMapper objectMapper) {
|
@Override
|
||||||
objectMapper.registerModule(new JavaTimeModule());
|
public void customize(ObjectMapper objectMapper) {
|
||||||
|
objectMapper.registerModule(new JavaTimeModule());
|
||||||
// read and write instants as milliseconds instead of nanoseconds
|
|
||||||
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true)
|
// read and write instants as milliseconds instead of nanoseconds
|
||||||
.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false)
|
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true)
|
||||||
.configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false);
|
.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false)
|
||||||
|
.configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false);
|
||||||
// add support for serializing metrics
|
|
||||||
objectMapper.registerModule(new MetricsModule(TimeUnit.SECONDS, TimeUnit.SECONDS, false));
|
// add support for serializing metrics
|
||||||
}
|
objectMapper.registerModule(new MetricsModule(TimeUnit.SECONDS, TimeUnit.SECONDS, false));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,226 +1,226 @@
|
|||||||
package com.commafeed;
|
package com.commafeed;
|
||||||
|
|
||||||
import com.codahale.metrics.Counter;
|
import com.codahale.metrics.Counter;
|
||||||
import com.codahale.metrics.Gauge;
|
import com.codahale.metrics.Gauge;
|
||||||
import com.codahale.metrics.Histogram;
|
import com.codahale.metrics.Histogram;
|
||||||
import com.codahale.metrics.Meter;
|
import com.codahale.metrics.Meter;
|
||||||
import com.codahale.metrics.MetricRegistry;
|
import com.codahale.metrics.MetricRegistry;
|
||||||
import com.codahale.metrics.Timer;
|
import com.codahale.metrics.Timer;
|
||||||
|
|
||||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||||
|
|
||||||
@RegisterForReflection(
|
@RegisterForReflection(
|
||||||
targets = {
|
targets = {
|
||||||
// metrics
|
// metrics
|
||||||
MetricRegistry.class, Meter.class, Gauge.class, Counter.class, Timer.class, Histogram.class,
|
MetricRegistry.class, Meter.class, Gauge.class, Counter.class, Timer.class, Histogram.class,
|
||||||
|
|
||||||
// rome
|
// rome
|
||||||
java.util.Date.class, com.rometools.opml.feed.synd.impl.TreeCategoryImpl.class,
|
java.util.Date.class, com.rometools.opml.feed.synd.impl.TreeCategoryImpl.class,
|
||||||
com.rometools.rome.feed.synd.SyndFeedImpl.class, com.rometools.rome.feed.module.DCSubjectImpl.class,
|
com.rometools.rome.feed.synd.SyndFeedImpl.class, com.rometools.rome.feed.module.DCSubjectImpl.class,
|
||||||
com.rometools.rome.feed.synd.SyndEntryImpl.class, com.rometools.modules.psc.types.SimpleChapter.class,
|
com.rometools.rome.feed.synd.SyndEntryImpl.class, com.rometools.modules.psc.types.SimpleChapter.class,
|
||||||
com.rometools.rome.feed.synd.SyndCategoryImpl.class, com.rometools.rome.feed.synd.SyndImageImpl.class,
|
com.rometools.rome.feed.synd.SyndCategoryImpl.class, com.rometools.rome.feed.synd.SyndImageImpl.class,
|
||||||
com.rometools.rome.feed.synd.SyndContentImpl.class, com.rometools.rome.feed.synd.SyndEnclosureImpl.class,
|
com.rometools.rome.feed.synd.SyndContentImpl.class, com.rometools.rome.feed.synd.SyndEnclosureImpl.class,
|
||||||
|
|
||||||
// rome cloneable
|
// rome cloneable
|
||||||
com.rometools.modules.activitystreams.types.Article.class, com.rometools.modules.activitystreams.types.Audio.class,
|
com.rometools.modules.activitystreams.types.Article.class, com.rometools.modules.activitystreams.types.Audio.class,
|
||||||
com.rometools.modules.activitystreams.types.Bookmark.class, com.rometools.modules.activitystreams.types.Comment.class,
|
com.rometools.modules.activitystreams.types.Bookmark.class, com.rometools.modules.activitystreams.types.Comment.class,
|
||||||
com.rometools.modules.activitystreams.types.Event.class, com.rometools.modules.activitystreams.types.File.class,
|
com.rometools.modules.activitystreams.types.Event.class, com.rometools.modules.activitystreams.types.File.class,
|
||||||
com.rometools.modules.activitystreams.types.Folder.class, com.rometools.modules.activitystreams.types.List.class,
|
com.rometools.modules.activitystreams.types.Folder.class, com.rometools.modules.activitystreams.types.List.class,
|
||||||
com.rometools.modules.activitystreams.types.Note.class, com.rometools.modules.activitystreams.types.Person.class,
|
com.rometools.modules.activitystreams.types.Note.class, com.rometools.modules.activitystreams.types.Person.class,
|
||||||
com.rometools.modules.activitystreams.types.Photo.class, com.rometools.modules.activitystreams.types.PhotoAlbum.class,
|
com.rometools.modules.activitystreams.types.Photo.class, com.rometools.modules.activitystreams.types.PhotoAlbum.class,
|
||||||
com.rometools.modules.activitystreams.types.Place.class, com.rometools.modules.activitystreams.types.Playlist.class,
|
com.rometools.modules.activitystreams.types.Place.class, com.rometools.modules.activitystreams.types.Playlist.class,
|
||||||
com.rometools.modules.activitystreams.types.Product.class, com.rometools.modules.activitystreams.types.Review.class,
|
com.rometools.modules.activitystreams.types.Product.class, com.rometools.modules.activitystreams.types.Review.class,
|
||||||
com.rometools.modules.activitystreams.types.Service.class, com.rometools.modules.activitystreams.types.Song.class,
|
com.rometools.modules.activitystreams.types.Service.class, com.rometools.modules.activitystreams.types.Song.class,
|
||||||
com.rometools.modules.activitystreams.types.Status.class, com.rometools.modules.base.types.DateTimeRange.class,
|
com.rometools.modules.activitystreams.types.Status.class, com.rometools.modules.base.types.DateTimeRange.class,
|
||||||
com.rometools.modules.base.types.FloatUnit.class, com.rometools.modules.base.types.GenderEnumeration.class,
|
com.rometools.modules.base.types.FloatUnit.class, com.rometools.modules.base.types.GenderEnumeration.class,
|
||||||
com.rometools.modules.base.types.IntUnit.class, com.rometools.modules.base.types.PriceTypeEnumeration.class,
|
com.rometools.modules.base.types.IntUnit.class, com.rometools.modules.base.types.PriceTypeEnumeration.class,
|
||||||
com.rometools.modules.base.types.ShippingType.class, com.rometools.modules.base.types.ShortDate.class,
|
com.rometools.modules.base.types.ShippingType.class, com.rometools.modules.base.types.ShortDate.class,
|
||||||
com.rometools.modules.base.types.Size.class, com.rometools.modules.base.types.YearType.class,
|
com.rometools.modules.base.types.Size.class, com.rometools.modules.base.types.YearType.class,
|
||||||
com.rometools.modules.content.ContentItem.class, com.rometools.modules.georss.GeoRSSPoint.class,
|
com.rometools.modules.content.ContentItem.class, com.rometools.modules.georss.GeoRSSPoint.class,
|
||||||
com.rometools.modules.georss.geometries.Envelope.class, com.rometools.modules.georss.geometries.LineString.class,
|
com.rometools.modules.georss.geometries.Envelope.class, com.rometools.modules.georss.geometries.LineString.class,
|
||||||
com.rometools.modules.georss.geometries.LinearRing.class, com.rometools.modules.georss.geometries.Point.class,
|
com.rometools.modules.georss.geometries.LinearRing.class, com.rometools.modules.georss.geometries.Point.class,
|
||||||
com.rometools.modules.georss.geometries.Polygon.class, com.rometools.modules.georss.geometries.Position.class,
|
com.rometools.modules.georss.geometries.Polygon.class, com.rometools.modules.georss.geometries.Position.class,
|
||||||
com.rometools.modules.georss.geometries.PositionList.class, com.rometools.modules.mediarss.types.MediaGroup.class,
|
com.rometools.modules.georss.geometries.PositionList.class, com.rometools.modules.mediarss.types.MediaGroup.class,
|
||||||
com.rometools.modules.mediarss.types.Metadata.class, com.rometools.modules.mediarss.types.Thumbnail.class,
|
com.rometools.modules.mediarss.types.Metadata.class, com.rometools.modules.mediarss.types.Thumbnail.class,
|
||||||
com.rometools.modules.opensearch.entity.OSQuery.class, com.rometools.modules.photocast.types.PhotoDate.class,
|
com.rometools.modules.opensearch.entity.OSQuery.class, com.rometools.modules.photocast.types.PhotoDate.class,
|
||||||
com.rometools.modules.sle.types.DateValue.class, com.rometools.modules.sle.types.Group.class,
|
com.rometools.modules.sle.types.DateValue.class, com.rometools.modules.sle.types.Group.class,
|
||||||
com.rometools.modules.sle.types.NumberValue.class, com.rometools.modules.sle.types.Sort.class,
|
com.rometools.modules.sle.types.NumberValue.class, com.rometools.modules.sle.types.Sort.class,
|
||||||
com.rometools.modules.sle.types.StringValue.class, com.rometools.modules.yahooweather.types.Astronomy.class,
|
com.rometools.modules.sle.types.StringValue.class, com.rometools.modules.yahooweather.types.Astronomy.class,
|
||||||
com.rometools.modules.yahooweather.types.Atmosphere.class, com.rometools.modules.yahooweather.types.Condition.class,
|
com.rometools.modules.yahooweather.types.Atmosphere.class, com.rometools.modules.yahooweather.types.Condition.class,
|
||||||
com.rometools.modules.yahooweather.types.Forecast.class, com.rometools.modules.yahooweather.types.Location.class,
|
com.rometools.modules.yahooweather.types.Forecast.class, com.rometools.modules.yahooweather.types.Location.class,
|
||||||
com.rometools.modules.yahooweather.types.Units.class, com.rometools.modules.yahooweather.types.Wind.class,
|
com.rometools.modules.yahooweather.types.Units.class, com.rometools.modules.yahooweather.types.Wind.class,
|
||||||
com.rometools.opml.feed.opml.Attribute.class, com.rometools.opml.feed.opml.Opml.class,
|
com.rometools.opml.feed.opml.Attribute.class, com.rometools.opml.feed.opml.Opml.class,
|
||||||
com.rometools.opml.feed.opml.Outline.class, com.rometools.rome.feed.atom.Category.class,
|
com.rometools.opml.feed.opml.Outline.class, com.rometools.rome.feed.atom.Category.class,
|
||||||
com.rometools.rome.feed.atom.Content.class, com.rometools.rome.feed.atom.Entry.class,
|
com.rometools.rome.feed.atom.Content.class, com.rometools.rome.feed.atom.Entry.class,
|
||||||
com.rometools.rome.feed.atom.Feed.class, com.rometools.rome.feed.atom.Generator.class,
|
com.rometools.rome.feed.atom.Feed.class, com.rometools.rome.feed.atom.Generator.class,
|
||||||
com.rometools.rome.feed.atom.Link.class, com.rometools.rome.feed.atom.Person.class,
|
com.rometools.rome.feed.atom.Link.class, com.rometools.rome.feed.atom.Person.class,
|
||||||
com.rometools.rome.feed.rss.Category.class, com.rometools.rome.feed.rss.Channel.class,
|
com.rometools.rome.feed.rss.Category.class, com.rometools.rome.feed.rss.Channel.class,
|
||||||
com.rometools.rome.feed.rss.Cloud.class, com.rometools.rome.feed.rss.Content.class,
|
com.rometools.rome.feed.rss.Cloud.class, com.rometools.rome.feed.rss.Content.class,
|
||||||
com.rometools.rome.feed.rss.Description.class, com.rometools.rome.feed.rss.Enclosure.class,
|
com.rometools.rome.feed.rss.Description.class, com.rometools.rome.feed.rss.Enclosure.class,
|
||||||
com.rometools.rome.feed.rss.Guid.class, com.rometools.rome.feed.rss.Image.class, com.rometools.rome.feed.rss.Item.class,
|
com.rometools.rome.feed.rss.Guid.class, com.rometools.rome.feed.rss.Image.class, com.rometools.rome.feed.rss.Item.class,
|
||||||
com.rometools.rome.feed.rss.Source.class, com.rometools.rome.feed.rss.TextInput.class,
|
com.rometools.rome.feed.rss.Source.class, com.rometools.rome.feed.rss.TextInput.class,
|
||||||
com.rometools.rome.feed.synd.SyndLinkImpl.class, com.rometools.rome.feed.synd.SyndPersonImpl.class,
|
com.rometools.rome.feed.synd.SyndLinkImpl.class, com.rometools.rome.feed.synd.SyndPersonImpl.class,
|
||||||
java.util.ArrayList.class,
|
java.util.ArrayList.class,
|
||||||
|
|
||||||
// rome modules
|
// rome modules
|
||||||
com.rometools.modules.sse.modules.Conflict.class, com.rometools.modules.sse.modules.Conflicts.class,
|
com.rometools.modules.sse.modules.Conflict.class, com.rometools.modules.sse.modules.Conflicts.class,
|
||||||
com.rometools.modules.cc.CreativeCommonsImpl.class, com.rometools.modules.feedpress.modules.FeedpressModuleImpl.class,
|
com.rometools.modules.cc.CreativeCommonsImpl.class, com.rometools.modules.feedpress.modules.FeedpressModuleImpl.class,
|
||||||
com.rometools.modules.opensearch.impl.OpenSearchModuleImpl.class, com.rometools.modules.sse.modules.Sharing.class,
|
com.rometools.modules.opensearch.impl.OpenSearchModuleImpl.class, com.rometools.modules.sse.modules.Sharing.class,
|
||||||
com.rometools.modules.georss.SimpleModuleImpl.class, com.rometools.modules.atom.modules.AtomLinkModuleImpl.class,
|
com.rometools.modules.georss.SimpleModuleImpl.class, com.rometools.modules.atom.modules.AtomLinkModuleImpl.class,
|
||||||
com.rometools.modules.itunes.EntryInformationImpl.class, com.rometools.modules.sse.modules.Update.class,
|
com.rometools.modules.itunes.EntryInformationImpl.class, com.rometools.modules.sse.modules.Update.class,
|
||||||
com.rometools.modules.photocast.PhotocastModuleImpl.class, com.rometools.modules.itunes.FeedInformationImpl.class,
|
com.rometools.modules.photocast.PhotocastModuleImpl.class, com.rometools.modules.itunes.FeedInformationImpl.class,
|
||||||
com.rometools.modules.yahooweather.YWeatherModuleImpl.class, com.rometools.modules.feedburner.FeedBurnerImpl.class,
|
com.rometools.modules.yahooweather.YWeatherModuleImpl.class, com.rometools.modules.feedburner.FeedBurnerImpl.class,
|
||||||
com.rometools.modules.sse.modules.Related.class, com.rometools.modules.fyyd.modules.FyydModuleImpl.class,
|
com.rometools.modules.sse.modules.Related.class, com.rometools.modules.fyyd.modules.FyydModuleImpl.class,
|
||||||
com.rometools.modules.psc.modules.PodloveSimpleChapterModuleImpl.class, com.rometools.modules.thr.ThreadingModuleImpl.class,
|
com.rometools.modules.psc.modules.PodloveSimpleChapterModuleImpl.class, com.rometools.modules.thr.ThreadingModuleImpl.class,
|
||||||
com.rometools.modules.sse.modules.Sync.class, com.rometools.modules.sle.SimpleListExtensionImpl.class,
|
com.rometools.modules.sse.modules.Sync.class, com.rometools.modules.sle.SimpleListExtensionImpl.class,
|
||||||
com.rometools.modules.slash.SlashImpl.class, com.rometools.modules.sse.modules.History.class,
|
com.rometools.modules.slash.SlashImpl.class, com.rometools.modules.sse.modules.History.class,
|
||||||
com.rometools.modules.georss.GMLModuleImpl.class, com.rometools.modules.base.CustomTagsImpl.class,
|
com.rometools.modules.georss.GMLModuleImpl.class, com.rometools.modules.base.CustomTagsImpl.class,
|
||||||
com.rometools.modules.base.GoogleBaseImpl.class, com.rometools.modules.sle.SleEntryImpl.class,
|
com.rometools.modules.base.GoogleBaseImpl.class, com.rometools.modules.sle.SleEntryImpl.class,
|
||||||
com.rometools.modules.mediarss.MediaEntryModuleImpl.class, com.rometools.modules.content.ContentModuleImpl.class,
|
com.rometools.modules.mediarss.MediaEntryModuleImpl.class, com.rometools.modules.content.ContentModuleImpl.class,
|
||||||
com.rometools.modules.georss.W3CGeoModuleImpl.class, com.rometools.rome.feed.module.DCModuleImpl.class,
|
com.rometools.modules.georss.W3CGeoModuleImpl.class, com.rometools.rome.feed.module.DCModuleImpl.class,
|
||||||
com.rometools.modules.mediarss.MediaModuleImpl.class, com.rometools.rome.feed.module.SyModuleImpl.class,
|
com.rometools.modules.mediarss.MediaModuleImpl.class, com.rometools.rome.feed.module.SyModuleImpl.class,
|
||||||
|
|
||||||
// extracted from all 3 rome.properties files of rome library
|
// extracted from all 3 rome.properties files of rome library
|
||||||
com.rometools.rome.io.impl.RSS090Parser.class, com.rometools.rome.io.impl.RSS091NetscapeParser.class,
|
com.rometools.rome.io.impl.RSS090Parser.class, com.rometools.rome.io.impl.RSS091NetscapeParser.class,
|
||||||
com.rometools.rome.io.impl.RSS091UserlandParser.class, com.rometools.rome.io.impl.RSS092Parser.class,
|
com.rometools.rome.io.impl.RSS091UserlandParser.class, com.rometools.rome.io.impl.RSS092Parser.class,
|
||||||
com.rometools.rome.io.impl.RSS093Parser.class, com.rometools.rome.io.impl.RSS094Parser.class,
|
com.rometools.rome.io.impl.RSS093Parser.class, com.rometools.rome.io.impl.RSS094Parser.class,
|
||||||
com.rometools.rome.io.impl.RSS10Parser.class, com.rometools.rome.io.impl.RSS20wNSParser.class,
|
com.rometools.rome.io.impl.RSS10Parser.class, com.rometools.rome.io.impl.RSS20wNSParser.class,
|
||||||
com.rometools.rome.io.impl.RSS20Parser.class, com.rometools.rome.io.impl.Atom10Parser.class,
|
com.rometools.rome.io.impl.RSS20Parser.class, com.rometools.rome.io.impl.Atom10Parser.class,
|
||||||
com.rometools.rome.io.impl.Atom03Parser.class,
|
com.rometools.rome.io.impl.Atom03Parser.class,
|
||||||
|
|
||||||
com.rometools.rome.io.impl.SyModuleParser.class, com.rometools.rome.io.impl.DCModuleParser.class,
|
com.rometools.rome.io.impl.SyModuleParser.class, com.rometools.rome.io.impl.DCModuleParser.class,
|
||||||
|
|
||||||
com.rometools.rome.io.impl.RSS090Generator.class, com.rometools.rome.io.impl.RSS091NetscapeGenerator.class,
|
com.rometools.rome.io.impl.RSS090Generator.class, com.rometools.rome.io.impl.RSS091NetscapeGenerator.class,
|
||||||
com.rometools.rome.io.impl.RSS091UserlandGenerator.class, com.rometools.rome.io.impl.RSS092Generator.class,
|
com.rometools.rome.io.impl.RSS091UserlandGenerator.class, com.rometools.rome.io.impl.RSS092Generator.class,
|
||||||
com.rometools.rome.io.impl.RSS093Generator.class, com.rometools.rome.io.impl.RSS094Generator.class,
|
com.rometools.rome.io.impl.RSS093Generator.class, com.rometools.rome.io.impl.RSS094Generator.class,
|
||||||
com.rometools.rome.io.impl.RSS10Generator.class, com.rometools.rome.io.impl.RSS20Generator.class,
|
com.rometools.rome.io.impl.RSS10Generator.class, com.rometools.rome.io.impl.RSS20Generator.class,
|
||||||
com.rometools.rome.io.impl.Atom10Generator.class, com.rometools.rome.io.impl.Atom03Generator.class,
|
com.rometools.rome.io.impl.Atom10Generator.class, com.rometools.rome.io.impl.Atom03Generator.class,
|
||||||
|
|
||||||
com.rometools.rome.feed.synd.impl.ConverterForAtom10.class, com.rometools.rome.feed.synd.impl.ConverterForAtom03.class,
|
com.rometools.rome.feed.synd.impl.ConverterForAtom10.class, com.rometools.rome.feed.synd.impl.ConverterForAtom03.class,
|
||||||
com.rometools.rome.feed.synd.impl.ConverterForRSS090.class,
|
com.rometools.rome.feed.synd.impl.ConverterForRSS090.class,
|
||||||
com.rometools.rome.feed.synd.impl.ConverterForRSS091Netscape.class,
|
com.rometools.rome.feed.synd.impl.ConverterForRSS091Netscape.class,
|
||||||
com.rometools.rome.feed.synd.impl.ConverterForRSS091Userland.class,
|
com.rometools.rome.feed.synd.impl.ConverterForRSS091Userland.class,
|
||||||
com.rometools.rome.feed.synd.impl.ConverterForRSS092.class, com.rometools.rome.feed.synd.impl.ConverterForRSS093.class,
|
com.rometools.rome.feed.synd.impl.ConverterForRSS092.class, com.rometools.rome.feed.synd.impl.ConverterForRSS093.class,
|
||||||
com.rometools.rome.feed.synd.impl.ConverterForRSS094.class, com.rometools.rome.feed.synd.impl.ConverterForRSS10.class,
|
com.rometools.rome.feed.synd.impl.ConverterForRSS094.class, com.rometools.rome.feed.synd.impl.ConverterForRSS10.class,
|
||||||
com.rometools.rome.feed.synd.impl.ConverterForRSS20.class,
|
com.rometools.rome.feed.synd.impl.ConverterForRSS20.class,
|
||||||
|
|
||||||
com.rometools.modules.mediarss.io.RSS20YahooParser.class,
|
com.rometools.modules.mediarss.io.RSS20YahooParser.class,
|
||||||
|
|
||||||
com.rometools.modules.cc.io.ModuleParserRSS2.class, com.rometools.modules.content.io.ContentModuleParser.class,
|
com.rometools.modules.cc.io.ModuleParserRSS2.class, com.rometools.modules.content.io.ContentModuleParser.class,
|
||||||
com.rometools.modules.itunes.io.ITunesParser.class, com.rometools.modules.mediarss.io.MediaModuleParser.class,
|
com.rometools.modules.itunes.io.ITunesParser.class, com.rometools.modules.mediarss.io.MediaModuleParser.class,
|
||||||
com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class, com.rometools.modules.georss.SimpleParser.class,
|
com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class, com.rometools.modules.georss.SimpleParser.class,
|
||||||
com.rometools.modules.georss.W3CGeoParser.class, com.rometools.modules.photocast.io.Parser.class,
|
com.rometools.modules.georss.W3CGeoParser.class, com.rometools.modules.photocast.io.Parser.class,
|
||||||
com.rometools.modules.mediarss.io.MediaModuleParser.class, com.rometools.modules.atom.io.AtomModuleParser.class,
|
com.rometools.modules.mediarss.io.MediaModuleParser.class, com.rometools.modules.atom.io.AtomModuleParser.class,
|
||||||
com.rometools.modules.itunes.io.ITunesParserOldNamespace.class,
|
com.rometools.modules.itunes.io.ITunesParserOldNamespace.class,
|
||||||
com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class, com.rometools.modules.sle.io.ModuleParser.class,
|
com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class, com.rometools.modules.sle.io.ModuleParser.class,
|
||||||
com.rometools.modules.yahooweather.io.WeatherModuleParser.class, com.rometools.modules.feedpress.io.FeedpressParser.class,
|
com.rometools.modules.yahooweather.io.WeatherModuleParser.class, com.rometools.modules.feedpress.io.FeedpressParser.class,
|
||||||
com.rometools.modules.fyyd.io.FyydParser.class,
|
com.rometools.modules.fyyd.io.FyydParser.class,
|
||||||
|
|
||||||
com.rometools.modules.cc.io.ModuleParserRSS2.class, com.rometools.modules.content.io.ContentModuleParser.class,
|
com.rometools.modules.cc.io.ModuleParserRSS2.class, com.rometools.modules.content.io.ContentModuleParser.class,
|
||||||
com.rometools.modules.itunes.io.ITunesParser.class, com.rometools.modules.mediarss.io.MediaModuleParser.class,
|
com.rometools.modules.itunes.io.ITunesParser.class, com.rometools.modules.mediarss.io.MediaModuleParser.class,
|
||||||
com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class, com.rometools.modules.georss.SimpleParser.class,
|
com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class, com.rometools.modules.georss.SimpleParser.class,
|
||||||
com.rometools.modules.georss.W3CGeoParser.class, com.rometools.modules.photocast.io.Parser.class,
|
com.rometools.modules.georss.W3CGeoParser.class, com.rometools.modules.photocast.io.Parser.class,
|
||||||
com.rometools.modules.mediarss.io.MediaModuleParser.class, com.rometools.modules.atom.io.AtomModuleParser.class,
|
com.rometools.modules.mediarss.io.MediaModuleParser.class, com.rometools.modules.atom.io.AtomModuleParser.class,
|
||||||
com.rometools.modules.itunes.io.ITunesParserOldNamespace.class,
|
com.rometools.modules.itunes.io.ITunesParserOldNamespace.class,
|
||||||
com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class, com.rometools.modules.sle.io.ModuleParser.class,
|
com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class, com.rometools.modules.sle.io.ModuleParser.class,
|
||||||
com.rometools.modules.yahooweather.io.WeatherModuleParser.class, com.rometools.modules.feedpress.io.FeedpressParser.class,
|
com.rometools.modules.yahooweather.io.WeatherModuleParser.class, com.rometools.modules.feedpress.io.FeedpressParser.class,
|
||||||
com.rometools.modules.fyyd.io.FyydParser.class,
|
com.rometools.modules.fyyd.io.FyydParser.class,
|
||||||
|
|
||||||
com.rometools.modules.cc.io.ModuleParserRSS1.class, com.rometools.modules.content.io.ContentModuleParser.class,
|
com.rometools.modules.cc.io.ModuleParserRSS1.class, com.rometools.modules.content.io.ContentModuleParser.class,
|
||||||
|
|
||||||
com.rometools.modules.cc.io.ModuleParserRSS2.class, com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class,
|
com.rometools.modules.cc.io.ModuleParserRSS2.class, com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class,
|
||||||
com.rometools.modules.georss.SimpleParser.class, com.rometools.modules.georss.W3CGeoParser.class,
|
com.rometools.modules.georss.SimpleParser.class, com.rometools.modules.georss.W3CGeoParser.class,
|
||||||
com.rometools.modules.photocast.io.Parser.class, com.rometools.modules.mediarss.io.MediaModuleParser.class,
|
com.rometools.modules.photocast.io.Parser.class, com.rometools.modules.mediarss.io.MediaModuleParser.class,
|
||||||
com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class,
|
com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class,
|
||||||
|
|
||||||
com.rometools.modules.cc.io.ModuleParserRSS2.class, com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class,
|
com.rometools.modules.cc.io.ModuleParserRSS2.class, com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class,
|
||||||
com.rometools.modules.georss.SimpleParser.class, com.rometools.modules.georss.W3CGeoParser.class,
|
com.rometools.modules.georss.SimpleParser.class, com.rometools.modules.georss.W3CGeoParser.class,
|
||||||
com.rometools.modules.photocast.io.Parser.class, com.rometools.modules.mediarss.io.MediaModuleParser.class,
|
com.rometools.modules.photocast.io.Parser.class, com.rometools.modules.mediarss.io.MediaModuleParser.class,
|
||||||
com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class,
|
com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class,
|
||||||
com.rometools.modules.feedpress.io.FeedpressParser.class, com.rometools.modules.fyyd.io.FyydParser.class,
|
com.rometools.modules.feedpress.io.FeedpressParser.class, com.rometools.modules.fyyd.io.FyydParser.class,
|
||||||
|
|
||||||
com.rometools.modules.cc.io.ModuleParserRSS2.class, com.rometools.modules.base.io.GoogleBaseParser.class,
|
com.rometools.modules.cc.io.ModuleParserRSS2.class, com.rometools.modules.base.io.GoogleBaseParser.class,
|
||||||
com.rometools.modules.content.io.ContentModuleParser.class, com.rometools.modules.slash.io.SlashModuleParser.class,
|
com.rometools.modules.content.io.ContentModuleParser.class, com.rometools.modules.slash.io.SlashModuleParser.class,
|
||||||
com.rometools.modules.itunes.io.ITunesParser.class, com.rometools.modules.mediarss.io.MediaModuleParser.class,
|
com.rometools.modules.itunes.io.ITunesParser.class, com.rometools.modules.mediarss.io.MediaModuleParser.class,
|
||||||
com.rometools.modules.atom.io.AtomModuleParser.class, com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class,
|
com.rometools.modules.atom.io.AtomModuleParser.class, com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class,
|
||||||
com.rometools.modules.georss.SimpleParser.class, com.rometools.modules.georss.W3CGeoParser.class,
|
com.rometools.modules.georss.SimpleParser.class, com.rometools.modules.georss.W3CGeoParser.class,
|
||||||
com.rometools.modules.photocast.io.Parser.class, com.rometools.modules.itunes.io.ITunesParserOldNamespace.class,
|
com.rometools.modules.photocast.io.Parser.class, com.rometools.modules.itunes.io.ITunesParserOldNamespace.class,
|
||||||
com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class, com.rometools.modules.sle.io.ItemParser.class,
|
com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class, com.rometools.modules.sle.io.ItemParser.class,
|
||||||
com.rometools.modules.yahooweather.io.WeatherModuleParser.class,
|
com.rometools.modules.yahooweather.io.WeatherModuleParser.class,
|
||||||
com.rometools.modules.psc.io.PodloveSimpleChapterParser.class,
|
com.rometools.modules.psc.io.PodloveSimpleChapterParser.class,
|
||||||
|
|
||||||
com.rometools.modules.cc.io.ModuleParserRSS1.class, com.rometools.modules.base.io.GoogleBaseParser.class,
|
com.rometools.modules.cc.io.ModuleParserRSS1.class, com.rometools.modules.base.io.GoogleBaseParser.class,
|
||||||
com.rometools.modules.base.io.CustomTagParser.class, com.rometools.modules.content.io.ContentModuleParser.class,
|
com.rometools.modules.base.io.CustomTagParser.class, com.rometools.modules.content.io.ContentModuleParser.class,
|
||||||
com.rometools.modules.slash.io.SlashModuleParser.class,
|
com.rometools.modules.slash.io.SlashModuleParser.class,
|
||||||
|
|
||||||
com.rometools.modules.cc.io.ModuleParserRSS2.class, com.rometools.modules.base.io.GoogleBaseParser.class,
|
com.rometools.modules.cc.io.ModuleParserRSS2.class, com.rometools.modules.base.io.GoogleBaseParser.class,
|
||||||
com.rometools.modules.base.io.CustomTagParser.class, com.rometools.modules.slash.io.SlashModuleParser.class,
|
com.rometools.modules.base.io.CustomTagParser.class, com.rometools.modules.slash.io.SlashModuleParser.class,
|
||||||
com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class, com.rometools.modules.georss.SimpleParser.class,
|
com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class, com.rometools.modules.georss.SimpleParser.class,
|
||||||
com.rometools.modules.georss.W3CGeoParser.class, com.rometools.modules.photocast.io.Parser.class,
|
com.rometools.modules.georss.W3CGeoParser.class, com.rometools.modules.photocast.io.Parser.class,
|
||||||
com.rometools.modules.mediarss.io.MediaModuleParser.class,
|
com.rometools.modules.mediarss.io.MediaModuleParser.class,
|
||||||
com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class,
|
com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class,
|
||||||
|
|
||||||
com.rometools.modules.cc.io.ModuleParserRSS2.class, com.rometools.modules.base.io.GoogleBaseParser.class,
|
com.rometools.modules.cc.io.ModuleParserRSS2.class, com.rometools.modules.base.io.GoogleBaseParser.class,
|
||||||
com.rometools.modules.base.io.CustomTagParser.class, com.rometools.modules.slash.io.SlashModuleParser.class,
|
com.rometools.modules.base.io.CustomTagParser.class, com.rometools.modules.slash.io.SlashModuleParser.class,
|
||||||
com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class, com.rometools.modules.georss.SimpleParser.class,
|
com.rometools.modules.opensearch.impl.OpenSearchModuleParser.class, com.rometools.modules.georss.SimpleParser.class,
|
||||||
com.rometools.modules.georss.W3CGeoParser.class, com.rometools.modules.photocast.io.Parser.class,
|
com.rometools.modules.georss.W3CGeoParser.class, com.rometools.modules.photocast.io.Parser.class,
|
||||||
com.rometools.modules.mediarss.io.MediaModuleParser.class,
|
com.rometools.modules.mediarss.io.MediaModuleParser.class,
|
||||||
com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class,
|
com.rometools.modules.mediarss.io.AlternateMediaModuleParser.class,
|
||||||
com.rometools.modules.thr.io.ThreadingModuleParser.class, com.rometools.modules.psc.io.PodloveSimpleChapterParser.class,
|
com.rometools.modules.thr.io.ThreadingModuleParser.class, com.rometools.modules.psc.io.PodloveSimpleChapterParser.class,
|
||||||
|
|
||||||
com.rometools.modules.cc.io.CCModuleGenerator.class, com.rometools.modules.content.io.ContentModuleGenerator.class,
|
com.rometools.modules.cc.io.CCModuleGenerator.class, com.rometools.modules.content.io.ContentModuleGenerator.class,
|
||||||
com.rometools.modules.itunes.io.ITunesGenerator.class,
|
com.rometools.modules.itunes.io.ITunesGenerator.class,
|
||||||
com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator.class, com.rometools.modules.georss.SimpleGenerator.class,
|
com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator.class, com.rometools.modules.georss.SimpleGenerator.class,
|
||||||
com.rometools.modules.georss.W3CGeoGenerator.class, com.rometools.modules.photocast.io.Generator.class,
|
com.rometools.modules.georss.W3CGeoGenerator.class, com.rometools.modules.photocast.io.Generator.class,
|
||||||
com.rometools.modules.mediarss.io.MediaModuleGenerator.class, com.rometools.modules.atom.io.AtomModuleGenerator.class,
|
com.rometools.modules.mediarss.io.MediaModuleGenerator.class, com.rometools.modules.atom.io.AtomModuleGenerator.class,
|
||||||
com.rometools.modules.sle.io.ModuleGenerator.class, com.rometools.modules.yahooweather.io.WeatherModuleGenerator.class,
|
com.rometools.modules.sle.io.ModuleGenerator.class, com.rometools.modules.yahooweather.io.WeatherModuleGenerator.class,
|
||||||
com.rometools.modules.feedpress.io.FeedpressGenerator.class, com.rometools.modules.fyyd.io.FyydGenerator.class,
|
com.rometools.modules.feedpress.io.FeedpressGenerator.class, com.rometools.modules.fyyd.io.FyydGenerator.class,
|
||||||
|
|
||||||
com.rometools.modules.content.io.ContentModuleGenerator.class,
|
com.rometools.modules.content.io.ContentModuleGenerator.class,
|
||||||
|
|
||||||
com.rometools.modules.cc.io.CCModuleGenerator.class, com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator.class,
|
com.rometools.modules.cc.io.CCModuleGenerator.class, com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator.class,
|
||||||
com.rometools.modules.georss.SimpleGenerator.class, com.rometools.modules.georss.W3CGeoGenerator.class,
|
com.rometools.modules.georss.SimpleGenerator.class, com.rometools.modules.georss.W3CGeoGenerator.class,
|
||||||
com.rometools.modules.photocast.io.Generator.class, com.rometools.modules.mediarss.io.MediaModuleGenerator.class,
|
com.rometools.modules.photocast.io.Generator.class, com.rometools.modules.mediarss.io.MediaModuleGenerator.class,
|
||||||
|
|
||||||
com.rometools.modules.cc.io.CCModuleGenerator.class, com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator.class,
|
com.rometools.modules.cc.io.CCModuleGenerator.class, com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator.class,
|
||||||
com.rometools.modules.georss.SimpleGenerator.class, com.rometools.modules.georss.W3CGeoGenerator.class,
|
com.rometools.modules.georss.SimpleGenerator.class, com.rometools.modules.georss.W3CGeoGenerator.class,
|
||||||
com.rometools.modules.photocast.io.Generator.class, com.rometools.modules.mediarss.io.MediaModuleGenerator.class,
|
com.rometools.modules.photocast.io.Generator.class, com.rometools.modules.mediarss.io.MediaModuleGenerator.class,
|
||||||
com.rometools.modules.feedpress.io.FeedpressGenerator.class, com.rometools.modules.fyyd.io.FyydGenerator.class,
|
com.rometools.modules.feedpress.io.FeedpressGenerator.class, com.rometools.modules.fyyd.io.FyydGenerator.class,
|
||||||
|
|
||||||
com.rometools.modules.cc.io.CCModuleGenerator.class, com.rometools.modules.base.io.GoogleBaseGenerator.class,
|
com.rometools.modules.cc.io.CCModuleGenerator.class, com.rometools.modules.base.io.GoogleBaseGenerator.class,
|
||||||
com.rometools.modules.base.io.CustomTagGenerator.class, com.rometools.modules.content.io.ContentModuleGenerator.class,
|
com.rometools.modules.base.io.CustomTagGenerator.class, com.rometools.modules.content.io.ContentModuleGenerator.class,
|
||||||
com.rometools.modules.slash.io.SlashModuleGenerator.class, com.rometools.modules.itunes.io.ITunesGenerator.class,
|
com.rometools.modules.slash.io.SlashModuleGenerator.class, com.rometools.modules.itunes.io.ITunesGenerator.class,
|
||||||
com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator.class, com.rometools.modules.georss.SimpleGenerator.class,
|
com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator.class, com.rometools.modules.georss.SimpleGenerator.class,
|
||||||
com.rometools.modules.georss.W3CGeoGenerator.class, com.rometools.modules.photocast.io.Generator.class,
|
com.rometools.modules.georss.W3CGeoGenerator.class, com.rometools.modules.photocast.io.Generator.class,
|
||||||
com.rometools.modules.mediarss.io.MediaModuleGenerator.class, com.rometools.modules.atom.io.AtomModuleGenerator.class,
|
com.rometools.modules.mediarss.io.MediaModuleGenerator.class, com.rometools.modules.atom.io.AtomModuleGenerator.class,
|
||||||
com.rometools.modules.yahooweather.io.WeatherModuleGenerator.class,
|
com.rometools.modules.yahooweather.io.WeatherModuleGenerator.class,
|
||||||
com.rometools.modules.psc.io.PodloveSimpleChapterGenerator.class,
|
com.rometools.modules.psc.io.PodloveSimpleChapterGenerator.class,
|
||||||
|
|
||||||
com.rometools.modules.base.io.GoogleBaseGenerator.class, com.rometools.modules.content.io.ContentModuleGenerator.class,
|
com.rometools.modules.base.io.GoogleBaseGenerator.class, com.rometools.modules.content.io.ContentModuleGenerator.class,
|
||||||
com.rometools.modules.slash.io.SlashModuleGenerator.class,
|
com.rometools.modules.slash.io.SlashModuleGenerator.class,
|
||||||
|
|
||||||
com.rometools.modules.cc.io.CCModuleGenerator.class, com.rometools.modules.base.io.GoogleBaseGenerator.class,
|
com.rometools.modules.cc.io.CCModuleGenerator.class, com.rometools.modules.base.io.GoogleBaseGenerator.class,
|
||||||
com.rometools.modules.base.io.CustomTagGenerator.class, com.rometools.modules.slash.io.SlashModuleGenerator.class,
|
com.rometools.modules.base.io.CustomTagGenerator.class, com.rometools.modules.slash.io.SlashModuleGenerator.class,
|
||||||
com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator.class, com.rometools.modules.georss.SimpleGenerator.class,
|
com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator.class, com.rometools.modules.georss.SimpleGenerator.class,
|
||||||
com.rometools.modules.georss.W3CGeoGenerator.class, com.rometools.modules.photocast.io.Generator.class,
|
com.rometools.modules.georss.W3CGeoGenerator.class, com.rometools.modules.photocast.io.Generator.class,
|
||||||
com.rometools.modules.mediarss.io.MediaModuleGenerator.class,
|
com.rometools.modules.mediarss.io.MediaModuleGenerator.class,
|
||||||
|
|
||||||
com.rometools.modules.cc.io.CCModuleGenerator.class, com.rometools.modules.base.io.CustomTagGenerator.class,
|
com.rometools.modules.cc.io.CCModuleGenerator.class, com.rometools.modules.base.io.CustomTagGenerator.class,
|
||||||
com.rometools.modules.slash.io.SlashModuleGenerator.class,
|
com.rometools.modules.slash.io.SlashModuleGenerator.class,
|
||||||
com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator.class, com.rometools.modules.georss.SimpleGenerator.class,
|
com.rometools.modules.opensearch.impl.OpenSearchModuleGenerator.class, com.rometools.modules.georss.SimpleGenerator.class,
|
||||||
com.rometools.modules.georss.W3CGeoGenerator.class, com.rometools.modules.photocast.io.Generator.class,
|
com.rometools.modules.georss.W3CGeoGenerator.class, com.rometools.modules.photocast.io.Generator.class,
|
||||||
com.rometools.modules.mediarss.io.MediaModuleGenerator.class, com.rometools.modules.thr.io.ThreadingModuleGenerator.class,
|
com.rometools.modules.mediarss.io.MediaModuleGenerator.class, com.rometools.modules.thr.io.ThreadingModuleGenerator.class,
|
||||||
com.rometools.modules.psc.io.PodloveSimpleChapterGenerator.class,
|
com.rometools.modules.psc.io.PodloveSimpleChapterGenerator.class,
|
||||||
|
|
||||||
com.rometools.modules.mediarss.io.MediaModuleParser.class,
|
com.rometools.modules.mediarss.io.MediaModuleParser.class,
|
||||||
|
|
||||||
com.rometools.modules.mediarss.io.MediaModuleGenerator.class,
|
com.rometools.modules.mediarss.io.MediaModuleGenerator.class,
|
||||||
|
|
||||||
com.rometools.opml.io.impl.OPML10Generator.class, com.rometools.opml.io.impl.OPML20Generator.class,
|
com.rometools.opml.io.impl.OPML10Generator.class, com.rometools.opml.io.impl.OPML20Generator.class,
|
||||||
|
|
||||||
com.rometools.opml.io.impl.OPML10Parser.class, com.rometools.opml.io.impl.OPML20Parser.class,
|
com.rometools.opml.io.impl.OPML10Parser.class, com.rometools.opml.io.impl.OPML20Parser.class,
|
||||||
|
|
||||||
com.rometools.opml.feed.synd.impl.ConverterForOPML10.class, com.rometools.opml.feed.synd.impl.ConverterForOPML20.class, })
|
com.rometools.opml.feed.synd.impl.ConverterForOPML10.class, com.rometools.opml.feed.synd.impl.ConverterForOPML20.class, })
|
||||||
|
|
||||||
public class NativeImageClasses {
|
public class NativeImageClasses {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +1,29 @@
|
|||||||
package com.commafeed.backend;
|
package com.commafeed.backend;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
import com.google.common.hash.HashFunction;
|
import com.google.common.hash.HashFunction;
|
||||||
import com.google.common.hash.Hashing;
|
import com.google.common.hash.Hashing;
|
||||||
|
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
@UtilityClass
|
@UtilityClass
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public class Digests {
|
public class Digests {
|
||||||
|
|
||||||
public static String sha1Hex(byte[] input) {
|
public static String sha1Hex(byte[] input) {
|
||||||
return hashBytesToHex(Hashing.sha1(), input);
|
return hashBytesToHex(Hashing.sha1(), input);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String sha1Hex(String input) {
|
public static String sha1Hex(String input) {
|
||||||
return hashBytesToHex(Hashing.sha1(), input.getBytes(StandardCharsets.UTF_8));
|
return hashBytesToHex(Hashing.sha1(), input.getBytes(StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String md5Hex(String input) {
|
public static String md5Hex(String input) {
|
||||||
return hashBytesToHex(Hashing.md5(), input.getBytes(StandardCharsets.UTF_8));
|
return hashBytesToHex(Hashing.md5(), input.getBytes(StandardCharsets.UTF_8));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String hashBytesToHex(HashFunction function, byte[] input) {
|
private static String hashBytesToHex(HashFunction function, byte[] input) {
|
||||||
return function.hashBytes(input).toString();
|
return function.hashBytes(input).toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,427 +1,421 @@
|
|||||||
package com.commafeed.backend;
|
package com.commafeed.backend;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.InstantSource;
|
import java.time.InstantSource;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import jakarta.inject.Singleton;
|
||||||
import org.apache.hc.client5.http.DnsResolver;
|
import jakarta.ws.rs.core.CacheControl;
|
||||||
import org.apache.hc.client5.http.SystemDefaultDnsResolver;
|
|
||||||
import org.apache.hc.client5.http.config.ConnectionConfig;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.hc.client5.http.config.RequestConfig;
|
import org.apache.hc.client5.http.DnsResolver;
|
||||||
import org.apache.hc.client5.http.config.TlsConfig;
|
import org.apache.hc.client5.http.SystemDefaultDnsResolver;
|
||||||
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
import org.apache.hc.client5.http.config.ConnectionConfig;
|
||||||
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
|
import org.apache.hc.client5.http.config.RequestConfig;
|
||||||
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
|
import org.apache.hc.client5.http.config.TlsConfig;
|
||||||
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
|
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||||
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
|
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
|
||||||
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
|
||||||
import org.apache.hc.client5.http.protocol.RedirectLocations;
|
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
|
||||||
import org.apache.hc.client5.http.utils.DateUtils;
|
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
|
||||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||||
import org.apache.hc.core5.http.Header;
|
import org.apache.hc.client5.http.protocol.RedirectLocations;
|
||||||
import org.apache.hc.core5.http.HttpEntity;
|
import org.apache.hc.client5.http.utils.DateUtils;
|
||||||
import org.apache.hc.core5.http.HttpStatus;
|
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||||
import org.apache.hc.core5.http.NameValuePair;
|
import org.apache.hc.core5.http.Header;
|
||||||
import org.apache.hc.core5.http.io.support.ClassicRequestBuilder;
|
import org.apache.hc.core5.http.HttpEntity;
|
||||||
import org.apache.hc.core5.http.message.BasicHeader;
|
import org.apache.hc.core5.http.HttpStatus;
|
||||||
import org.apache.hc.core5.util.TimeValue;
|
import org.apache.hc.core5.http.NameValuePair;
|
||||||
import org.apache.hc.core5.util.Timeout;
|
import org.apache.hc.core5.http.io.support.ClassicRequestBuilder;
|
||||||
import org.jboss.resteasy.reactive.common.headers.CacheControlDelegate;
|
import org.apache.hc.core5.http.message.BasicHeader;
|
||||||
|
import org.apache.hc.core5.util.TimeValue;
|
||||||
import com.codahale.metrics.MetricRegistry;
|
import org.apache.hc.core5.util.Timeout;
|
||||||
import com.commafeed.CommaFeedConfiguration;
|
import org.jboss.resteasy.reactive.common.headers.CacheControlDelegate;
|
||||||
import com.commafeed.CommaFeedConfiguration.HttpClientCache;
|
|
||||||
import com.commafeed.CommaFeedVersion;
|
import com.codahale.metrics.MetricRegistry;
|
||||||
import com.google.common.cache.Cache;
|
import com.commafeed.CommaFeedConfiguration;
|
||||||
import com.google.common.cache.CacheBuilder;
|
import com.commafeed.CommaFeedConfiguration.HttpClientCache;
|
||||||
import com.google.common.collect.Iterables;
|
import com.commafeed.CommaFeedVersion;
|
||||||
import com.google.common.io.ByteStreams;
|
import com.google.common.cache.Cache;
|
||||||
import com.google.common.net.HttpHeaders;
|
import com.google.common.cache.CacheBuilder;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
import jakarta.inject.Singleton;
|
import com.google.common.io.ByteStreams;
|
||||||
import jakarta.ws.rs.core.CacheControl;
|
import com.google.common.net.HttpHeaders;
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.Builder;
|
||||||
import lombok.Getter;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.Getter;
|
||||||
import lombok.Value;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.Value;
|
||||||
import nl.altindag.ssl.SSLFactory;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import nl.altindag.ssl.apache5.util.Apache5SslUtils;
|
import nl.altindag.ssl.SSLFactory;
|
||||||
|
import nl.altindag.ssl.apache5.util.Apache5SslUtils;
|
||||||
/**
|
|
||||||
* Smart HTTP getter: handles gzip, ssl, last modified and etag headers
|
/**
|
||||||
*/
|
* Smart HTTP getter: handles gzip, ssl, last modified and etag headers
|
||||||
@Singleton
|
*/
|
||||||
@Slf4j
|
@Singleton
|
||||||
public class HttpGetter {
|
@Slf4j
|
||||||
|
public class HttpGetter {
|
||||||
private final CommaFeedConfiguration config;
|
|
||||||
private final InstantSource instantSource;
|
private final CommaFeedConfiguration config;
|
||||||
private final CloseableHttpClient client;
|
private final InstantSource instantSource;
|
||||||
private final Cache<HttpRequest, HttpResponse> cache;
|
private final CloseableHttpClient client;
|
||||||
private final DnsResolver dnsResolver = SystemDefaultDnsResolver.INSTANCE;
|
private final Cache<HttpRequest, HttpResponse> cache;
|
||||||
|
private final DnsResolver dnsResolver = SystemDefaultDnsResolver.INSTANCE;
|
||||||
public HttpGetter(CommaFeedConfiguration config, InstantSource instantSource, CommaFeedVersion version, MetricRegistry metrics) {
|
|
||||||
this.config = config;
|
public HttpGetter(CommaFeedConfiguration config, InstantSource instantSource, CommaFeedVersion version, MetricRegistry metrics) {
|
||||||
this.instantSource = instantSource;
|
this.config = config;
|
||||||
|
this.instantSource = instantSource;
|
||||||
PoolingHttpClientConnectionManager connectionManager = newConnectionManager(config);
|
|
||||||
String userAgent = config.httpClient()
|
PoolingHttpClientConnectionManager connectionManager = newConnectionManager(config);
|
||||||
.userAgent()
|
String userAgent = config.httpClient()
|
||||||
.orElseGet(() -> String.format("CommaFeed/%s (https://github.com/Athou/commafeed)", version.getVersion()));
|
.userAgent()
|
||||||
|
.orElseGet(() -> String.format("CommaFeed/%s (https://github.com/Athou/commafeed)", version.getVersion()));
|
||||||
this.client = newClient(connectionManager, userAgent, config.httpClient().idleConnectionsEvictionInterval());
|
|
||||||
this.cache = newCache(config);
|
this.client = newClient(connectionManager, userAgent, config.httpClient().idleConnectionsEvictionInterval());
|
||||||
|
this.cache = newCache(config);
|
||||||
metrics.registerGauge(MetricRegistry.name(getClass(), "pool", "max"), () -> connectionManager.getTotalStats().getMax());
|
|
||||||
metrics.registerGauge(MetricRegistry.name(getClass(), "pool", "size"),
|
metrics.registerGauge(MetricRegistry.name(getClass(), "pool", "max"), () -> connectionManager.getTotalStats().getMax());
|
||||||
() -> connectionManager.getTotalStats().getAvailable() + connectionManager.getTotalStats().getLeased());
|
metrics.registerGauge(MetricRegistry.name(getClass(), "pool", "size"),
|
||||||
metrics.registerGauge(MetricRegistry.name(getClass(), "pool", "leased"), () -> connectionManager.getTotalStats().getLeased());
|
() -> connectionManager.getTotalStats().getAvailable() + connectionManager.getTotalStats().getLeased());
|
||||||
metrics.registerGauge(MetricRegistry.name(getClass(), "pool", "pending"), () -> connectionManager.getTotalStats().getPending());
|
metrics.registerGauge(MetricRegistry.name(getClass(), "pool", "leased"), () -> connectionManager.getTotalStats().getLeased());
|
||||||
metrics.registerGauge(MetricRegistry.name(getClass(), "cache", "size"), () -> cache == null ? 0 : cache.size());
|
metrics.registerGauge(MetricRegistry.name(getClass(), "pool", "pending"), () -> connectionManager.getTotalStats().getPending());
|
||||||
metrics.registerGauge(MetricRegistry.name(getClass(), "cache", "memoryUsage"),
|
metrics.registerGauge(MetricRegistry.name(getClass(), "cache", "size"), () -> cache == null ? 0 : cache.size());
|
||||||
() -> cache == null ? 0 : cache.asMap().values().stream().mapToInt(e -> e.content != null ? e.content.length : 0).sum());
|
metrics.registerGauge(MetricRegistry.name(getClass(), "cache", "memoryUsage"),
|
||||||
}
|
() -> cache == null ? 0 : cache.asMap().values().stream().mapToInt(e -> e.content != null ? e.content.length : 0).sum());
|
||||||
|
}
|
||||||
public HttpResult get(String url)
|
|
||||||
throws IOException, NotModifiedException, TooManyRequestsException, SchemeNotAllowedException, HostNotAllowedException {
|
public HttpResult get(String url)
|
||||||
return get(HttpRequest.builder(url).build());
|
throws IOException, NotModifiedException, TooManyRequestsException, SchemeNotAllowedException, HostNotAllowedException {
|
||||||
}
|
return get(HttpRequest.builder(url).build());
|
||||||
|
}
|
||||||
public HttpResult get(HttpRequest request)
|
|
||||||
throws IOException, NotModifiedException, TooManyRequestsException, SchemeNotAllowedException, HostNotAllowedException {
|
public HttpResult get(HttpRequest request)
|
||||||
URI uri = URI.create(request.getUrl());
|
throws IOException, NotModifiedException, TooManyRequestsException, SchemeNotAllowedException, HostNotAllowedException {
|
||||||
ensureHttpScheme(uri.getScheme());
|
URI uri = URI.create(request.getUrl());
|
||||||
|
ensureHttpScheme(uri.getScheme());
|
||||||
if (config.httpClient().blockLocalAddresses()) {
|
|
||||||
ensurePublicAddress(uri.getHost());
|
if (config.httpClient().blockLocalAddresses()) {
|
||||||
}
|
ensurePublicAddress(uri.getHost());
|
||||||
|
}
|
||||||
final HttpResponse response;
|
|
||||||
if (cache == null) {
|
final HttpResponse response;
|
||||||
response = invoke(request);
|
if (cache == null) {
|
||||||
} else {
|
response = invoke(request);
|
||||||
try {
|
} else {
|
||||||
response = cache.get(request, () -> invoke(request));
|
try {
|
||||||
} catch (ExecutionException e) {
|
response = cache.get(request, () -> invoke(request));
|
||||||
if (e.getCause() instanceof IOException ioe) {
|
} catch (ExecutionException e) {
|
||||||
throw ioe;
|
if (e.getCause() instanceof IOException ioe) {
|
||||||
} else {
|
throw ioe;
|
||||||
throw new RuntimeException(e);
|
} else {
|
||||||
}
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
int code = response.getCode();
|
|
||||||
if (code == HttpStatus.SC_TOO_MANY_REQUESTS || code == HttpStatus.SC_SERVICE_UNAVAILABLE && response.getRetryAfter() != null) {
|
int code = response.getCode();
|
||||||
throw new TooManyRequestsException(response.getRetryAfter());
|
if (code == HttpStatus.SC_TOO_MANY_REQUESTS || code == HttpStatus.SC_SERVICE_UNAVAILABLE && response.getRetryAfter() != null) {
|
||||||
}
|
throw new TooManyRequestsException(response.getRetryAfter());
|
||||||
|
}
|
||||||
if (code == HttpStatus.SC_NOT_MODIFIED) {
|
|
||||||
throw new NotModifiedException("'304 - not modified' http code received");
|
if (code == HttpStatus.SC_NOT_MODIFIED) {
|
||||||
}
|
throw new NotModifiedException("'304 - not modified' http code received");
|
||||||
|
}
|
||||||
if (code >= 300) {
|
|
||||||
throw new HttpResponseException(code, "Server returned HTTP error code " + code);
|
if (code >= 300) {
|
||||||
}
|
throw new HttpResponseException(code, "Server returned HTTP error code " + code);
|
||||||
|
}
|
||||||
String lastModifiedHeader = response.getLastModifiedHeader();
|
|
||||||
if (lastModifiedHeader != null && lastModifiedHeader.equals(request.getLastModified())) {
|
String lastModifiedHeader = response.getLastModifiedHeader();
|
||||||
throw new NotModifiedException("lastModifiedHeader is the same");
|
String eTagHeader = response.getETagHeader();
|
||||||
}
|
|
||||||
|
Duration validFor = Optional.ofNullable(response.getCacheControl())
|
||||||
String eTagHeader = response.getETagHeader();
|
.filter(cc -> cc.getMaxAge() >= 0)
|
||||||
if (eTagHeader != null && eTagHeader.equals(request.getETag())) {
|
.map(cc -> Duration.ofSeconds(cc.getMaxAge()))
|
||||||
throw new NotModifiedException("eTagHeader is the same");
|
.orElse(Duration.ZERO);
|
||||||
}
|
|
||||||
|
return new HttpResult(response.getContent(), response.getContentType(), lastModifiedHeader, eTagHeader,
|
||||||
Duration validFor = Optional.ofNullable(response.getCacheControl())
|
response.getUrlAfterRedirect(), validFor);
|
||||||
.filter(cc -> cc.getMaxAge() >= 0)
|
}
|
||||||
.map(cc -> Duration.ofSeconds(cc.getMaxAge()))
|
|
||||||
.orElse(Duration.ZERO);
|
private void ensureHttpScheme(String scheme) throws SchemeNotAllowedException {
|
||||||
|
if (!"http".equals(scheme) && !"https".equals(scheme)) {
|
||||||
return new HttpResult(response.getContent(), response.getContentType(), lastModifiedHeader, eTagHeader,
|
throw new SchemeNotAllowedException(scheme);
|
||||||
response.getUrlAfterRedirect(), validFor);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureHttpScheme(String scheme) throws SchemeNotAllowedException {
|
private void ensurePublicAddress(String host) throws HostNotAllowedException, UnknownHostException {
|
||||||
if (!"http".equals(scheme) && !"https".equals(scheme)) {
|
if (host == null) {
|
||||||
throw new SchemeNotAllowedException(scheme);
|
throw new HostNotAllowedException(null);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
InetAddress[] addresses = dnsResolver.resolve(host);
|
||||||
private void ensurePublicAddress(String host) throws HostNotAllowedException, UnknownHostException {
|
if (Stream.of(addresses).anyMatch(this::isPrivateAddress)) {
|
||||||
if (host == null) {
|
throw new HostNotAllowedException(host);
|
||||||
throw new HostNotAllowedException(null);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InetAddress[] addresses = dnsResolver.resolve(host);
|
private boolean isPrivateAddress(InetAddress address) {
|
||||||
if (Stream.of(addresses).anyMatch(this::isPrivateAddress)) {
|
return address.isSiteLocalAddress() || address.isAnyLocalAddress() || address.isLinkLocalAddress() || address.isLoopbackAddress()
|
||||||
throw new HostNotAllowedException(host);
|
|| address.isMulticastAddress();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private HttpResponse invoke(HttpRequest request) throws IOException {
|
||||||
private boolean isPrivateAddress(InetAddress address) {
|
log.debug("fetching {}", request.getUrl());
|
||||||
return address.isSiteLocalAddress() || address.isAnyLocalAddress() || address.isLinkLocalAddress() || address.isLoopbackAddress()
|
|
||||||
|| address.isMulticastAddress();
|
HttpClientContext context = HttpClientContext.create();
|
||||||
}
|
context.setRequestConfig(RequestConfig.custom()
|
||||||
|
.setResponseTimeout(Timeout.of(config.httpClient().responseTimeout()))
|
||||||
private HttpResponse invoke(HttpRequest request) throws IOException {
|
// causes issues with some feeds
|
||||||
log.debug("fetching {}", request.getUrl());
|
// see https://github.com/Athou/commafeed/issues/1572
|
||||||
|
// and https://issues.apache.org/jira/browse/HTTPCLIENT-2344
|
||||||
HttpClientContext context = HttpClientContext.create();
|
.setProtocolUpgradeEnabled(false)
|
||||||
context.setRequestConfig(RequestConfig.custom()
|
.build());
|
||||||
.setResponseTimeout(Timeout.of(config.httpClient().responseTimeout()))
|
|
||||||
// causes issues with some feeds
|
return client.execute(request.toClassicHttpRequest(), context, resp -> {
|
||||||
// see https://github.com/Athou/commafeed/issues/1572
|
byte[] content = resp.getEntity() == null ? null
|
||||||
// and https://issues.apache.org/jira/browse/HTTPCLIENT-2344
|
: toByteArray(resp.getEntity(), config.httpClient().maxResponseSize().asLongValue());
|
||||||
.setProtocolUpgradeEnabled(false)
|
int code = resp.getCode();
|
||||||
.build());
|
String lastModifiedHeader = Optional.ofNullable(resp.getFirstHeader(HttpHeaders.LAST_MODIFIED))
|
||||||
|
.map(NameValuePair::getValue)
|
||||||
return client.execute(request.toClassicHttpRequest(), context, resp -> {
|
.map(StringUtils::trimToNull)
|
||||||
byte[] content = resp.getEntity() == null ? null
|
.orElse(null);
|
||||||
: toByteArray(resp.getEntity(), config.httpClient().maxResponseSize().asLongValue());
|
String eTagHeader = Optional.ofNullable(resp.getFirstHeader(HttpHeaders.ETAG))
|
||||||
int code = resp.getCode();
|
.map(NameValuePair::getValue)
|
||||||
String lastModifiedHeader = Optional.ofNullable(resp.getFirstHeader(HttpHeaders.LAST_MODIFIED))
|
.map(StringUtils::trimToNull)
|
||||||
.map(NameValuePair::getValue)
|
.orElse(null);
|
||||||
.map(StringUtils::trimToNull)
|
|
||||||
.orElse(null);
|
CacheControl cacheControl = Optional.ofNullable(resp.getFirstHeader(HttpHeaders.CACHE_CONTROL))
|
||||||
String eTagHeader = Optional.ofNullable(resp.getFirstHeader(HttpHeaders.ETAG))
|
.map(NameValuePair::getValue)
|
||||||
.map(NameValuePair::getValue)
|
.map(StringUtils::trimToNull)
|
||||||
.map(StringUtils::trimToNull)
|
.map(HttpGetter::toCacheControl)
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
|
|
||||||
CacheControl cacheControl = Optional.ofNullable(resp.getFirstHeader(HttpHeaders.CACHE_CONTROL))
|
Instant retryAfter = Optional.ofNullable(resp.getFirstHeader(HttpHeaders.RETRY_AFTER))
|
||||||
.map(NameValuePair::getValue)
|
.map(NameValuePair::getValue)
|
||||||
.map(StringUtils::trimToNull)
|
.map(StringUtils::trimToNull)
|
||||||
.map(HttpGetter::toCacheControl)
|
.map(this::toInstant)
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
|
|
||||||
Instant retryAfter = Optional.ofNullable(resp.getFirstHeader(HttpHeaders.RETRY_AFTER))
|
String contentType = Optional.ofNullable(resp.getEntity()).map(HttpEntity::getContentType).orElse(null);
|
||||||
.map(NameValuePair::getValue)
|
String urlAfterRedirect = Optional.ofNullable(context.getRedirectLocations())
|
||||||
.map(StringUtils::trimToNull)
|
.map(RedirectLocations::getAll)
|
||||||
.map(this::toInstant)
|
.map(l -> Iterables.getLast(l, null))
|
||||||
.orElse(null);
|
.map(URI::toString)
|
||||||
|
.orElse(request.getUrl());
|
||||||
String contentType = Optional.ofNullable(resp.getEntity()).map(HttpEntity::getContentType).orElse(null);
|
|
||||||
String urlAfterRedirect = Optional.ofNullable(context.getRedirectLocations())
|
return new HttpResponse(code, lastModifiedHeader, eTagHeader, cacheControl, retryAfter, content, contentType, urlAfterRedirect);
|
||||||
.map(RedirectLocations::getAll)
|
});
|
||||||
.map(l -> Iterables.getLast(l, null))
|
}
|
||||||
.map(URI::toString)
|
|
||||||
.orElse(request.getUrl());
|
private static CacheControl toCacheControl(String headerValue) {
|
||||||
|
try {
|
||||||
return new HttpResponse(code, lastModifiedHeader, eTagHeader, cacheControl, retryAfter, content, contentType, urlAfterRedirect);
|
return CacheControlDelegate.INSTANCE.fromString(headerValue);
|
||||||
});
|
} catch (Exception e) {
|
||||||
}
|
log.debug("Invalid Cache-Control header: {}", headerValue);
|
||||||
|
return null;
|
||||||
private static CacheControl toCacheControl(String headerValue) {
|
}
|
||||||
try {
|
}
|
||||||
return CacheControlDelegate.INSTANCE.fromString(headerValue);
|
|
||||||
} catch (Exception e) {
|
private Instant toInstant(String headerValue) {
|
||||||
log.debug("Invalid Cache-Control header: {}", headerValue);
|
if (headerValue == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if (StringUtils.isNumeric(headerValue)) {
|
||||||
private Instant toInstant(String headerValue) {
|
return instantSource.instant().plusSeconds(Long.parseLong(headerValue));
|
||||||
if (headerValue == null) {
|
}
|
||||||
return null;
|
|
||||||
}
|
return DateUtils.parseStandardDate(headerValue);
|
||||||
|
}
|
||||||
if (StringUtils.isNumeric(headerValue)) {
|
|
||||||
return instantSource.instant().plusSeconds(Long.parseLong(headerValue));
|
private static byte[] toByteArray(HttpEntity entity, long maxBytes) throws IOException {
|
||||||
}
|
if (entity.getContentLength() > maxBytes) {
|
||||||
|
throw new IOException(
|
||||||
return DateUtils.parseStandardDate(headerValue);
|
"Response size (%s bytes) exceeds the maximum allowed size (%s bytes)".formatted(entity.getContentLength(), maxBytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] toByteArray(HttpEntity entity, long maxBytes) throws IOException {
|
try (InputStream input = entity.getContent()) {
|
||||||
if (entity.getContentLength() > maxBytes) {
|
if (input == null) {
|
||||||
throw new IOException(
|
return null;
|
||||||
"Response size (%s bytes) exceeds the maximum allowed size (%s bytes)".formatted(entity.getContentLength(), maxBytes));
|
}
|
||||||
}
|
|
||||||
|
byte[] bytes = ByteStreams.limit(input, maxBytes).readAllBytes();
|
||||||
try (InputStream input = entity.getContent()) {
|
if (bytes.length == maxBytes) {
|
||||||
if (input == null) {
|
throw new IOException("Response size exceeds the maximum allowed size (%s bytes)".formatted(maxBytes));
|
||||||
return null;
|
}
|
||||||
}
|
return bytes;
|
||||||
|
}
|
||||||
byte[] bytes = ByteStreams.limit(input, maxBytes).readAllBytes();
|
}
|
||||||
if (bytes.length == maxBytes) {
|
|
||||||
throw new IOException("Response size exceeds the maximum allowed size (%s bytes)".formatted(maxBytes));
|
private PoolingHttpClientConnectionManager newConnectionManager(CommaFeedConfiguration config) {
|
||||||
}
|
SSLFactory sslFactory = SSLFactory.builder().withUnsafeTrustMaterial().withUnsafeHostnameVerifier().build();
|
||||||
return bytes;
|
|
||||||
}
|
int poolSize = config.feedRefresh().httpThreads();
|
||||||
}
|
return PoolingHttpClientConnectionManagerBuilder.create()
|
||||||
|
.setTlsSocketStrategy(Apache5SslUtils.toTlsSocketStrategy(sslFactory))
|
||||||
private PoolingHttpClientConnectionManager newConnectionManager(CommaFeedConfiguration config) {
|
.setDefaultConnectionConfig(ConnectionConfig.custom()
|
||||||
SSLFactory sslFactory = SSLFactory.builder().withUnsafeTrustMaterial().withUnsafeHostnameVerifier().build();
|
.setConnectTimeout(Timeout.of(config.httpClient().connectTimeout()))
|
||||||
|
.setSocketTimeout(Timeout.of(config.httpClient().socketTimeout()))
|
||||||
int poolSize = config.feedRefresh().httpThreads();
|
.setTimeToLive(Timeout.of(config.httpClient().connectionTimeToLive()))
|
||||||
return PoolingHttpClientConnectionManagerBuilder.create()
|
.build())
|
||||||
.setTlsSocketStrategy(Apache5SslUtils.toTlsSocketStrategy(sslFactory))
|
.setDefaultTlsConfig(TlsConfig.custom().setHandshakeTimeout(Timeout.of(config.httpClient().sslHandshakeTimeout())).build())
|
||||||
.setDefaultConnectionConfig(ConnectionConfig.custom()
|
.setMaxConnPerRoute(poolSize)
|
||||||
.setConnectTimeout(Timeout.of(config.httpClient().connectTimeout()))
|
.setMaxConnTotal(poolSize)
|
||||||
.setSocketTimeout(Timeout.of(config.httpClient().socketTimeout()))
|
.setDnsResolver(dnsResolver)
|
||||||
.setTimeToLive(Timeout.of(config.httpClient().connectionTimeToLive()))
|
.build();
|
||||||
.build())
|
|
||||||
.setDefaultTlsConfig(TlsConfig.custom().setHandshakeTimeout(Timeout.of(config.httpClient().sslHandshakeTimeout())).build())
|
}
|
||||||
.setMaxConnPerRoute(poolSize)
|
|
||||||
.setMaxConnTotal(poolSize)
|
private static CloseableHttpClient newClient(HttpClientConnectionManager connectionManager, String userAgent,
|
||||||
.setDnsResolver(dnsResolver)
|
Duration idleConnectionsEvictionInterval) {
|
||||||
.build();
|
List<Header> headers = new ArrayList<>();
|
||||||
|
headers.add(new BasicHeader(HttpHeaders.ACCEPT_LANGUAGE, "en"));
|
||||||
}
|
headers.add(new BasicHeader(HttpHeaders.PRAGMA, "No-cache"));
|
||||||
|
headers.add(new BasicHeader(HttpHeaders.CACHE_CONTROL, "no-cache"));
|
||||||
private static CloseableHttpClient newClient(HttpClientConnectionManager connectionManager, String userAgent,
|
|
||||||
Duration idleConnectionsEvictionInterval) {
|
return HttpClientBuilder.create()
|
||||||
List<Header> headers = new ArrayList<>();
|
.useSystemProperties()
|
||||||
headers.add(new BasicHeader(HttpHeaders.ACCEPT_LANGUAGE, "en"));
|
.disableAutomaticRetries()
|
||||||
headers.add(new BasicHeader(HttpHeaders.PRAGMA, "No-cache"));
|
.disableCookieManagement()
|
||||||
headers.add(new BasicHeader(HttpHeaders.CACHE_CONTROL, "no-cache"));
|
.setUserAgent(userAgent)
|
||||||
|
.setDefaultHeaders(headers)
|
||||||
return HttpClientBuilder.create()
|
.setConnectionManager(connectionManager)
|
||||||
.useSystemProperties()
|
.evictExpiredConnections()
|
||||||
.disableAutomaticRetries()
|
.evictIdleConnections(TimeValue.of(idleConnectionsEvictionInterval))
|
||||||
.disableCookieManagement()
|
.build();
|
||||||
.setUserAgent(userAgent)
|
}
|
||||||
.setDefaultHeaders(headers)
|
|
||||||
.setConnectionManager(connectionManager)
|
private static Cache<HttpRequest, HttpResponse> newCache(CommaFeedConfiguration config) {
|
||||||
.evictExpiredConnections()
|
HttpClientCache cacheConfig = config.httpClient().cache();
|
||||||
.evictIdleConnections(TimeValue.of(idleConnectionsEvictionInterval))
|
if (!cacheConfig.enabled()) {
|
||||||
.build();
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Cache<HttpRequest, HttpResponse> newCache(CommaFeedConfiguration config) {
|
return CacheBuilder.newBuilder()
|
||||||
HttpClientCache cacheConfig = config.httpClient().cache();
|
.weigher((HttpRequest key, HttpResponse value) -> value.getContent() != null ? value.getContent().length : 0)
|
||||||
if (!cacheConfig.enabled()) {
|
.maximumWeight(cacheConfig.maximumMemorySize().asLongValue())
|
||||||
return null;
|
.expireAfterWrite(cacheConfig.expiration())
|
||||||
}
|
.build();
|
||||||
|
}
|
||||||
return CacheBuilder.newBuilder()
|
|
||||||
.weigher((HttpRequest key, HttpResponse value) -> value.getContent() != null ? value.getContent().length : 0)
|
public static class SchemeNotAllowedException extends Exception {
|
||||||
.maximumWeight(cacheConfig.maximumMemorySize().asLongValue())
|
private static final long serialVersionUID = 1L;
|
||||||
.expireAfterWrite(cacheConfig.expiration())
|
|
||||||
.build();
|
public SchemeNotAllowedException(String scheme) {
|
||||||
}
|
super("Scheme not allowed: " + scheme);
|
||||||
|
}
|
||||||
public static class SchemeNotAllowedException extends Exception {
|
}
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
public static class HostNotAllowedException extends Exception {
|
||||||
public SchemeNotAllowedException(String scheme) {
|
private static final long serialVersionUID = 1L;
|
||||||
super("Scheme not allowed: " + scheme);
|
|
||||||
}
|
public HostNotAllowedException(String host) {
|
||||||
}
|
super("Host not allowed: " + host);
|
||||||
|
}
|
||||||
public static class HostNotAllowedException extends Exception {
|
}
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
@Getter
|
||||||
public HostNotAllowedException(String host) {
|
public static class NotModifiedException extends Exception {
|
||||||
super("Host not allowed: " + host);
|
private static final long serialVersionUID = 1L;
|
||||||
}
|
|
||||||
}
|
/**
|
||||||
|
* if the value of this header changed, this is its new value
|
||||||
@Getter
|
*/
|
||||||
public static class NotModifiedException extends Exception {
|
private final String newLastModifiedHeader;
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
/**
|
||||||
/**
|
* if the value of this header changed, this is its new value
|
||||||
* if the value of this header changed, this is its new value
|
*/
|
||||||
*/
|
private final String newEtagHeader;
|
||||||
private final String newLastModifiedHeader;
|
|
||||||
|
public NotModifiedException(String message) {
|
||||||
/**
|
this(message, null, null);
|
||||||
* if the value of this header changed, this is its new value
|
}
|
||||||
*/
|
|
||||||
private final String newEtagHeader;
|
public NotModifiedException(String message, String newLastModifiedHeader, String newEtagHeader) {
|
||||||
|
super(message);
|
||||||
public NotModifiedException(String message) {
|
this.newLastModifiedHeader = newLastModifiedHeader;
|
||||||
this(message, null, null);
|
this.newEtagHeader = newEtagHeader;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public NotModifiedException(String message, String newLastModifiedHeader, String newEtagHeader) {
|
|
||||||
super(message);
|
@RequiredArgsConstructor
|
||||||
this.newLastModifiedHeader = newLastModifiedHeader;
|
@Getter
|
||||||
this.newEtagHeader = newEtagHeader;
|
public static class TooManyRequestsException extends Exception {
|
||||||
}
|
private static final long serialVersionUID = 1L;
|
||||||
}
|
|
||||||
|
private final Instant retryAfter;
|
||||||
@RequiredArgsConstructor
|
}
|
||||||
@Getter
|
|
||||||
public static class TooManyRequestsException extends Exception {
|
@Getter
|
||||||
private static final long serialVersionUID = 1L;
|
public static class HttpResponseException extends IOException {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
private final Instant retryAfter;
|
|
||||||
}
|
private final int code;
|
||||||
|
|
||||||
@Getter
|
public HttpResponseException(int code, String message) {
|
||||||
public static class HttpResponseException extends IOException {
|
super(message);
|
||||||
private static final long serialVersionUID = 1L;
|
this.code = code;
|
||||||
|
}
|
||||||
private final int code;
|
}
|
||||||
|
|
||||||
public HttpResponseException(int code, String message) {
|
@Builder(builderMethodName = "")
|
||||||
super(message);
|
@EqualsAndHashCode
|
||||||
this.code = code;
|
@Getter
|
||||||
}
|
public static class HttpRequest {
|
||||||
}
|
private String url;
|
||||||
|
private String lastModified;
|
||||||
@Builder(builderMethodName = "")
|
private String eTag;
|
||||||
@EqualsAndHashCode
|
|
||||||
@Getter
|
public static HttpRequestBuilder builder(String url) {
|
||||||
public static class HttpRequest {
|
return new HttpRequestBuilder().url(url);
|
||||||
private String url;
|
}
|
||||||
private String lastModified;
|
|
||||||
private String eTag;
|
public ClassicHttpRequest toClassicHttpRequest() {
|
||||||
|
ClassicHttpRequest req = ClassicRequestBuilder.get(url).build();
|
||||||
public static HttpRequestBuilder builder(String url) {
|
if (lastModified != null) {
|
||||||
return new HttpRequestBuilder().url(url);
|
req.addHeader(HttpHeaders.IF_MODIFIED_SINCE, lastModified);
|
||||||
}
|
}
|
||||||
|
if (eTag != null) {
|
||||||
public ClassicHttpRequest toClassicHttpRequest() {
|
req.addHeader(HttpHeaders.IF_NONE_MATCH, eTag);
|
||||||
ClassicHttpRequest req = ClassicRequestBuilder.get(url).build();
|
}
|
||||||
if (lastModified != null) {
|
return req;
|
||||||
req.addHeader(HttpHeaders.IF_MODIFIED_SINCE, lastModified);
|
}
|
||||||
}
|
}
|
||||||
if (eTag != null) {
|
|
||||||
req.addHeader(HttpHeaders.IF_NONE_MATCH, eTag);
|
@Value
|
||||||
}
|
private static class HttpResponse {
|
||||||
return req;
|
int code;
|
||||||
}
|
String lastModifiedHeader;
|
||||||
}
|
String eTagHeader;
|
||||||
|
CacheControl cacheControl;
|
||||||
@Value
|
Instant retryAfter;
|
||||||
private static class HttpResponse {
|
byte[] content;
|
||||||
int code;
|
String contentType;
|
||||||
String lastModifiedHeader;
|
String urlAfterRedirect;
|
||||||
String eTagHeader;
|
}
|
||||||
CacheControl cacheControl;
|
|
||||||
Instant retryAfter;
|
@Value
|
||||||
byte[] content;
|
public static class HttpResult {
|
||||||
String contentType;
|
byte[] content;
|
||||||
String urlAfterRedirect;
|
String contentType;
|
||||||
}
|
String lastModifiedSince;
|
||||||
|
String eTag;
|
||||||
@Value
|
String urlAfterRedirect;
|
||||||
public static class HttpResult {
|
Duration validFor;
|
||||||
byte[] content;
|
}
|
||||||
String contentType;
|
|
||||||
String lastModifiedSince;
|
}
|
||||||
String eTag;
|
|
||||||
String urlAfterRedirect;
|
|
||||||
Duration validFor;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,71 +1,71 @@
|
|||||||
package com.commafeed.backend.dao;
|
package com.commafeed.backend.dao;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import com.commafeed.backend.model.FeedCategory;
|
import jakarta.inject.Singleton;
|
||||||
import com.commafeed.backend.model.QFeedCategory;
|
import jakarta.persistence.EntityManager;
|
||||||
import com.commafeed.backend.model.QUser;
|
|
||||||
import com.commafeed.backend.model.User;
|
import com.commafeed.backend.model.FeedCategory;
|
||||||
import com.querydsl.core.types.Predicate;
|
import com.commafeed.backend.model.QFeedCategory;
|
||||||
|
import com.commafeed.backend.model.QUser;
|
||||||
import jakarta.inject.Singleton;
|
import com.commafeed.backend.model.User;
|
||||||
import jakarta.persistence.EntityManager;
|
import com.querydsl.core.types.Predicate;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class FeedCategoryDAO extends GenericDAO<FeedCategory> {
|
public class FeedCategoryDAO extends GenericDAO<FeedCategory> {
|
||||||
|
|
||||||
private static final QFeedCategory CATEGORY = QFeedCategory.feedCategory;
|
private static final QFeedCategory CATEGORY = QFeedCategory.feedCategory;
|
||||||
|
|
||||||
public FeedCategoryDAO(EntityManager entityManager) {
|
public FeedCategoryDAO(EntityManager entityManager) {
|
||||||
super(entityManager, FeedCategory.class);
|
super(entityManager, FeedCategory.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<FeedCategory> findAll(User user) {
|
public List<FeedCategory> findAll(User user) {
|
||||||
return query().selectFrom(CATEGORY).where(CATEGORY.user.eq(user)).join(CATEGORY.user, QUser.user).fetchJoin().fetch();
|
return query().selectFrom(CATEGORY).where(CATEGORY.user.eq(user)).join(CATEGORY.user, QUser.user).fetchJoin().fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
public FeedCategory findById(User user, Long id) {
|
public FeedCategory findById(User user, Long id) {
|
||||||
return query().selectFrom(CATEGORY).where(CATEGORY.user.eq(user), CATEGORY.id.eq(id)).fetchOne();
|
return query().selectFrom(CATEGORY).where(CATEGORY.user.eq(user), CATEGORY.id.eq(id)).fetchOne();
|
||||||
}
|
}
|
||||||
|
|
||||||
public FeedCategory findByName(User user, String name, FeedCategory parent) {
|
public FeedCategory findByName(User user, String name, FeedCategory parent) {
|
||||||
Predicate parentPredicate;
|
Predicate parentPredicate;
|
||||||
if (parent == null) {
|
if (parent == null) {
|
||||||
parentPredicate = CATEGORY.parent.isNull();
|
parentPredicate = CATEGORY.parent.isNull();
|
||||||
} else {
|
} else {
|
||||||
parentPredicate = CATEGORY.parent.eq(parent);
|
parentPredicate = CATEGORY.parent.eq(parent);
|
||||||
}
|
}
|
||||||
return query().selectFrom(CATEGORY).where(CATEGORY.user.eq(user), CATEGORY.name.eq(name), parentPredicate).fetchOne();
|
return query().selectFrom(CATEGORY).where(CATEGORY.user.eq(user), CATEGORY.name.eq(name), parentPredicate).fetchOne();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<FeedCategory> findByParent(User user, FeedCategory parent) {
|
public List<FeedCategory> findByParent(User user, FeedCategory parent) {
|
||||||
Predicate parentPredicate;
|
Predicate parentPredicate;
|
||||||
if (parent == null) {
|
if (parent == null) {
|
||||||
parentPredicate = CATEGORY.parent.isNull();
|
parentPredicate = CATEGORY.parent.isNull();
|
||||||
} else {
|
} else {
|
||||||
parentPredicate = CATEGORY.parent.eq(parent);
|
parentPredicate = CATEGORY.parent.eq(parent);
|
||||||
}
|
}
|
||||||
return query().selectFrom(CATEGORY).where(CATEGORY.user.eq(user), parentPredicate).fetch();
|
return query().selectFrom(CATEGORY).where(CATEGORY.user.eq(user), parentPredicate).fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<FeedCategory> findAllChildrenCategories(User user, FeedCategory parent) {
|
public List<FeedCategory> findAllChildrenCategories(User user, FeedCategory parent) {
|
||||||
return findAll(user).stream().filter(c -> isChild(c, parent)).toList();
|
return findAll(user).stream().filter(c -> isChild(c, parent)).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isChild(FeedCategory child, FeedCategory parent) {
|
private boolean isChild(FeedCategory child, FeedCategory parent) {
|
||||||
if (parent == null) {
|
if (parent == null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
boolean isChild = false;
|
boolean isChild = false;
|
||||||
while (child != null) {
|
while (child != null) {
|
||||||
if (Objects.equals(child.getId(), parent.getId())) {
|
if (Objects.equals(child.getId(), parent.getId())) {
|
||||||
isChild = true;
|
isChild = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
child = child.getParent();
|
child = child.getParent();
|
||||||
}
|
}
|
||||||
return isChild;
|
return isChild;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,64 +1,64 @@
|
|||||||
package com.commafeed.backend.dao;
|
package com.commafeed.backend.dao;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import jakarta.inject.Singleton;
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
import com.commafeed.backend.model.Feed;
|
|
||||||
import com.commafeed.backend.model.QFeed;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import com.commafeed.backend.model.QFeedSubscription;
|
|
||||||
import com.querydsl.jpa.JPAExpressions;
|
import com.commafeed.backend.model.Feed;
|
||||||
import com.querydsl.jpa.impl.JPAQuery;
|
import com.commafeed.backend.model.QFeed;
|
||||||
|
import com.commafeed.backend.model.QFeedSubscription;
|
||||||
import jakarta.inject.Singleton;
|
import com.querydsl.jpa.JPAExpressions;
|
||||||
import jakarta.persistence.EntityManager;
|
import com.querydsl.jpa.impl.JPAQuery;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class FeedDAO extends GenericDAO<Feed> {
|
public class FeedDAO extends GenericDAO<Feed> {
|
||||||
|
|
||||||
private static final QFeed FEED = QFeed.feed;
|
private static final QFeed FEED = QFeed.feed;
|
||||||
private static final QFeedSubscription SUBSCRIPTION = QFeedSubscription.feedSubscription;
|
private static final QFeedSubscription SUBSCRIPTION = QFeedSubscription.feedSubscription;
|
||||||
|
|
||||||
public FeedDAO(EntityManager entityManager) {
|
public FeedDAO(EntityManager entityManager) {
|
||||||
super(entityManager, Feed.class);
|
super(entityManager, Feed.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Feed> findByIds(List<Long> id) {
|
public List<Feed> findByIds(List<Long> id) {
|
||||||
return query().selectFrom(FEED).where(FEED.id.in(id)).fetch();
|
return query().selectFrom(FEED).where(FEED.id.in(id)).fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Feed> findNextUpdatable(int count, Instant lastLoginThreshold) {
|
public List<Feed> findNextUpdatable(int count, Instant lastLoginThreshold) {
|
||||||
JPAQuery<Feed> query = query().selectFrom(FEED)
|
JPAQuery<Feed> query = query().selectFrom(FEED)
|
||||||
.distinct()
|
.distinct()
|
||||||
// join on subscriptions to only refresh feeds that have subscribers
|
// join on subscriptions to only refresh feeds that have subscribers
|
||||||
.join(SUBSCRIPTION)
|
.join(SUBSCRIPTION)
|
||||||
.on(SUBSCRIPTION.feed.eq(FEED))
|
.on(SUBSCRIPTION.feed.eq(FEED))
|
||||||
.where(FEED.disabledUntil.isNull().or(FEED.disabledUntil.lt(Instant.now())));
|
.where(FEED.disabledUntil.isNull().or(FEED.disabledUntil.lt(Instant.now())));
|
||||||
|
|
||||||
if (lastLoginThreshold != null) {
|
if (lastLoginThreshold != null) {
|
||||||
query.join(SUBSCRIPTION.user).where(SUBSCRIPTION.user.lastLogin.gt(lastLoginThreshold));
|
query.join(SUBSCRIPTION.user).where(SUBSCRIPTION.user.lastLogin.gt(lastLoginThreshold));
|
||||||
}
|
}
|
||||||
|
|
||||||
return query.orderBy(FEED.disabledUntil.asc()).limit(count).fetch();
|
return query.orderBy(FEED.disabledUntil.asc()).limit(count).fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDisabledUntil(List<Long> feedIds, Instant date) {
|
public void setDisabledUntil(List<Long> feedIds, Instant date) {
|
||||||
updateQuery(FEED).set(FEED.disabledUntil, date).where(FEED.id.in(feedIds)).execute();
|
updateQuery(FEED).set(FEED.disabledUntil, date).where(FEED.id.in(feedIds)).execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Feed findByUrl(String normalizedUrl, String normalizedUrlHash) {
|
public Feed findByUrl(String normalizedUrl, String normalizedUrlHash) {
|
||||||
return query().selectFrom(FEED)
|
return query().selectFrom(FEED)
|
||||||
.where(FEED.normalizedUrlHash.eq(normalizedUrlHash))
|
.where(FEED.normalizedUrlHash.eq(normalizedUrlHash))
|
||||||
.fetch()
|
.fetch()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(f -> StringUtils.equals(normalizedUrl, f.getNormalizedUrl()))
|
.filter(f -> StringUtils.equals(normalizedUrl, f.getNormalizedUrl()))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Feed> findWithoutSubscriptions(int max) {
|
public List<Feed> findWithoutSubscriptions(int max) {
|
||||||
QFeedSubscription sub = QFeedSubscription.feedSubscription;
|
QFeedSubscription sub = QFeedSubscription.feedSubscription;
|
||||||
return query().selectFrom(FEED).where(JPAExpressions.selectOne().from(sub).where(sub.feed.eq(FEED)).notExists()).limit(max).fetch();
|
return query().selectFrom(FEED).where(JPAExpressions.selectOne().from(sub).where(sub.feed.eq(FEED)).notExists()).limit(max).fetch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +1,36 @@
|
|||||||
package com.commafeed.backend.dao;
|
package com.commafeed.backend.dao;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.commafeed.backend.model.FeedEntryContent;
|
import jakarta.inject.Singleton;
|
||||||
import com.commafeed.backend.model.QFeedEntry;
|
import jakarta.persistence.EntityManager;
|
||||||
import com.commafeed.backend.model.QFeedEntryContent;
|
|
||||||
|
import com.commafeed.backend.model.FeedEntryContent;
|
||||||
import jakarta.inject.Singleton;
|
import com.commafeed.backend.model.QFeedEntry;
|
||||||
import jakarta.persistence.EntityManager;
|
import com.commafeed.backend.model.QFeedEntryContent;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class FeedEntryContentDAO extends GenericDAO<FeedEntryContent> {
|
public class FeedEntryContentDAO extends GenericDAO<FeedEntryContent> {
|
||||||
|
|
||||||
private static final QFeedEntryContent CONTENT = QFeedEntryContent.feedEntryContent;
|
private static final QFeedEntryContent CONTENT = QFeedEntryContent.feedEntryContent;
|
||||||
private static final QFeedEntry ENTRY = QFeedEntry.feedEntry;
|
private static final QFeedEntry ENTRY = QFeedEntry.feedEntry;
|
||||||
|
|
||||||
public FeedEntryContentDAO(EntityManager entityManager) {
|
public FeedEntryContentDAO(EntityManager entityManager) {
|
||||||
super(entityManager, FeedEntryContent.class);
|
super(entityManager, FeedEntryContent.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<FeedEntryContent> findExisting(String contentHash, String titleHash) {
|
public List<FeedEntryContent> findExisting(String contentHash, String titleHash) {
|
||||||
return query().select(CONTENT).from(CONTENT).where(CONTENT.contentHash.eq(contentHash), CONTENT.titleHash.eq(titleHash)).fetch();
|
return query().select(CONTENT).from(CONTENT).where(CONTENT.contentHash.eq(contentHash), CONTENT.titleHash.eq(titleHash)).fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
public long deleteWithoutEntries(int max) {
|
public long deleteWithoutEntries(int max) {
|
||||||
List<Long> ids = query().select(CONTENT.id)
|
List<Long> ids = query().select(CONTENT.id)
|
||||||
.from(CONTENT)
|
.from(CONTENT)
|
||||||
.leftJoin(ENTRY)
|
.leftJoin(ENTRY)
|
||||||
.on(ENTRY.content.id.eq(CONTENT.id))
|
.on(ENTRY.content.id.eq(CONTENT.id))
|
||||||
.where(ENTRY.id.isNull())
|
.where(ENTRY.id.isNull())
|
||||||
.limit(max)
|
.limit(max)
|
||||||
.fetch();
|
.fetch();
|
||||||
return deleteQuery(CONTENT).where(CONTENT.id.in(ids)).execute();
|
return deleteQuery(CONTENT).where(CONTENT.id.in(ids)).execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,72 +1,73 @@
|
|||||||
package com.commafeed.backend.dao;
|
package com.commafeed.backend.dao;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.commafeed.backend.model.Feed;
|
import jakarta.inject.Singleton;
|
||||||
import com.commafeed.backend.model.FeedEntry;
|
import jakarta.persistence.EntityManager;
|
||||||
import com.commafeed.backend.model.QFeedEntry;
|
|
||||||
import com.querydsl.core.Tuple;
|
import com.commafeed.backend.model.Feed;
|
||||||
import com.querydsl.core.types.dsl.NumberExpression;
|
import com.commafeed.backend.model.FeedEntry;
|
||||||
|
import com.commafeed.backend.model.QFeedEntry;
|
||||||
import jakarta.inject.Singleton;
|
import com.querydsl.core.Tuple;
|
||||||
import jakarta.persistence.EntityManager;
|
import com.querydsl.core.types.dsl.NumberExpression;
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
@Singleton
|
|
||||||
public class FeedEntryDAO extends GenericDAO<FeedEntry> {
|
@Singleton
|
||||||
|
public class FeedEntryDAO extends GenericDAO<FeedEntry> {
|
||||||
private static final QFeedEntry ENTRY = QFeedEntry.feedEntry;
|
|
||||||
|
private static final QFeedEntry ENTRY = QFeedEntry.feedEntry;
|
||||||
public FeedEntryDAO(EntityManager entityManager) {
|
|
||||||
super(entityManager, FeedEntry.class);
|
public FeedEntryDAO(EntityManager entityManager) {
|
||||||
}
|
super(entityManager, FeedEntry.class);
|
||||||
|
}
|
||||||
public FeedEntry findExisting(String guidHash, Feed feed) {
|
|
||||||
return query().select(ENTRY).from(ENTRY).where(ENTRY.guidHash.eq(guidHash), ENTRY.feed.eq(feed)).limit(1).fetchOne();
|
public FeedEntry findExisting(String guidHash, Feed feed) {
|
||||||
}
|
return query().select(ENTRY).from(ENTRY).where(ENTRY.guidHash.eq(guidHash), ENTRY.feed.eq(feed)).limit(1).fetchOne();
|
||||||
|
}
|
||||||
public List<FeedCapacity> findFeedsExceedingCapacity(long maxCapacity, long max) {
|
|
||||||
NumberExpression<Long> count = ENTRY.id.count();
|
public List<FeedCapacity> findFeedsExceedingCapacity(long maxCapacity, long max) {
|
||||||
List<Tuple> tuples = query().select(ENTRY.feed.id, count)
|
NumberExpression<Long> count = ENTRY.id.count();
|
||||||
.from(ENTRY)
|
List<Tuple> tuples = query().select(ENTRY.feed.id, count)
|
||||||
.groupBy(ENTRY.feed)
|
.from(ENTRY)
|
||||||
.having(count.gt(maxCapacity))
|
.groupBy(ENTRY.feed)
|
||||||
.limit(max)
|
.having(count.gt(maxCapacity))
|
||||||
.fetch();
|
.limit(max)
|
||||||
return tuples.stream().map(t -> new FeedCapacity(t.get(ENTRY.feed.id), t.get(count))).toList();
|
.fetch();
|
||||||
}
|
return tuples.stream().map(t -> new FeedCapacity(t.get(ENTRY.feed.id), t.get(count))).toList();
|
||||||
|
}
|
||||||
public int delete(Long feedId, long max) {
|
|
||||||
List<FeedEntry> list = query().selectFrom(ENTRY).where(ENTRY.feed.id.eq(feedId)).limit(max).fetch();
|
public int delete(Long feedId, long max) {
|
||||||
return delete(list);
|
List<FeedEntry> list = query().selectFrom(ENTRY).where(ENTRY.feed.id.eq(feedId)).limit(max).fetch();
|
||||||
}
|
return delete(list);
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Delete entries older than a certain date
|
/**
|
||||||
*/
|
* 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) {
|
||||||
.where(ENTRY.published.lt(olderThan))
|
List<FeedEntry> list = query().selectFrom(ENTRY)
|
||||||
.orderBy(ENTRY.published.asc())
|
.where(ENTRY.published.lt(olderThan))
|
||||||
.limit(max)
|
.orderBy(ENTRY.published.asc())
|
||||||
.fetch();
|
.limit(max)
|
||||||
return delete(list);
|
.fetch();
|
||||||
}
|
return delete(list);
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Delete the oldest entries of a feed
|
/**
|
||||||
*/
|
* 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();
|
public int deleteOldEntries(Long feedId, long max) {
|
||||||
return delete(list);
|
List<FeedEntry> list = query().selectFrom(ENTRY).where(ENTRY.feed.id.eq(feedId)).orderBy(ENTRY.published.asc()).limit(max).fetch();
|
||||||
}
|
return delete(list);
|
||||||
|
}
|
||||||
@AllArgsConstructor
|
|
||||||
@Getter
|
@AllArgsConstructor
|
||||||
public static class FeedCapacity {
|
@Getter
|
||||||
private Long id;
|
public static class FeedCapacity {
|
||||||
private Long capacity;
|
private Long id;
|
||||||
}
|
private Long capacity;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,236 +1,236 @@
|
|||||||
package com.commafeed.backend.dao;
|
package com.commafeed.backend.dao;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import jakarta.inject.Singleton;
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
import com.commafeed.CommaFeedConfiguration;
|
|
||||||
import com.commafeed.backend.feed.FeedEntryKeyword;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import com.commafeed.backend.feed.FeedEntryKeyword.Mode;
|
|
||||||
import com.commafeed.backend.model.FeedEntry;
|
import com.commafeed.CommaFeedConfiguration;
|
||||||
import com.commafeed.backend.model.FeedEntryStatus;
|
import com.commafeed.backend.feed.FeedEntryKeyword;
|
||||||
import com.commafeed.backend.model.FeedEntryTag;
|
import com.commafeed.backend.feed.FeedEntryKeyword.Mode;
|
||||||
import com.commafeed.backend.model.FeedSubscription;
|
import com.commafeed.backend.model.FeedEntry;
|
||||||
import com.commafeed.backend.model.QFeedEntry;
|
import com.commafeed.backend.model.FeedEntryStatus;
|
||||||
import com.commafeed.backend.model.QFeedEntryContent;
|
import com.commafeed.backend.model.FeedEntryTag;
|
||||||
import com.commafeed.backend.model.QFeedEntryStatus;
|
import com.commafeed.backend.model.FeedSubscription;
|
||||||
import com.commafeed.backend.model.QFeedEntryTag;
|
import com.commafeed.backend.model.QFeedEntry;
|
||||||
import com.commafeed.backend.model.User;
|
import com.commafeed.backend.model.QFeedEntryContent;
|
||||||
import com.commafeed.backend.model.UserSettings.ReadingOrder;
|
import com.commafeed.backend.model.QFeedEntryStatus;
|
||||||
import com.commafeed.frontend.model.UnreadCount;
|
import com.commafeed.backend.model.QFeedEntryTag;
|
||||||
import com.google.common.collect.Iterables;
|
import com.commafeed.backend.model.User;
|
||||||
import com.querydsl.core.BooleanBuilder;
|
import com.commafeed.backend.model.UserSettings.ReadingOrder;
|
||||||
import com.querydsl.core.Tuple;
|
import com.commafeed.frontend.model.UnreadCount;
|
||||||
import com.querydsl.jpa.impl.JPAQuery;
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.querydsl.core.BooleanBuilder;
|
||||||
import jakarta.inject.Singleton;
|
import com.querydsl.core.Tuple;
|
||||||
import jakarta.persistence.EntityManager;
|
import com.querydsl.jpa.impl.JPAQuery;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
||||||
|
|
||||||
private static final QFeedEntryStatus STATUS = QFeedEntryStatus.feedEntryStatus;
|
private static final QFeedEntryStatus STATUS = QFeedEntryStatus.feedEntryStatus;
|
||||||
private static final QFeedEntry ENTRY = QFeedEntry.feedEntry;
|
private static final QFeedEntry ENTRY = QFeedEntry.feedEntry;
|
||||||
private static final QFeedEntryContent CONTENT = QFeedEntryContent.feedEntryContent;
|
private static final QFeedEntryContent CONTENT = QFeedEntryContent.feedEntryContent;
|
||||||
private static final QFeedEntryTag TAG = QFeedEntryTag.feedEntryTag;
|
private static final QFeedEntryTag TAG = QFeedEntryTag.feedEntryTag;
|
||||||
|
|
||||||
private final FeedEntryTagDAO feedEntryTagDAO;
|
private final FeedEntryTagDAO feedEntryTagDAO;
|
||||||
private final CommaFeedConfiguration config;
|
private final CommaFeedConfiguration config;
|
||||||
|
|
||||||
public FeedEntryStatusDAO(EntityManager entityManager, FeedEntryTagDAO feedEntryTagDAO, CommaFeedConfiguration config) {
|
public FeedEntryStatusDAO(EntityManager entityManager, FeedEntryTagDAO feedEntryTagDAO, CommaFeedConfiguration config) {
|
||||||
super(entityManager, FeedEntryStatus.class);
|
super(entityManager, FeedEntryStatus.class);
|
||||||
this.feedEntryTagDAO = feedEntryTagDAO;
|
this.feedEntryTagDAO = feedEntryTagDAO;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FeedEntryStatus getStatus(User user, FeedSubscription sub, FeedEntry entry) {
|
public FeedEntryStatus getStatus(User user, FeedSubscription sub, FeedEntry entry) {
|
||||||
List<FeedEntryStatus> statuses = query().selectFrom(STATUS).where(STATUS.entry.eq(entry), STATUS.subscription.eq(sub)).fetch();
|
List<FeedEntryStatus> statuses = query().selectFrom(STATUS).where(STATUS.entry.eq(entry), STATUS.subscription.eq(sub)).fetch();
|
||||||
FeedEntryStatus status = Iterables.getFirst(statuses, null);
|
FeedEntryStatus status = Iterables.getFirst(statuses, null);
|
||||||
return handleStatus(user, status, sub, entry);
|
return handleStatus(user, status, sub, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* creates an artificial "unread" status if status is null
|
* creates an artificial "unread" status if status is null
|
||||||
*/
|
*/
|
||||||
private FeedEntryStatus handleStatus(User user, FeedEntryStatus status, FeedSubscription sub, FeedEntry entry) {
|
private FeedEntryStatus handleStatus(User user, FeedEntryStatus status, FeedSubscription sub, FeedEntry entry) {
|
||||||
if (status == null) {
|
if (status == null) {
|
||||||
Instant statusesInstantThreshold = config.database().cleanup().statusesInstantThreshold();
|
Instant statusesInstantThreshold = config.database().cleanup().statusesInstantThreshold();
|
||||||
boolean read = statusesInstantThreshold != null && entry.getPublished().isBefore(statusesInstantThreshold);
|
boolean read = statusesInstantThreshold != null && entry.getPublished().isBefore(statusesInstantThreshold);
|
||||||
status = new FeedEntryStatus(user, sub, entry);
|
status = new FeedEntryStatus(user, sub, entry);
|
||||||
status.setRead(read);
|
status.setRead(read);
|
||||||
status.setMarkable(!read);
|
status.setMarkable(!read);
|
||||||
} else {
|
} else {
|
||||||
status.setMarkable(true);
|
status.setMarkable(true);
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fetchTags(User user, List<FeedEntryStatus> statuses) {
|
private void fetchTags(User user, List<FeedEntryStatus> statuses) {
|
||||||
Map<Long, List<FeedEntryTag>> tagsByEntryIds = feedEntryTagDAO.findByEntries(user,
|
Map<Long, List<FeedEntryTag>> tagsByEntryIds = feedEntryTagDAO.findByEntries(user,
|
||||||
statuses.stream().map(FeedEntryStatus::getEntry).toList());
|
statuses.stream().map(FeedEntryStatus::getEntry).toList());
|
||||||
for (FeedEntryStatus status : statuses) {
|
for (FeedEntryStatus status : statuses) {
|
||||||
List<FeedEntryTag> tags = tagsByEntryIds.get(status.getEntry().getId());
|
List<FeedEntryTag> tags = tagsByEntryIds.get(status.getEntry().getId());
|
||||||
status.setTags(tags == null ? List.of() : tags);
|
status.setTags(tags == null ? List.of() : tags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<FeedEntryStatus> findStarred(User user, Instant newerThan, int offset, int limit, ReadingOrder order,
|
public List<FeedEntryStatus> findStarred(User user, Instant newerThan, int offset, int limit, ReadingOrder order,
|
||||||
boolean includeContent) {
|
boolean includeContent) {
|
||||||
JPAQuery<FeedEntryStatus> query = query().selectFrom(STATUS).where(STATUS.user.eq(user), STATUS.starred.isTrue());
|
JPAQuery<FeedEntryStatus> query = query().selectFrom(STATUS).where(STATUS.user.eq(user), STATUS.starred.isTrue());
|
||||||
if (includeContent) {
|
if (includeContent) {
|
||||||
query.join(STATUS.entry).fetchJoin();
|
query.join(STATUS.entry).fetchJoin();
|
||||||
query.join(STATUS.entry.content).fetchJoin();
|
query.join(STATUS.entry.content).fetchJoin();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newerThan != null) {
|
if (newerThan != null) {
|
||||||
query.where(STATUS.entryInserted.gt(newerThan));
|
query.where(STATUS.entryInserted.gt(newerThan));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (order == ReadingOrder.asc) {
|
if (order == ReadingOrder.asc) {
|
||||||
query.orderBy(STATUS.entryPublished.asc(), STATUS.id.asc());
|
query.orderBy(STATUS.entryPublished.asc(), STATUS.id.asc());
|
||||||
} else {
|
} else {
|
||||||
query.orderBy(STATUS.entryPublished.desc(), STATUS.id.desc());
|
query.orderBy(STATUS.entryPublished.desc(), STATUS.id.desc());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offset > -1) {
|
if (offset > -1) {
|
||||||
query.offset(offset);
|
query.offset(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (limit > -1) {
|
if (limit > -1) {
|
||||||
query.limit(limit);
|
query.limit(limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(query, config.database().queryTimeout());
|
setTimeout(query, config.database().queryTimeout());
|
||||||
|
|
||||||
List<FeedEntryStatus> statuses = query.fetch();
|
List<FeedEntryStatus> statuses = query.fetch();
|
||||||
statuses.forEach(s -> s.setMarkable(true));
|
statuses.forEach(s -> s.setMarkable(true));
|
||||||
if (includeContent) {
|
if (includeContent) {
|
||||||
fetchTags(user, statuses);
|
fetchTags(user, statuses);
|
||||||
}
|
}
|
||||||
|
|
||||||
return statuses;
|
return statuses;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<FeedEntryStatus> findBySubscriptions(User user, List<FeedSubscription> subs, boolean unreadOnly,
|
public List<FeedEntryStatus> findBySubscriptions(User user, List<FeedSubscription> subs, boolean unreadOnly,
|
||||||
List<FeedEntryKeyword> keywords, Instant newerThan, int offset, int limit, ReadingOrder order, boolean includeContent,
|
List<FeedEntryKeyword> keywords, Instant newerThan, int offset, int limit, ReadingOrder order, boolean includeContent,
|
||||||
String tag, Long minEntryId, Long maxEntryId) {
|
String tag, Long minEntryId, Long maxEntryId) {
|
||||||
Map<Long, List<FeedSubscription>> subsByFeedId = subs.stream().collect(Collectors.groupingBy(s -> s.getFeed().getId()));
|
Map<Long, List<FeedSubscription>> subsByFeedId = subs.stream().collect(Collectors.groupingBy(s -> s.getFeed().getId()));
|
||||||
|
|
||||||
JPAQuery<Tuple> query = query().select(ENTRY, STATUS).from(ENTRY);
|
JPAQuery<Tuple> query = query().select(ENTRY, STATUS).from(ENTRY);
|
||||||
query.leftJoin(ENTRY.statuses, STATUS).on(STATUS.subscription.in(subs));
|
query.leftJoin(ENTRY.statuses, STATUS).on(STATUS.subscription.in(subs));
|
||||||
query.where(ENTRY.feed.id.in(subsByFeedId.keySet()));
|
query.where(ENTRY.feed.id.in(subsByFeedId.keySet()));
|
||||||
|
|
||||||
if (includeContent || CollectionUtils.isNotEmpty(keywords)) {
|
if (includeContent || CollectionUtils.isNotEmpty(keywords)) {
|
||||||
query.join(ENTRY.content, CONTENT).fetchJoin();
|
query.join(ENTRY.content, CONTENT).fetchJoin();
|
||||||
}
|
}
|
||||||
if (CollectionUtils.isNotEmpty(keywords)) {
|
if (CollectionUtils.isNotEmpty(keywords)) {
|
||||||
for (FeedEntryKeyword keyword : keywords) {
|
for (FeedEntryKeyword keyword : keywords) {
|
||||||
BooleanBuilder or = new BooleanBuilder();
|
BooleanBuilder or = new BooleanBuilder();
|
||||||
or.or(CONTENT.content.containsIgnoreCase(keyword.getKeyword()));
|
or.or(CONTENT.content.containsIgnoreCase(keyword.getKeyword()));
|
||||||
or.or(CONTENT.title.containsIgnoreCase(keyword.getKeyword()));
|
or.or(CONTENT.title.containsIgnoreCase(keyword.getKeyword()));
|
||||||
if (keyword.getMode() == Mode.EXCLUDE) {
|
if (keyword.getMode() == Mode.EXCLUDE) {
|
||||||
or.not();
|
or.not();
|
||||||
}
|
}
|
||||||
query.where(or);
|
query.where(or);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unreadOnly && tag == null) {
|
if (unreadOnly && tag == null) {
|
||||||
query.where(buildUnreadPredicate());
|
query.where(buildUnreadPredicate());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tag != null) {
|
if (tag != null) {
|
||||||
BooleanBuilder and = new BooleanBuilder();
|
BooleanBuilder and = new BooleanBuilder();
|
||||||
and.and(TAG.user.id.eq(user.getId()));
|
and.and(TAG.user.id.eq(user.getId()));
|
||||||
and.and(TAG.name.eq(tag));
|
and.and(TAG.name.eq(tag));
|
||||||
query.join(ENTRY.tags, TAG).on(and);
|
query.join(ENTRY.tags, TAG).on(and);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newerThan != null) {
|
if (newerThan != null) {
|
||||||
query.where(ENTRY.inserted.goe(newerThan));
|
query.where(ENTRY.inserted.goe(newerThan));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (minEntryId != null) {
|
if (minEntryId != null) {
|
||||||
query.where(ENTRY.id.gt(minEntryId));
|
query.where(ENTRY.id.gt(minEntryId));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maxEntryId != null) {
|
if (maxEntryId != null) {
|
||||||
query.where(ENTRY.id.lt(maxEntryId));
|
query.where(ENTRY.id.lt(maxEntryId));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (order != null) {
|
if (order != null) {
|
||||||
if (order == ReadingOrder.asc) {
|
if (order == ReadingOrder.asc) {
|
||||||
query.orderBy(ENTRY.published.asc(), ENTRY.id.asc());
|
query.orderBy(ENTRY.published.asc(), ENTRY.id.asc());
|
||||||
} else {
|
} else {
|
||||||
query.orderBy(ENTRY.published.desc(), ENTRY.id.desc());
|
query.orderBy(ENTRY.published.desc(), ENTRY.id.desc());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offset > -1) {
|
if (offset > -1) {
|
||||||
query.offset(offset);
|
query.offset(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (limit > -1) {
|
if (limit > -1) {
|
||||||
query.limit(limit);
|
query.limit(limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(query, config.database().queryTimeout());
|
setTimeout(query, config.database().queryTimeout());
|
||||||
|
|
||||||
List<FeedEntryStatus> statuses = new ArrayList<>();
|
List<FeedEntryStatus> statuses = new ArrayList<>();
|
||||||
List<Tuple> tuples = query.fetch();
|
List<Tuple> tuples = query.fetch();
|
||||||
for (Tuple tuple : tuples) {
|
for (Tuple tuple : tuples) {
|
||||||
FeedEntry e = tuple.get(ENTRY);
|
FeedEntry e = tuple.get(ENTRY);
|
||||||
FeedEntryStatus s = tuple.get(STATUS);
|
FeedEntryStatus s = tuple.get(STATUS);
|
||||||
for (FeedSubscription sub : subsByFeedId.get(e.getFeed().getId())) {
|
for (FeedSubscription sub : subsByFeedId.get(e.getFeed().getId())) {
|
||||||
statuses.add(handleStatus(user, s, sub, e));
|
statuses.add(handleStatus(user, s, sub, e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (includeContent) {
|
if (includeContent) {
|
||||||
fetchTags(user, statuses);
|
fetchTags(user, statuses);
|
||||||
}
|
}
|
||||||
|
|
||||||
return statuses;
|
return statuses;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnreadCount getUnreadCount(FeedSubscription sub) {
|
public UnreadCount getUnreadCount(FeedSubscription sub) {
|
||||||
JPAQuery<Tuple> query = query().select(ENTRY.count(), ENTRY.published.max())
|
JPAQuery<Tuple> query = query().select(ENTRY.count(), ENTRY.published.max())
|
||||||
.from(ENTRY)
|
.from(ENTRY)
|
||||||
.leftJoin(ENTRY.statuses, STATUS)
|
.leftJoin(ENTRY.statuses, STATUS)
|
||||||
.on(STATUS.subscription.eq(sub))
|
.on(STATUS.subscription.eq(sub))
|
||||||
.where(ENTRY.feed.eq(sub.getFeed()))
|
.where(ENTRY.feed.eq(sub.getFeed()))
|
||||||
.where(buildUnreadPredicate());
|
.where(buildUnreadPredicate());
|
||||||
|
|
||||||
Tuple tuple = query.fetchOne();
|
Tuple tuple = query.fetchOne();
|
||||||
Long count = tuple.get(ENTRY.count());
|
Long count = tuple.get(ENTRY.count());
|
||||||
Instant published = tuple.get(ENTRY.published.max());
|
Instant published = tuple.get(ENTRY.published.max());
|
||||||
return new UnreadCount(sub.getId(), count == null ? 0 : count, published);
|
return new UnreadCount(sub.getId(), count == null ? 0 : count, published);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BooleanBuilder buildUnreadPredicate() {
|
private BooleanBuilder buildUnreadPredicate() {
|
||||||
BooleanBuilder or = new BooleanBuilder();
|
BooleanBuilder or = new BooleanBuilder();
|
||||||
or.or(STATUS.read.isNull());
|
or.or(STATUS.read.isNull());
|
||||||
or.or(STATUS.read.isFalse());
|
or.or(STATUS.read.isFalse());
|
||||||
|
|
||||||
Instant statusesInstantThreshold = config.database().cleanup().statusesInstantThreshold();
|
Instant statusesInstantThreshold = config.database().cleanup().statusesInstantThreshold();
|
||||||
if (statusesInstantThreshold != null) {
|
if (statusesInstantThreshold != null) {
|
||||||
return or.and(ENTRY.published.goe(statusesInstantThreshold));
|
return or.and(ENTRY.published.goe(statusesInstantThreshold));
|
||||||
} else {
|
} else {
|
||||||
return or;
|
return or;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public long deleteOldStatuses(Instant olderThan, int limit) {
|
public long deleteOldStatuses(Instant olderThan, int limit) {
|
||||||
List<Long> ids = query().select(STATUS.id)
|
List<Long> ids = query().select(STATUS.id)
|
||||||
.from(STATUS)
|
.from(STATUS)
|
||||||
.where(STATUS.entryInserted.lt(olderThan), STATUS.starred.isFalse())
|
.where(STATUS.entryInserted.lt(olderThan), STATUS.starred.isFalse())
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
.fetch();
|
.fetch();
|
||||||
return deleteQuery(STATUS).where(STATUS.id.in(ids)).execute();
|
return deleteQuery(STATUS).where(STATUS.id.in(ids)).execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,39 +1,39 @@
|
|||||||
package com.commafeed.backend.dao;
|
package com.commafeed.backend.dao;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.commafeed.backend.model.FeedEntry;
|
import jakarta.inject.Singleton;
|
||||||
import com.commafeed.backend.model.FeedEntryTag;
|
import jakarta.persistence.EntityManager;
|
||||||
import com.commafeed.backend.model.QFeedEntryTag;
|
|
||||||
import com.commafeed.backend.model.User;
|
import com.commafeed.backend.model.FeedEntry;
|
||||||
|
import com.commafeed.backend.model.FeedEntryTag;
|
||||||
import jakarta.inject.Singleton;
|
import com.commafeed.backend.model.QFeedEntryTag;
|
||||||
import jakarta.persistence.EntityManager;
|
import com.commafeed.backend.model.User;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class FeedEntryTagDAO extends GenericDAO<FeedEntryTag> {
|
public class FeedEntryTagDAO extends GenericDAO<FeedEntryTag> {
|
||||||
|
|
||||||
private static final QFeedEntryTag TAG = QFeedEntryTag.feedEntryTag;
|
private static final QFeedEntryTag TAG = QFeedEntryTag.feedEntryTag;
|
||||||
|
|
||||||
public FeedEntryTagDAO(EntityManager entityManager) {
|
public FeedEntryTagDAO(EntityManager entityManager) {
|
||||||
super(entityManager, FeedEntryTag.class);
|
super(entityManager, FeedEntryTag.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> findByUser(User user) {
|
public List<String> findByUser(User user) {
|
||||||
return query().selectDistinct(TAG.name).from(TAG).where(TAG.user.eq(user)).fetch();
|
return query().selectDistinct(TAG.name).from(TAG).where(TAG.user.eq(user)).fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<FeedEntryTag> findByEntry(User user, FeedEntry entry) {
|
public List<FeedEntryTag> findByEntry(User user, FeedEntry entry) {
|
||||||
return query().selectFrom(TAG).where(TAG.user.eq(user), TAG.entry.eq(entry)).fetch();
|
return query().selectFrom(TAG).where(TAG.user.eq(user), TAG.entry.eq(entry)).fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<Long, List<FeedEntryTag>> findByEntries(User user, List<FeedEntry> entries) {
|
public Map<Long, List<FeedEntryTag>> findByEntries(User user, List<FeedEntry> entries) {
|
||||||
return query().selectFrom(TAG)
|
return query().selectFrom(TAG)
|
||||||
.where(TAG.user.eq(user), TAG.entry.in(entries))
|
.where(TAG.user.eq(user), TAG.entry.in(entries))
|
||||||
.fetch()
|
.fetch()
|
||||||
.stream()
|
.stream()
|
||||||
.collect(Collectors.groupingBy(t -> t.getEntry().getId()));
|
.collect(Collectors.groupingBy(t -> t.getEntry().getId()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,130 +1,130 @@
|
|||||||
package com.commafeed.backend.dao;
|
package com.commafeed.backend.dao;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import jakarta.inject.Singleton;
|
||||||
import org.hibernate.event.service.spi.EventListenerRegistry;
|
import jakarta.persistence.EntityManager;
|
||||||
import org.hibernate.event.spi.EventType;
|
|
||||||
import org.hibernate.event.spi.PostCommitInsertEventListener;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.event.spi.PostInsertEvent;
|
import org.hibernate.event.service.spi.EventListenerRegistry;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.event.spi.EventType;
|
||||||
|
import org.hibernate.event.spi.PostCommitInsertEventListener;
|
||||||
import com.commafeed.backend.model.AbstractModel;
|
import org.hibernate.event.spi.PostInsertEvent;
|
||||||
import com.commafeed.backend.model.Feed;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import com.commafeed.backend.model.FeedCategory;
|
|
||||||
import com.commafeed.backend.model.FeedSubscription;
|
import com.commafeed.backend.model.AbstractModel;
|
||||||
import com.commafeed.backend.model.Models;
|
import com.commafeed.backend.model.Feed;
|
||||||
import com.commafeed.backend.model.QFeedSubscription;
|
import com.commafeed.backend.model.FeedCategory;
|
||||||
import com.commafeed.backend.model.User;
|
import com.commafeed.backend.model.FeedSubscription;
|
||||||
import com.google.common.collect.Iterables;
|
import com.commafeed.backend.model.Models;
|
||||||
import com.querydsl.jpa.JPQLQuery;
|
import com.commafeed.backend.model.QFeedSubscription;
|
||||||
|
import com.commafeed.backend.model.User;
|
||||||
import jakarta.inject.Singleton;
|
import com.google.common.collect.Iterables;
|
||||||
import jakarta.persistence.EntityManager;
|
import com.querydsl.jpa.JPQLQuery;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class FeedSubscriptionDAO extends GenericDAO<FeedSubscription> {
|
public class FeedSubscriptionDAO extends GenericDAO<FeedSubscription> {
|
||||||
|
|
||||||
private static final QFeedSubscription SUBSCRIPTION = QFeedSubscription.feedSubscription;
|
private static final QFeedSubscription SUBSCRIPTION = QFeedSubscription.feedSubscription;
|
||||||
|
|
||||||
private final EntityManager entityManager;
|
private final EntityManager entityManager;
|
||||||
|
|
||||||
public FeedSubscriptionDAO(EntityManager entityManager) {
|
public FeedSubscriptionDAO(EntityManager entityManager) {
|
||||||
super(entityManager, FeedSubscription.class);
|
super(entityManager, FeedSubscription.class);
|
||||||
this.entityManager = entityManager;
|
this.entityManager = entityManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onPostCommitInsert(Consumer<FeedSubscription> consumer) {
|
public void onPostCommitInsert(Consumer<FeedSubscription> consumer) {
|
||||||
entityManager.unwrap(SharedSessionContractImplementor.class)
|
entityManager.unwrap(SharedSessionContractImplementor.class)
|
||||||
.getFactory()
|
.getFactory()
|
||||||
.getServiceRegistry()
|
.getServiceRegistry()
|
||||||
.getService(EventListenerRegistry.class)
|
.getService(EventListenerRegistry.class)
|
||||||
.getEventListenerGroup(EventType.POST_COMMIT_INSERT)
|
.getEventListenerGroup(EventType.POST_COMMIT_INSERT)
|
||||||
.appendListener(new PostCommitInsertEventListener() {
|
.appendListener(new PostCommitInsertEventListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onPostInsert(PostInsertEvent event) {
|
public void onPostInsert(PostInsertEvent event) {
|
||||||
if (event.getEntity() instanceof FeedSubscription s) {
|
if (event.getEntity() instanceof FeedSubscription s) {
|
||||||
consumer.accept(s);
|
consumer.accept(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean requiresPostCommitHandling(EntityPersister persister) {
|
public boolean requiresPostCommitHandling(EntityPersister persister) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPostInsertCommitFailed(PostInsertEvent event) {
|
public void onPostInsertCommitFailed(PostInsertEvent event) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public FeedSubscription findById(User user, Long id) {
|
public FeedSubscription findById(User user, Long id) {
|
||||||
List<FeedSubscription> subs = query().selectFrom(SUBSCRIPTION)
|
List<FeedSubscription> subs = query().selectFrom(SUBSCRIPTION)
|
||||||
.where(SUBSCRIPTION.user.eq(user), SUBSCRIPTION.id.eq(id))
|
.where(SUBSCRIPTION.user.eq(user), SUBSCRIPTION.id.eq(id))
|
||||||
.leftJoin(SUBSCRIPTION.feed)
|
.leftJoin(SUBSCRIPTION.feed)
|
||||||
.fetchJoin()
|
.fetchJoin()
|
||||||
.leftJoin(SUBSCRIPTION.category)
|
.leftJoin(SUBSCRIPTION.category)
|
||||||
.fetchJoin()
|
.fetchJoin()
|
||||||
.fetch();
|
.fetch();
|
||||||
return initRelations(Iterables.getFirst(subs, null));
|
return initRelations(Iterables.getFirst(subs, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<FeedSubscription> findByFeed(Feed feed) {
|
public List<FeedSubscription> findByFeed(Feed feed) {
|
||||||
return query().selectFrom(SUBSCRIPTION).where(SUBSCRIPTION.feed.eq(feed)).fetch();
|
return query().selectFrom(SUBSCRIPTION).where(SUBSCRIPTION.feed.eq(feed)).fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
public FeedSubscription findByFeed(User user, Feed feed) {
|
public FeedSubscription findByFeed(User user, Feed feed) {
|
||||||
List<FeedSubscription> subs = query().selectFrom(SUBSCRIPTION)
|
List<FeedSubscription> subs = query().selectFrom(SUBSCRIPTION)
|
||||||
.where(SUBSCRIPTION.user.eq(user), SUBSCRIPTION.feed.eq(feed))
|
.where(SUBSCRIPTION.user.eq(user), SUBSCRIPTION.feed.eq(feed))
|
||||||
.fetch();
|
.fetch();
|
||||||
return initRelations(Iterables.getFirst(subs, null));
|
return initRelations(Iterables.getFirst(subs, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<FeedSubscription> findAll(User user) {
|
public List<FeedSubscription> findAll(User user) {
|
||||||
List<FeedSubscription> subs = query().selectFrom(SUBSCRIPTION)
|
List<FeedSubscription> subs = query().selectFrom(SUBSCRIPTION)
|
||||||
.where(SUBSCRIPTION.user.eq(user))
|
.where(SUBSCRIPTION.user.eq(user))
|
||||||
.leftJoin(SUBSCRIPTION.feed)
|
.leftJoin(SUBSCRIPTION.feed)
|
||||||
.fetchJoin()
|
.fetchJoin()
|
||||||
.leftJoin(SUBSCRIPTION.category)
|
.leftJoin(SUBSCRIPTION.category)
|
||||||
.fetchJoin()
|
.fetchJoin()
|
||||||
.fetch();
|
.fetch();
|
||||||
return initRelations(subs);
|
return initRelations(subs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long count(User user) {
|
public Long count(User user) {
|
||||||
return query().select(SUBSCRIPTION.count()).from(SUBSCRIPTION).where(SUBSCRIPTION.user.eq(user)).fetchOne();
|
return query().select(SUBSCRIPTION.count()).from(SUBSCRIPTION).where(SUBSCRIPTION.user.eq(user)).fetchOne();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<FeedSubscription> findByCategory(User user, FeedCategory category) {
|
public List<FeedSubscription> findByCategory(User user, FeedCategory category) {
|
||||||
JPQLQuery<FeedSubscription> query = query().selectFrom(SUBSCRIPTION).where(SUBSCRIPTION.user.eq(user));
|
JPQLQuery<FeedSubscription> query = query().selectFrom(SUBSCRIPTION).where(SUBSCRIPTION.user.eq(user));
|
||||||
if (category == null) {
|
if (category == null) {
|
||||||
query.where(SUBSCRIPTION.category.isNull());
|
query.where(SUBSCRIPTION.category.isNull());
|
||||||
} else {
|
} else {
|
||||||
query.where(SUBSCRIPTION.category.eq(category));
|
query.where(SUBSCRIPTION.category.eq(category));
|
||||||
}
|
}
|
||||||
return initRelations(query.fetch());
|
return initRelations(query.fetch());
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<FeedSubscription> findByCategories(User user, List<FeedCategory> categories) {
|
public List<FeedSubscription> findByCategories(User user, List<FeedCategory> categories) {
|
||||||
Set<Long> categoryIds = categories.stream().map(AbstractModel::getId).collect(Collectors.toSet());
|
Set<Long> categoryIds = categories.stream().map(AbstractModel::getId).collect(Collectors.toSet());
|
||||||
return findAll(user).stream().filter(s -> s.getCategory() != null && categoryIds.contains(s.getCategory().getId())).toList();
|
return findAll(user).stream().filter(s -> s.getCategory() != null && categoryIds.contains(s.getCategory().getId())).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<FeedSubscription> initRelations(List<FeedSubscription> list) {
|
private List<FeedSubscription> initRelations(List<FeedSubscription> list) {
|
||||||
list.forEach(this::initRelations);
|
list.forEach(this::initRelations);
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
private FeedSubscription initRelations(FeedSubscription sub) {
|
private FeedSubscription initRelations(FeedSubscription sub) {
|
||||||
if (sub != null) {
|
if (sub != null) {
|
||||||
Models.initialize(sub.getFeed());
|
Models.initialize(sub.getFeed());
|
||||||
Models.initialize(sub.getCategory());
|
Models.initialize(sub.getCategory());
|
||||||
}
|
}
|
||||||
return sub;
|
return sub;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,75 +1,76 @@
|
|||||||
package com.commafeed.backend.dao;
|
package com.commafeed.backend.dao;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import org.hibernate.Session;
|
import jakarta.persistence.EntityManager;
|
||||||
import org.hibernate.jpa.SpecHints;
|
|
||||||
|
import org.hibernate.Session;
|
||||||
import com.commafeed.backend.model.AbstractModel;
|
import org.hibernate.jpa.SpecHints;
|
||||||
import com.querydsl.core.types.EntityPath;
|
|
||||||
import com.querydsl.jpa.impl.JPADeleteClause;
|
import com.commafeed.backend.model.AbstractModel;
|
||||||
import com.querydsl.jpa.impl.JPAQuery;
|
import com.querydsl.core.types.EntityPath;
|
||||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
import com.querydsl.jpa.impl.JPADeleteClause;
|
||||||
import com.querydsl.jpa.impl.JPAUpdateClause;
|
import com.querydsl.jpa.impl.JPAQuery;
|
||||||
|
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||||
import jakarta.persistence.EntityManager;
|
import com.querydsl.jpa.impl.JPAUpdateClause;
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
@RequiredArgsConstructor
|
|
||||||
public abstract class GenericDAO<T extends AbstractModel> {
|
@RequiredArgsConstructor
|
||||||
|
public abstract class GenericDAO<T extends AbstractModel> {
|
||||||
private final EntityManager entityManager;
|
|
||||||
private final Class<T> entityClass;
|
private final EntityManager entityManager;
|
||||||
|
private final Class<T> entityClass;
|
||||||
protected JPAQueryFactory query() {
|
|
||||||
return new JPAQueryFactory(entityManager);
|
protected JPAQueryFactory query() {
|
||||||
}
|
return new JPAQueryFactory(entityManager);
|
||||||
|
}
|
||||||
protected JPAUpdateClause updateQuery(EntityPath<T> entityPath) {
|
|
||||||
return new JPAUpdateClause(entityManager, entityPath);
|
protected JPAUpdateClause updateQuery(EntityPath<T> entityPath) {
|
||||||
}
|
return new JPAUpdateClause(entityManager, entityPath);
|
||||||
|
}
|
||||||
protected JPADeleteClause deleteQuery(EntityPath<T> entityPath) {
|
|
||||||
return new JPADeleteClause(entityManager, entityPath);
|
protected JPADeleteClause deleteQuery(EntityPath<T> entityPath) {
|
||||||
}
|
return new JPADeleteClause(entityManager, entityPath);
|
||||||
|
}
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public void saveOrUpdate(T model) {
|
@SuppressWarnings("deprecation")
|
||||||
entityManager.unwrap(Session.class).saveOrUpdate(model);
|
public void saveOrUpdate(T model) {
|
||||||
}
|
entityManager.unwrap(Session.class).saveOrUpdate(model);
|
||||||
|
}
|
||||||
public void saveOrUpdate(Collection<T> models) {
|
|
||||||
models.forEach(this::saveOrUpdate);
|
public void saveOrUpdate(Collection<T> models) {
|
||||||
}
|
models.forEach(this::saveOrUpdate);
|
||||||
|
}
|
||||||
public void persist(T model) {
|
|
||||||
entityManager.persist(model);
|
public void persist(T model) {
|
||||||
}
|
entityManager.persist(model);
|
||||||
|
}
|
||||||
public T merge(T model) {
|
|
||||||
return entityManager.merge(model);
|
public T merge(T model) {
|
||||||
}
|
return entityManager.merge(model);
|
||||||
|
}
|
||||||
public T findById(Long id) {
|
|
||||||
return entityManager.find(entityClass, id);
|
public T findById(Long id) {
|
||||||
}
|
return entityManager.find(entityClass, id);
|
||||||
|
}
|
||||||
public void delete(T object) {
|
|
||||||
if (object != null) {
|
public void delete(T object) {
|
||||||
entityManager.remove(object);
|
if (object != null) {
|
||||||
}
|
entityManager.remove(object);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public int delete(Collection<T> objects) {
|
|
||||||
objects.forEach(this::delete);
|
public int delete(Collection<T> objects) {
|
||||||
return objects.size();
|
objects.forEach(this::delete);
|
||||||
}
|
return objects.size();
|
||||||
|
}
|
||||||
protected void setTimeout(JPAQuery<?> query, Duration timeout) {
|
|
||||||
if (!timeout.isZero()) {
|
protected void setTimeout(JPAQuery<?> query, Duration timeout) {
|
||||||
query.setHint(SpecHints.HINT_SPEC_QUERY_TIMEOUT, Math.toIntExact(timeout.toMillis()));
|
if (!timeout.isZero()) {
|
||||||
}
|
query.setHint(SpecHints.HINT_SPEC_QUERY_TIMEOUT, Math.toIntExact(timeout.toMillis()));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,30 +1,19 @@
|
|||||||
package com.commafeed.backend.dao;
|
package com.commafeed.backend.dao;
|
||||||
|
|
||||||
import io.quarkus.narayana.jta.QuarkusTransaction;
|
import java.util.concurrent.Callable;
|
||||||
import jakarta.inject.Singleton;
|
|
||||||
|
import jakarta.inject.Singleton;
|
||||||
@Singleton
|
|
||||||
public class UnitOfWork {
|
import io.quarkus.narayana.jta.QuarkusTransaction;
|
||||||
|
|
||||||
public void run(SessionRunner runner) {
|
@Singleton
|
||||||
call(() -> {
|
public class UnitOfWork {
|
||||||
runner.runInSession();
|
|
||||||
return null;
|
public void run(Runnable runnable) {
|
||||||
});
|
QuarkusTransaction.joiningExisting().run(runnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> T call(SessionRunnerReturningValue<T> runner) {
|
public <T> T call(Callable<T> callable) {
|
||||||
return QuarkusTransaction.joiningExisting().call(runner::runInSession);
|
return QuarkusTransaction.joiningExisting().call(callable);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
@FunctionalInterface
|
|
||||||
public interface SessionRunner {
|
|
||||||
void runInSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface SessionRunnerReturningValue<T> {
|
|
||||||
T runInSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
package com.commafeed.backend.dao;
|
package com.commafeed.backend.dao;
|
||||||
|
|
||||||
import com.commafeed.backend.model.QUser;
|
import jakarta.inject.Singleton;
|
||||||
import com.commafeed.backend.model.User;
|
import jakarta.persistence.EntityManager;
|
||||||
|
|
||||||
import jakarta.inject.Singleton;
|
import com.commafeed.backend.model.QUser;
|
||||||
import jakarta.persistence.EntityManager;
|
import com.commafeed.backend.model.User;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class UserDAO extends GenericDAO<User> {
|
public class UserDAO extends GenericDAO<User> {
|
||||||
|
|
||||||
private static final QUser USER = QUser.user;
|
private static final QUser USER = QUser.user;
|
||||||
|
|
||||||
public UserDAO(EntityManager entityManager) {
|
public UserDAO(EntityManager entityManager) {
|
||||||
super(entityManager, User.class);
|
super(entityManager, User.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public User findByName(String name) {
|
public User findByName(String name) {
|
||||||
return query().selectFrom(USER).where(USER.name.equalsIgnoreCase(name)).fetchOne();
|
return query().selectFrom(USER).where(USER.name.equalsIgnoreCase(name)).fetchOne();
|
||||||
}
|
}
|
||||||
|
|
||||||
public User findByApiKey(String key) {
|
public User findByApiKey(String key) {
|
||||||
return query().selectFrom(USER).where(USER.apiKey.equalsIgnoreCase(key)).fetchOne();
|
return query().selectFrom(USER).where(USER.apiKey.equalsIgnoreCase(key)).fetchOne();
|
||||||
}
|
}
|
||||||
|
|
||||||
public User findByEmail(String email) {
|
public User findByEmail(String email) {
|
||||||
return query().selectFrom(USER).where(USER.email.equalsIgnoreCase(email)).fetchOne();
|
return query().selectFrom(USER).where(USER.email.equalsIgnoreCase(email)).fetchOne();
|
||||||
}
|
}
|
||||||
|
|
||||||
public long count() {
|
public long count() {
|
||||||
return query().select(USER.count()).from(USER).fetchOne();
|
return query().select(USER.count()).from(USER).fetchOne();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +1,35 @@
|
|||||||
package com.commafeed.backend.dao;
|
package com.commafeed.backend.dao;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.commafeed.backend.model.QUserRole;
|
import jakarta.inject.Singleton;
|
||||||
import com.commafeed.backend.model.User;
|
import jakarta.persistence.EntityManager;
|
||||||
import com.commafeed.backend.model.UserRole;
|
|
||||||
import com.commafeed.backend.model.UserRole.Role;
|
import com.commafeed.backend.model.QUserRole;
|
||||||
|
import com.commafeed.backend.model.User;
|
||||||
import jakarta.inject.Singleton;
|
import com.commafeed.backend.model.UserRole;
|
||||||
import jakarta.persistence.EntityManager;
|
import com.commafeed.backend.model.UserRole.Role;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class UserRoleDAO extends GenericDAO<UserRole> {
|
public class UserRoleDAO extends GenericDAO<UserRole> {
|
||||||
|
|
||||||
private static final QUserRole ROLE = QUserRole.userRole;
|
private static final QUserRole ROLE = QUserRole.userRole;
|
||||||
|
|
||||||
public UserRoleDAO(EntityManager entityManager) {
|
public UserRoleDAO(EntityManager entityManager) {
|
||||||
super(entityManager, UserRole.class);
|
super(entityManager, UserRole.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<UserRole> findAll() {
|
public List<UserRole> findAll() {
|
||||||
return query().selectFrom(ROLE).leftJoin(ROLE.user).fetchJoin().distinct().fetch();
|
return query().selectFrom(ROLE).leftJoin(ROLE.user).fetchJoin().distinct().fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<UserRole> findAll(User user) {
|
public List<UserRole> findAll(User user) {
|
||||||
return query().selectFrom(ROLE).where(ROLE.user.eq(user)).distinct().fetch();
|
return query().selectFrom(ROLE).where(ROLE.user.eq(user)).distinct().fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<Role> findRoles(User user) {
|
public Set<Role> findRoles(User user) {
|
||||||
return findAll(user).stream().map(UserRole::getRole).collect(Collectors.toSet());
|
return findAll(user).stream().map(UserRole::getRole).collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
package com.commafeed.backend.dao;
|
package com.commafeed.backend.dao;
|
||||||
|
|
||||||
import com.commafeed.backend.model.QUserSettings;
|
import jakarta.inject.Singleton;
|
||||||
import com.commafeed.backend.model.User;
|
import jakarta.persistence.EntityManager;
|
||||||
import com.commafeed.backend.model.UserSettings;
|
|
||||||
|
import com.commafeed.backend.model.QUserSettings;
|
||||||
import jakarta.inject.Singleton;
|
import com.commafeed.backend.model.User;
|
||||||
import jakarta.persistence.EntityManager;
|
import com.commafeed.backend.model.UserSettings;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class UserSettingsDAO extends GenericDAO<UserSettings> {
|
public class UserSettingsDAO extends GenericDAO<UserSettings> {
|
||||||
|
|
||||||
private static final QUserSettings SETTINGS = QUserSettings.userSettings;
|
private static final QUserSettings SETTINGS = QUserSettings.userSettings;
|
||||||
|
|
||||||
public UserSettingsDAO(EntityManager entityManager) {
|
public UserSettingsDAO(EntityManager entityManager) {
|
||||||
super(entityManager, UserSettings.class);
|
super(entityManager, UserSettings.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserSettings findByUser(User user) {
|
public UserSettings findByUser(User user) {
|
||||||
return query().selectFrom(SETTINGS).where(SETTINGS.user.eq(user)).fetchFirst();
|
return query().selectFrom(SETTINGS).where(SETTINGS.user.eq(user)).fetchFirst();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,49 +1,49 @@
|
|||||||
package com.commafeed.backend.favicon;
|
package com.commafeed.backend.favicon;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import com.commafeed.backend.model.Feed;
|
import com.commafeed.backend.model.Feed;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public abstract class AbstractFaviconFetcher {
|
public abstract class AbstractFaviconFetcher {
|
||||||
|
|
||||||
private static final List<String> ICON_MIMETYPE_BLACKLIST = Arrays.asList("application/xml", "text/html");
|
private static final List<String> ICON_MIMETYPE_BLACKLIST = Arrays.asList("application/xml", "text/html");
|
||||||
private static final long MIN_ICON_LENGTH = 100;
|
private static final long MIN_ICON_LENGTH = 100;
|
||||||
private static final long MAX_ICON_LENGTH = 100000;
|
private static final long MAX_ICON_LENGTH = 100000;
|
||||||
|
|
||||||
public abstract Favicon fetch(Feed feed);
|
public abstract Favicon fetch(Feed feed);
|
||||||
|
|
||||||
protected boolean isValidIconResponse(byte[] content, String contentType) {
|
protected boolean isValidIconResponse(byte[] content, String contentType) {
|
||||||
if (content == null) {
|
if (content == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
long length = content.length;
|
long length = content.length;
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(contentType)) {
|
if (StringUtils.isNotBlank(contentType)) {
|
||||||
contentType = contentType.split(";")[0];
|
contentType = contentType.split(";")[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ICON_MIMETYPE_BLACKLIST.contains(contentType)) {
|
if (ICON_MIMETYPE_BLACKLIST.contains(contentType)) {
|
||||||
log.debug("Content-Type {} is blacklisted", contentType);
|
log.debug("Content-Type {} is blacklisted", contentType);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (length < MIN_ICON_LENGTH) {
|
if (length < MIN_ICON_LENGTH) {
|
||||||
log.debug("Length {} below MIN_ICON_LENGTH {}", length, MIN_ICON_LENGTH);
|
log.debug("Length {} below MIN_ICON_LENGTH {}", length, MIN_ICON_LENGTH);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (length > MAX_ICON_LENGTH) {
|
if (length > MAX_ICON_LENGTH) {
|
||||||
log.debug("Length {} greater than MAX_ICON_LENGTH {}", length, MAX_ICON_LENGTH);
|
log.debug("Length {} greater than MAX_ICON_LENGTH {}", length, MAX_ICON_LENGTH);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,132 +1,133 @@
|
|||||||
package com.commafeed.backend.favicon;
|
package com.commafeed.backend.favicon;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import jakarta.annotation.Priority;
|
||||||
import org.jsoup.Jsoup;
|
import jakarta.inject.Singleton;
|
||||||
import org.jsoup.nodes.Document;
|
|
||||||
import org.jsoup.select.Elements;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.jsoup.Jsoup;
|
||||||
import com.commafeed.backend.HttpGetter;
|
import org.jsoup.nodes.Document;
|
||||||
import com.commafeed.backend.HttpGetter.HttpResult;
|
import org.jsoup.select.Elements;
|
||||||
import com.commafeed.backend.feed.FeedUtils;
|
|
||||||
import com.commafeed.backend.model.Feed;
|
import com.commafeed.backend.HttpGetter;
|
||||||
|
import com.commafeed.backend.HttpGetter.HttpResult;
|
||||||
import jakarta.annotation.Priority;
|
import com.commafeed.backend.feed.FeedUtils;
|
||||||
import jakarta.inject.Singleton;
|
import com.commafeed.backend.model.Feed;
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
/**
|
|
||||||
* Inspired/Ported from https://github.com/potatolondon/getfavicon
|
/**
|
||||||
*
|
* Inspired/Ported from https://github.com/potatolondon/getfavicon
|
||||||
*/
|
*
|
||||||
@Slf4j
|
*/
|
||||||
@RequiredArgsConstructor
|
@Slf4j
|
||||||
@Singleton
|
@RequiredArgsConstructor
|
||||||
@Priority(Integer.MIN_VALUE)
|
@Singleton
|
||||||
public class DefaultFaviconFetcher extends AbstractFaviconFetcher {
|
@Priority(Integer.MIN_VALUE)
|
||||||
|
public class DefaultFaviconFetcher extends AbstractFaviconFetcher {
|
||||||
private final HttpGetter getter;
|
|
||||||
|
private final HttpGetter getter;
|
||||||
@Override
|
|
||||||
public Favicon fetch(Feed feed) {
|
@Override
|
||||||
Favicon icon = fetch(feed.getLink());
|
public Favicon fetch(Feed feed) {
|
||||||
if (icon == null) {
|
Favicon icon = fetch(feed.getLink());
|
||||||
icon = fetch(feed.getUrl());
|
if (icon == null) {
|
||||||
}
|
icon = fetch(feed.getUrl());
|
||||||
return icon;
|
}
|
||||||
}
|
return icon;
|
||||||
|
}
|
||||||
private Favicon fetch(String url) {
|
|
||||||
if (url == null) {
|
private Favicon fetch(String url) {
|
||||||
log.debug("url is null");
|
if (url == null) {
|
||||||
return null;
|
log.debug("url is null");
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
int doubleSlash = url.indexOf("//");
|
|
||||||
if (doubleSlash == -1) {
|
int doubleSlash = url.indexOf("//");
|
||||||
doubleSlash = 0;
|
if (doubleSlash == -1) {
|
||||||
} else {
|
doubleSlash = 0;
|
||||||
doubleSlash += 2;
|
} else {
|
||||||
}
|
doubleSlash += 2;
|
||||||
int firstSlash = url.indexOf('/', doubleSlash);
|
}
|
||||||
if (firstSlash != -1) {
|
int firstSlash = url.indexOf('/', doubleSlash);
|
||||||
url = url.substring(0, firstSlash);
|
if (firstSlash != -1) {
|
||||||
}
|
url = url.substring(0, firstSlash);
|
||||||
|
}
|
||||||
Favicon icon = getIconAtRoot(url);
|
|
||||||
|
Favicon icon = getIconAtRoot(url);
|
||||||
if (icon == null) {
|
|
||||||
icon = getIconInPage(url);
|
if (icon == null) {
|
||||||
}
|
icon = getIconInPage(url);
|
||||||
|
}
|
||||||
return icon;
|
|
||||||
}
|
return icon;
|
||||||
|
}
|
||||||
private Favicon getIconAtRoot(String url) {
|
|
||||||
byte[] bytes = null;
|
private Favicon getIconAtRoot(String url) {
|
||||||
String contentType = null;
|
byte[] bytes = null;
|
||||||
|
String contentType = null;
|
||||||
try {
|
|
||||||
url = FeedUtils.removeTrailingSlash(url) + "/favicon.ico";
|
try {
|
||||||
log.debug("getting root icon at {}", url);
|
url = FeedUtils.removeTrailingSlash(url) + "/favicon.ico";
|
||||||
HttpResult result = getter.get(url);
|
log.debug("getting root icon at {}", url);
|
||||||
bytes = result.getContent();
|
HttpResult result = getter.get(url);
|
||||||
contentType = result.getContentType();
|
bytes = result.getContent();
|
||||||
} catch (Exception e) {
|
contentType = result.getContentType();
|
||||||
log.debug("Failed to retrieve iconAtRoot for url {}: ", url);
|
} catch (Exception e) {
|
||||||
log.trace("Failed to retrieve iconAtRoot for url {}: ", url, e);
|
log.debug("Failed to retrieve iconAtRoot for url {}: ", url);
|
||||||
}
|
log.trace("Failed to retrieve iconAtRoot for url {}: ", url, e);
|
||||||
|
}
|
||||||
if (!isValidIconResponse(bytes, contentType)) {
|
|
||||||
return null;
|
if (!isValidIconResponse(bytes, contentType)) {
|
||||||
}
|
return null;
|
||||||
return new Favicon(bytes, contentType);
|
}
|
||||||
}
|
return new Favicon(bytes, contentType);
|
||||||
|
}
|
||||||
private Favicon getIconInPage(String url) {
|
|
||||||
|
private Favicon getIconInPage(String url) {
|
||||||
Document doc;
|
|
||||||
try {
|
Document doc;
|
||||||
HttpResult result = getter.get(url);
|
try {
|
||||||
doc = Jsoup.parse(new String(result.getContent()), url);
|
HttpResult result = getter.get(url);
|
||||||
} catch (Exception e) {
|
doc = Jsoup.parse(new String(result.getContent()), url);
|
||||||
log.debug("Failed to retrieve page to find icon");
|
} catch (Exception e) {
|
||||||
log.trace("Failed to retrieve page to find icon", e);
|
log.debug("Failed to retrieve page to find icon");
|
||||||
return null;
|
log.trace("Failed to retrieve page to find icon", e);
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
Elements icons = doc.select("link[rel~=(?i)^(shortcut|icon|shortcut icon)$]");
|
|
||||||
|
Elements icons = doc.select("link[rel~=(?i)^(shortcut|icon|shortcut icon)$]");
|
||||||
if (icons.isEmpty()) {
|
|
||||||
log.debug("No icon found in page {}", url);
|
if (icons.isEmpty()) {
|
||||||
return null;
|
log.debug("No icon found in page {}", url);
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
String href = icons.get(0).attr("abs:href");
|
|
||||||
if (StringUtils.isBlank(href)) {
|
String href = icons.get(0).attr("abs:href");
|
||||||
log.debug("No icon found in page");
|
if (StringUtils.isBlank(href)) {
|
||||||
return null;
|
log.debug("No icon found in page");
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
log.debug("Found unconfirmed iconInPage at {}", href);
|
|
||||||
|
log.debug("Found unconfirmed iconInPage at {}", href);
|
||||||
byte[] bytes;
|
|
||||||
String contentType;
|
byte[] bytes;
|
||||||
try {
|
String contentType;
|
||||||
HttpResult result = getter.get(href);
|
try {
|
||||||
bytes = result.getContent();
|
HttpResult result = getter.get(href);
|
||||||
contentType = result.getContentType();
|
bytes = result.getContent();
|
||||||
} catch (Exception e) {
|
contentType = result.getContentType();
|
||||||
log.debug("Failed to retrieve icon found in page {}", href);
|
} catch (Exception e) {
|
||||||
log.trace("Failed to retrieve icon found in page {}", href, e);
|
log.debug("Failed to retrieve icon found in page {}", href);
|
||||||
return null;
|
log.trace("Failed to retrieve icon found in page {}", href, e);
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
if (!isValidIconResponse(bytes, contentType)) {
|
|
||||||
log.debug("Invalid icon found for {}", href);
|
if (!isValidIconResponse(bytes, contentType)) {
|
||||||
return null;
|
log.debug("Invalid icon found for {}", href);
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
return new Favicon(bytes, contentType);
|
|
||||||
}
|
return new Favicon(bytes, contentType);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,72 +1,73 @@
|
|||||||
package com.commafeed.backend.favicon;
|
package com.commafeed.backend.favicon;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.hc.core5.http.NameValuePair;
|
import jakarta.inject.Singleton;
|
||||||
import org.apache.hc.core5.net.URIBuilder;
|
|
||||||
|
import org.apache.hc.core5.http.NameValuePair;
|
||||||
import com.commafeed.backend.HttpGetter;
|
import org.apache.hc.core5.net.URIBuilder;
|
||||||
import com.commafeed.backend.HttpGetter.HttpResult;
|
|
||||||
import com.commafeed.backend.model.Feed;
|
import com.commafeed.backend.HttpGetter;
|
||||||
|
import com.commafeed.backend.HttpGetter.HttpResult;
|
||||||
import jakarta.inject.Singleton;
|
import com.commafeed.backend.model.Feed;
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@Slf4j
|
|
||||||
@RequiredArgsConstructor
|
@Slf4j
|
||||||
@Singleton
|
@RequiredArgsConstructor
|
||||||
public class FacebookFaviconFetcher extends AbstractFaviconFetcher {
|
@Singleton
|
||||||
|
public class FacebookFaviconFetcher extends AbstractFaviconFetcher {
|
||||||
private final HttpGetter getter;
|
|
||||||
|
private final HttpGetter getter;
|
||||||
@Override
|
|
||||||
public Favicon fetch(Feed feed) {
|
@Override
|
||||||
String url = feed.getUrl();
|
public Favicon fetch(Feed feed) {
|
||||||
|
String url = feed.getUrl();
|
||||||
if (!url.toLowerCase().contains("www.facebook.com")) {
|
|
||||||
return null;
|
if (!url.toLowerCase().contains("www.facebook.com")) {
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
String userName = extractUserName(url);
|
|
||||||
if (userName == null) {
|
String userName = extractUserName(url);
|
||||||
return null;
|
if (userName == null) {
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
String iconUrl = String.format("https://graph.facebook.com/%s/picture?type=square&height=16", userName);
|
|
||||||
|
String iconUrl = String.format("https://graph.facebook.com/%s/picture?type=square&height=16", userName);
|
||||||
byte[] bytes = null;
|
|
||||||
String contentType = null;
|
byte[] bytes = null;
|
||||||
|
String contentType = null;
|
||||||
try {
|
|
||||||
log.debug("Getting Facebook user's icon, {}", url);
|
try {
|
||||||
|
log.debug("Getting Facebook user's icon, {}", url);
|
||||||
HttpResult iconResult = getter.get(iconUrl);
|
|
||||||
bytes = iconResult.getContent();
|
HttpResult iconResult = getter.get(iconUrl);
|
||||||
contentType = iconResult.getContentType();
|
bytes = iconResult.getContent();
|
||||||
} catch (Exception e) {
|
contentType = iconResult.getContentType();
|
||||||
log.debug("Failed to retrieve Facebook icon", e);
|
} catch (Exception e) {
|
||||||
}
|
log.debug("Failed to retrieve Facebook icon", e);
|
||||||
|
}
|
||||||
if (!isValidIconResponse(bytes, contentType)) {
|
|
||||||
return null;
|
if (!isValidIconResponse(bytes, contentType)) {
|
||||||
}
|
return null;
|
||||||
return new Favicon(bytes, contentType);
|
}
|
||||||
}
|
return new Favicon(bytes, contentType);
|
||||||
|
}
|
||||||
private String extractUserName(String url) {
|
|
||||||
URI uri;
|
private String extractUserName(String url) {
|
||||||
try {
|
URI uri;
|
||||||
uri = new URI(url);
|
try {
|
||||||
} catch (URISyntaxException e) {
|
uri = new URI(url);
|
||||||
log.debug("could not parse url", e);
|
} catch (URISyntaxException e) {
|
||||||
return null;
|
log.debug("could not parse url", e);
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
List<NameValuePair> params = new URIBuilder(uri).getQueryParams();
|
|
||||||
return params.stream().filter(p -> "id".equals(p.getName())).map(NameValuePair::getValue).findFirst().orElse(null);
|
List<NameValuePair> params = new URIBuilder(uri).getQueryParams();
|
||||||
}
|
return params.stream().filter(p -> "id".equals(p.getName())).map(NameValuePair::getValue).findFirst().orElse(null);
|
||||||
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,30 +1,31 @@
|
|||||||
package com.commafeed.backend.favicon;
|
package com.commafeed.backend.favicon;
|
||||||
|
|
||||||
import jakarta.ws.rs.core.MediaType;
|
import jakarta.ws.rs.core.MediaType;
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.Getter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Getter
|
@RequiredArgsConstructor
|
||||||
@Slf4j
|
@Getter
|
||||||
public class Favicon {
|
@Slf4j
|
||||||
|
public class Favicon {
|
||||||
private static final MediaType DEFAULT_MEDIA_TYPE = MediaType.valueOf("image/x-icon");
|
|
||||||
|
private static final MediaType DEFAULT_MEDIA_TYPE = MediaType.valueOf("image/x-icon");
|
||||||
private final byte[] icon;
|
|
||||||
private final MediaType mediaType;
|
private final byte[] icon;
|
||||||
|
private final MediaType mediaType;
|
||||||
public Favicon(byte[] icon, String contentType) {
|
|
||||||
this(icon, parseMediaType(contentType));
|
public Favicon(byte[] icon, String contentType) {
|
||||||
}
|
this(icon, parseMediaType(contentType));
|
||||||
|
}
|
||||||
private static MediaType parseMediaType(String contentType) {
|
|
||||||
try {
|
private static MediaType parseMediaType(String contentType) {
|
||||||
return MediaType.valueOf(contentType);
|
try {
|
||||||
} catch (Exception e) {
|
return MediaType.valueOf(contentType);
|
||||||
log.debug("invalid content type '{}' received, returning default value", contentType);
|
} catch (Exception e) {
|
||||||
return DEFAULT_MEDIA_TYPE;
|
log.debug("invalid content type '{}' received, returning default value", contentType);
|
||||||
}
|
return DEFAULT_MEDIA_TYPE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,134 +1,135 @@
|
|||||||
package com.commafeed.backend.favicon;
|
package com.commafeed.backend.favicon;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import jakarta.inject.Singleton;
|
||||||
import org.apache.hc.core5.http.NameValuePair;
|
import jakarta.ws.rs.core.UriBuilder;
|
||||||
import org.apache.hc.core5.net.URIBuilder;
|
|
||||||
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
import com.commafeed.CommaFeedConfiguration;
|
import org.apache.hc.core5.http.NameValuePair;
|
||||||
import com.commafeed.backend.HttpGetter;
|
import org.apache.hc.core5.net.URIBuilder;
|
||||||
import com.commafeed.backend.HttpGetter.HostNotAllowedException;
|
|
||||||
import com.commafeed.backend.HttpGetter.HttpResult;
|
import com.commafeed.CommaFeedConfiguration;
|
||||||
import com.commafeed.backend.HttpGetter.NotModifiedException;
|
import com.commafeed.backend.HttpGetter;
|
||||||
import com.commafeed.backend.HttpGetter.SchemeNotAllowedException;
|
import com.commafeed.backend.HttpGetter.HostNotAllowedException;
|
||||||
import com.commafeed.backend.HttpGetter.TooManyRequestsException;
|
import com.commafeed.backend.HttpGetter.HttpResult;
|
||||||
import com.commafeed.backend.model.Feed;
|
import com.commafeed.backend.HttpGetter.NotModifiedException;
|
||||||
import com.fasterxml.jackson.core.JsonPointer;
|
import com.commafeed.backend.HttpGetter.SchemeNotAllowedException;
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.commafeed.backend.HttpGetter.TooManyRequestsException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.commafeed.backend.model.Feed;
|
||||||
|
import com.fasterxml.jackson.core.JsonPointer;
|
||||||
import jakarta.inject.Singleton;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import jakarta.ws.rs.core.UriBuilder;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@Slf4j
|
|
||||||
@RequiredArgsConstructor
|
@Slf4j
|
||||||
@Singleton
|
@RequiredArgsConstructor
|
||||||
public class YoutubeFaviconFetcher extends AbstractFaviconFetcher {
|
@Singleton
|
||||||
|
public class YoutubeFaviconFetcher extends AbstractFaviconFetcher {
|
||||||
private static final JsonPointer CHANNEL_THUMBNAIL_URL = JsonPointer.compile("/items/0/snippet/thumbnails/default/url");
|
|
||||||
private static final JsonPointer PLAYLIST_CHANNEL_ID = JsonPointer.compile("/items/0/snippet/channelId");
|
private static final JsonPointer CHANNEL_THUMBNAIL_URL = JsonPointer.compile("/items/0/snippet/thumbnails/default/url");
|
||||||
|
private static final JsonPointer PLAYLIST_CHANNEL_ID = JsonPointer.compile("/items/0/snippet/channelId");
|
||||||
private final HttpGetter getter;
|
|
||||||
private final CommaFeedConfiguration config;
|
private final HttpGetter getter;
|
||||||
private final ObjectMapper objectMapper;
|
private final CommaFeedConfiguration config;
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
@Override
|
|
||||||
public Favicon fetch(Feed feed) {
|
@Override
|
||||||
String url = feed.getUrl();
|
public Favicon fetch(Feed feed) {
|
||||||
if (!url.toLowerCase().contains("youtube.com/feeds/videos.xml")) {
|
String url = feed.getUrl();
|
||||||
return null;
|
if (!url.toLowerCase().contains("youtube.com/feeds/videos.xml")) {
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
Optional<String> googleAuthKey = config.googleAuthKey();
|
|
||||||
if (googleAuthKey.isEmpty()) {
|
Optional<String> googleAuthKey = config.googleAuthKey();
|
||||||
log.debug("no google auth key configured");
|
if (googleAuthKey.isEmpty()) {
|
||||||
return null;
|
log.debug("no google auth key configured");
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
byte[] bytes = null;
|
|
||||||
String contentType = null;
|
byte[] bytes = null;
|
||||||
try {
|
String contentType = null;
|
||||||
List<NameValuePair> params = new URIBuilder(url).getQueryParams();
|
try {
|
||||||
Optional<NameValuePair> userId = params.stream().filter(nvp -> nvp.getName().equalsIgnoreCase("user")).findFirst();
|
List<NameValuePair> params = new URIBuilder(url).getQueryParams();
|
||||||
Optional<NameValuePair> channelId = params.stream().filter(nvp -> nvp.getName().equalsIgnoreCase("channel_id")).findFirst();
|
Optional<NameValuePair> userId = params.stream().filter(nvp -> nvp.getName().equalsIgnoreCase("user")).findFirst();
|
||||||
Optional<NameValuePair> playlistId = params.stream().filter(nvp -> nvp.getName().equalsIgnoreCase("playlist_id")).findFirst();
|
Optional<NameValuePair> channelId = params.stream().filter(nvp -> nvp.getName().equalsIgnoreCase("channel_id")).findFirst();
|
||||||
|
Optional<NameValuePair> playlistId = params.stream().filter(nvp -> nvp.getName().equalsIgnoreCase("playlist_id")).findFirst();
|
||||||
byte[] response = null;
|
|
||||||
if (userId.isPresent()) {
|
byte[] response = null;
|
||||||
log.debug("contacting youtube api for user {}", userId.get().getValue());
|
if (userId.isPresent()) {
|
||||||
response = fetchForUser(googleAuthKey.get(), userId.get().getValue());
|
log.debug("contacting youtube api for user {}", userId.get().getValue());
|
||||||
} else if (channelId.isPresent()) {
|
response = fetchForUser(googleAuthKey.get(), userId.get().getValue());
|
||||||
log.debug("contacting youtube api for channel {}", channelId.get().getValue());
|
} else if (channelId.isPresent()) {
|
||||||
response = fetchForChannel(googleAuthKey.get(), channelId.get().getValue());
|
log.debug("contacting youtube api for channel {}", channelId.get().getValue());
|
||||||
} else if (playlistId.isPresent()) {
|
response = fetchForChannel(googleAuthKey.get(), channelId.get().getValue());
|
||||||
log.debug("contacting youtube api for playlist {}", playlistId.get().getValue());
|
} else if (playlistId.isPresent()) {
|
||||||
response = fetchForPlaylist(googleAuthKey.get(), playlistId.get().getValue());
|
log.debug("contacting youtube api for playlist {}", playlistId.get().getValue());
|
||||||
}
|
response = fetchForPlaylist(googleAuthKey.get(), playlistId.get().getValue());
|
||||||
if (ArrayUtils.isEmpty(response)) {
|
}
|
||||||
log.debug("youtube api returned empty response");
|
if (ArrayUtils.isEmpty(response)) {
|
||||||
return null;
|
log.debug("youtube api returned empty response");
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
JsonNode thumbnailUrl = objectMapper.readTree(response).at(CHANNEL_THUMBNAIL_URL);
|
|
||||||
if (thumbnailUrl.isMissingNode()) {
|
JsonNode thumbnailUrl = objectMapper.readTree(response).at(CHANNEL_THUMBNAIL_URL);
|
||||||
log.debug("youtube api returned invalid response");
|
if (thumbnailUrl.isMissingNode()) {
|
||||||
return null;
|
log.debug("youtube api returned invalid response");
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
HttpResult iconResult = getter.get(thumbnailUrl.asText());
|
|
||||||
bytes = iconResult.getContent();
|
HttpResult iconResult = getter.get(thumbnailUrl.asText());
|
||||||
contentType = iconResult.getContentType();
|
bytes = iconResult.getContent();
|
||||||
} catch (Exception e) {
|
contentType = iconResult.getContentType();
|
||||||
log.error("Failed to retrieve YouTube icon", e);
|
} catch (Exception e) {
|
||||||
}
|
log.error("Failed to retrieve YouTube icon", e);
|
||||||
|
}
|
||||||
if (!isValidIconResponse(bytes, contentType)) {
|
|
||||||
return null;
|
if (!isValidIconResponse(bytes, contentType)) {
|
||||||
}
|
return null;
|
||||||
return new Favicon(bytes, contentType);
|
}
|
||||||
}
|
return new Favicon(bytes, contentType);
|
||||||
|
}
|
||||||
private byte[] fetchForUser(String googleAuthKey, String userId)
|
|
||||||
throws IOException, NotModifiedException, TooManyRequestsException, HostNotAllowedException, SchemeNotAllowedException {
|
private byte[] fetchForUser(String googleAuthKey, String userId)
|
||||||
URI uri = UriBuilder.fromUri("https://www.googleapis.com/youtube/v3/channels")
|
throws IOException, NotModifiedException, TooManyRequestsException, HostNotAllowedException, SchemeNotAllowedException {
|
||||||
.queryParam("part", "snippet")
|
URI uri = UriBuilder.fromUri("https://www.googleapis.com/youtube/v3/channels")
|
||||||
.queryParam("key", googleAuthKey)
|
.queryParam("part", "snippet")
|
||||||
.queryParam("forUsername", userId)
|
.queryParam("key", googleAuthKey)
|
||||||
.build();
|
.queryParam("forUsername", userId)
|
||||||
return getter.get(uri.toString()).getContent();
|
.build();
|
||||||
}
|
return getter.get(uri.toString()).getContent();
|
||||||
|
}
|
||||||
private byte[] fetchForChannel(String googleAuthKey, String channelId)
|
|
||||||
throws IOException, NotModifiedException, TooManyRequestsException, HostNotAllowedException, SchemeNotAllowedException {
|
private byte[] fetchForChannel(String googleAuthKey, String channelId)
|
||||||
URI uri = UriBuilder.fromUri("https://www.googleapis.com/youtube/v3/channels")
|
throws IOException, NotModifiedException, TooManyRequestsException, HostNotAllowedException, SchemeNotAllowedException {
|
||||||
.queryParam("part", "snippet")
|
URI uri = UriBuilder.fromUri("https://www.googleapis.com/youtube/v3/channels")
|
||||||
.queryParam("key", googleAuthKey)
|
.queryParam("part", "snippet")
|
||||||
.queryParam("id", channelId)
|
.queryParam("key", googleAuthKey)
|
||||||
.build();
|
.queryParam("id", channelId)
|
||||||
return getter.get(uri.toString()).getContent();
|
.build();
|
||||||
}
|
return getter.get(uri.toString()).getContent();
|
||||||
|
}
|
||||||
private byte[] fetchForPlaylist(String googleAuthKey, String playlistId)
|
|
||||||
throws IOException, NotModifiedException, TooManyRequestsException, HostNotAllowedException, SchemeNotAllowedException {
|
private byte[] fetchForPlaylist(String googleAuthKey, String playlistId)
|
||||||
URI uri = UriBuilder.fromUri("https://www.googleapis.com/youtube/v3/playlists")
|
throws IOException, NotModifiedException, TooManyRequestsException, HostNotAllowedException, SchemeNotAllowedException {
|
||||||
.queryParam("part", "snippet")
|
URI uri = UriBuilder.fromUri("https://www.googleapis.com/youtube/v3/playlists")
|
||||||
.queryParam("key", googleAuthKey)
|
.queryParam("part", "snippet")
|
||||||
.queryParam("id", playlistId)
|
.queryParam("key", googleAuthKey)
|
||||||
.build();
|
.queryParam("id", playlistId)
|
||||||
byte[] playlistBytes = getter.get(uri.toString()).getContent();
|
.build();
|
||||||
|
byte[] playlistBytes = getter.get(uri.toString()).getContent();
|
||||||
JsonNode channelId = objectMapper.readTree(playlistBytes).at(PLAYLIST_CHANNEL_ID);
|
|
||||||
if (channelId.isMissingNode()) {
|
JsonNode channelId = objectMapper.readTree(playlistBytes).at(PLAYLIST_CHANNEL_ID);
|
||||||
return null;
|
if (channelId.isMissingNode()) {
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
return fetchForChannel(googleAuthKey, channelId.asText());
|
|
||||||
}
|
return fetchForChannel(googleAuthKey, channelId.asText());
|
||||||
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,39 +1,39 @@
|
|||||||
package com.commafeed.backend.feed;
|
package com.commafeed.backend.feed;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A keyword used in a search query
|
* A keyword used in a search query
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class FeedEntryKeyword {
|
public class FeedEntryKeyword {
|
||||||
|
|
||||||
public enum Mode {
|
public enum Mode {
|
||||||
INCLUDE, EXCLUDE
|
INCLUDE, EXCLUDE
|
||||||
}
|
}
|
||||||
|
|
||||||
private final String keyword;
|
private final String keyword;
|
||||||
private final Mode mode;
|
private final Mode mode;
|
||||||
|
|
||||||
public static List<FeedEntryKeyword> fromQueryString(String keywords) {
|
public static List<FeedEntryKeyword> fromQueryString(String keywords) {
|
||||||
List<FeedEntryKeyword> list = new ArrayList<>();
|
List<FeedEntryKeyword> list = new ArrayList<>();
|
||||||
if (keywords != null) {
|
if (keywords != null) {
|
||||||
for (String keyword : StringUtils.split(keywords)) {
|
for (String keyword : StringUtils.split(keywords)) {
|
||||||
boolean not = false;
|
boolean not = false;
|
||||||
if (keyword.startsWith("-") || keyword.startsWith("!")) {
|
if (keyword.startsWith("-") || keyword.startsWith("!")) {
|
||||||
not = true;
|
not = true;
|
||||||
keyword = keyword.substring(1);
|
keyword = keyword.substring(1);
|
||||||
}
|
}
|
||||||
list.add(new FeedEntryKeyword(keyword, not ? Mode.EXCLUDE : Mode.INCLUDE));
|
list.add(new FeedEntryKeyword(keyword, not ? Mode.EXCLUDE : Mode.INCLUDE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,114 +1,123 @@
|
|||||||
package com.commafeed.backend.feed;
|
package com.commafeed.backend.feed;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import jakarta.inject.Singleton;
|
||||||
|
|
||||||
import com.commafeed.backend.Digests;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import com.commafeed.backend.HttpGetter;
|
|
||||||
import com.commafeed.backend.HttpGetter.HostNotAllowedException;
|
import com.commafeed.backend.Digests;
|
||||||
import com.commafeed.backend.HttpGetter.HttpRequest;
|
import com.commafeed.backend.HttpGetter;
|
||||||
import com.commafeed.backend.HttpGetter.HttpResult;
|
import com.commafeed.backend.HttpGetter.HostNotAllowedException;
|
||||||
import com.commafeed.backend.HttpGetter.NotModifiedException;
|
import com.commafeed.backend.HttpGetter.HttpRequest;
|
||||||
import com.commafeed.backend.HttpGetter.SchemeNotAllowedException;
|
import com.commafeed.backend.HttpGetter.HttpResult;
|
||||||
import com.commafeed.backend.HttpGetter.TooManyRequestsException;
|
import com.commafeed.backend.HttpGetter.NotModifiedException;
|
||||||
import com.commafeed.backend.feed.parser.FeedParser;
|
import com.commafeed.backend.HttpGetter.SchemeNotAllowedException;
|
||||||
import com.commafeed.backend.feed.parser.FeedParserResult;
|
import com.commafeed.backend.HttpGetter.TooManyRequestsException;
|
||||||
import com.commafeed.backend.urlprovider.FeedURLProvider;
|
import com.commafeed.backend.feed.parser.FeedParser;
|
||||||
import com.rometools.rome.io.FeedException;
|
import com.commafeed.backend.feed.parser.FeedParser.FeedParsingException;
|
||||||
|
import com.commafeed.backend.feed.parser.FeedParserResult;
|
||||||
import io.quarkus.arc.All;
|
import com.commafeed.backend.urlprovider.FeedURLProvider;
|
||||||
import jakarta.inject.Singleton;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import io.quarkus.arc.All;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
/**
|
|
||||||
* Fetches a feed then parses it
|
/**
|
||||||
*/
|
* Fetches a feed then parses it
|
||||||
@Slf4j
|
*/
|
||||||
@Singleton
|
@Slf4j
|
||||||
public class FeedFetcher {
|
@Singleton
|
||||||
|
public class FeedFetcher {
|
||||||
private final FeedParser parser;
|
|
||||||
private final HttpGetter getter;
|
private final FeedParser parser;
|
||||||
private final List<FeedURLProvider> urlProviders;
|
private final HttpGetter getter;
|
||||||
|
private final List<FeedURLProvider> urlProviders;
|
||||||
public FeedFetcher(FeedParser parser, HttpGetter getter, @All List<FeedURLProvider> urlProviders) {
|
|
||||||
this.parser = parser;
|
public FeedFetcher(FeedParser parser, HttpGetter getter, @All List<FeedURLProvider> urlProviders) {
|
||||||
this.getter = getter;
|
this.parser = parser;
|
||||||
this.urlProviders = urlProviders;
|
this.getter = getter;
|
||||||
}
|
this.urlProviders = urlProviders;
|
||||||
|
}
|
||||||
public FeedFetcherResult fetch(String feedUrl, boolean extractFeedUrlFromHtml, String lastModified, String eTag,
|
|
||||||
Instant lastPublishedDate, String lastContentHash) throws FeedException, IOException, NotModifiedException,
|
public FeedFetcherResult fetch(String feedUrl, boolean extractFeedUrlFromHtml, String lastModified, String eTag,
|
||||||
TooManyRequestsException, SchemeNotAllowedException, HostNotAllowedException {
|
Instant lastPublishedDate, String lastContentHash) throws FeedParsingException, IOException, NotModifiedException,
|
||||||
log.debug("Fetching feed {}", feedUrl);
|
TooManyRequestsException, SchemeNotAllowedException, HostNotAllowedException, NoFeedFoundException {
|
||||||
|
log.debug("Fetching feed {}", feedUrl);
|
||||||
HttpResult result = getter.get(HttpRequest.builder(feedUrl).lastModified(lastModified).eTag(eTag).build());
|
|
||||||
byte[] content = result.getContent();
|
HttpResult result = getter.get(HttpRequest.builder(feedUrl).lastModified(lastModified).eTag(eTag).build());
|
||||||
|
byte[] content = result.getContent();
|
||||||
FeedParserResult parserResult;
|
|
||||||
try {
|
FeedParserResult parserResult;
|
||||||
parserResult = parser.parse(result.getUrlAfterRedirect(), content);
|
try {
|
||||||
} catch (FeedException e) {
|
parserResult = parser.parse(result.getUrlAfterRedirect(), content);
|
||||||
if (extractFeedUrlFromHtml) {
|
} catch (FeedParsingException e) {
|
||||||
String extractedUrl = extractFeedUrl(urlProviders, feedUrl, new String(result.getContent(), StandardCharsets.UTF_8));
|
if (extractFeedUrlFromHtml) {
|
||||||
if (org.apache.commons.lang3.StringUtils.isNotBlank(extractedUrl)) {
|
String extractedUrl = extractFeedUrl(urlProviders, feedUrl, new String(result.getContent(), StandardCharsets.UTF_8));
|
||||||
feedUrl = extractedUrl;
|
if (StringUtils.isNotBlank(extractedUrl)) {
|
||||||
|
feedUrl = extractedUrl;
|
||||||
result = getter.get(HttpRequest.builder(extractedUrl).lastModified(lastModified).eTag(eTag).build());
|
|
||||||
content = result.getContent();
|
result = getter.get(HttpRequest.builder(extractedUrl).lastModified(lastModified).eTag(eTag).build());
|
||||||
parserResult = parser.parse(result.getUrlAfterRedirect(), content);
|
content = result.getContent();
|
||||||
} else {
|
parserResult = parser.parse(result.getUrlAfterRedirect(), content);
|
||||||
throw e;
|
} else {
|
||||||
}
|
throw new NoFeedFoundException(e);
|
||||||
} else {
|
}
|
||||||
throw e;
|
} else {
|
||||||
}
|
throw e;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (content == null) {
|
|
||||||
throw new IOException("Feed content is empty.");
|
if (content == null) {
|
||||||
}
|
throw new IOException("Feed content is empty.");
|
||||||
|
}
|
||||||
boolean lastModifiedHeaderValueChanged = !StringUtils.equals(lastModified, result.getLastModifiedSince());
|
|
||||||
boolean etagHeaderValueChanged = !StringUtils.equals(eTag, result.getETag());
|
boolean lastModifiedHeaderValueChanged = !StringUtils.equals(lastModified, result.getLastModifiedSince());
|
||||||
|
boolean etagHeaderValueChanged = !StringUtils.equals(eTag, result.getETag());
|
||||||
String hash = Digests.sha1Hex(content);
|
|
||||||
if (lastContentHash != null && lastContentHash.equals(hash)) {
|
String hash = Digests.sha1Hex(content);
|
||||||
log.debug("content hash not modified: {}", feedUrl);
|
if (lastContentHash != null && lastContentHash.equals(hash)) {
|
||||||
throw new NotModifiedException("content hash not modified",
|
log.debug("content hash not modified: {}", feedUrl);
|
||||||
lastModifiedHeaderValueChanged ? result.getLastModifiedSince() : null,
|
throw new NotModifiedException("content hash not modified",
|
||||||
etagHeaderValueChanged ? result.getETag() : null);
|
lastModifiedHeaderValueChanged ? result.getLastModifiedSince() : null,
|
||||||
}
|
etagHeaderValueChanged ? result.getETag() : null);
|
||||||
|
}
|
||||||
if (lastPublishedDate != null && lastPublishedDate.equals(parserResult.lastPublishedDate())) {
|
|
||||||
log.debug("publishedDate not modified: {}", feedUrl);
|
if (lastPublishedDate != null && lastPublishedDate.equals(parserResult.lastPublishedDate())) {
|
||||||
throw new NotModifiedException("publishedDate not modified",
|
log.debug("publishedDate not modified: {}", feedUrl);
|
||||||
lastModifiedHeaderValueChanged ? result.getLastModifiedSince() : null,
|
throw new NotModifiedException("publishedDate not modified",
|
||||||
etagHeaderValueChanged ? result.getETag() : null);
|
lastModifiedHeaderValueChanged ? result.getLastModifiedSince() : null,
|
||||||
}
|
etagHeaderValueChanged ? result.getETag() : null);
|
||||||
|
}
|
||||||
return new FeedFetcherResult(parserResult, result.getUrlAfterRedirect(), result.getLastModifiedSince(), result.getETag(), hash,
|
|
||||||
result.getValidFor());
|
return new FeedFetcherResult(parserResult, result.getUrlAfterRedirect(), result.getLastModifiedSince(), result.getETag(), hash,
|
||||||
}
|
result.getValidFor());
|
||||||
|
}
|
||||||
private static String extractFeedUrl(List<FeedURLProvider> urlProviders, String url, String urlContent) {
|
|
||||||
for (FeedURLProvider urlProvider : urlProviders) {
|
private static String extractFeedUrl(List<FeedURLProvider> urlProviders, String url, String urlContent) {
|
||||||
String feedUrl = urlProvider.get(url, urlContent);
|
for (FeedURLProvider urlProvider : urlProviders) {
|
||||||
if (feedUrl != null) {
|
String feedUrl = urlProvider.get(url, urlContent);
|
||||||
return feedUrl;
|
if (feedUrl != null) {
|
||||||
}
|
return feedUrl;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return null;
|
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
public record FeedFetcherResult(FeedParserResult feed, String urlAfterRedirect, String lastModifiedHeader, String lastETagHeader,
|
|
||||||
String contentHash, Duration validFor) {
|
public record FeedFetcherResult(FeedParserResult feed, String urlAfterRedirect, String lastModifiedHeader, String lastETagHeader,
|
||||||
}
|
String contentHash, Duration validFor) {
|
||||||
|
}
|
||||||
}
|
|
||||||
|
public static class NoFeedFoundException extends Exception {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public NoFeedFoundException(Throwable cause) {
|
||||||
|
super("This URL does not point to an RSS feed or a website with an RSS feed.", cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,213 +1,214 @@
|
|||||||
package com.commafeed.backend.feed;
|
package com.commafeed.backend.feed;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.BlockingDeque;
|
import java.util.concurrent.BlockingDeque;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.LinkedBlockingDeque;
|
import java.util.concurrent.LinkedBlockingDeque;
|
||||||
import java.util.concurrent.SynchronousQueue;
|
import java.util.concurrent.SynchronousQueue;
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import com.codahale.metrics.Gauge;
|
import jakarta.inject.Singleton;
|
||||||
import com.codahale.metrics.Meter;
|
|
||||||
import com.codahale.metrics.MetricRegistry;
|
import com.codahale.metrics.Gauge;
|
||||||
import com.commafeed.CommaFeedConfiguration;
|
import com.codahale.metrics.Meter;
|
||||||
import com.commafeed.backend.dao.FeedDAO;
|
import com.codahale.metrics.MetricRegistry;
|
||||||
import com.commafeed.backend.dao.UnitOfWork;
|
import com.commafeed.CommaFeedConfiguration;
|
||||||
import com.commafeed.backend.model.AbstractModel;
|
import com.commafeed.backend.dao.FeedDAO;
|
||||||
import com.commafeed.backend.model.Feed;
|
import com.commafeed.backend.dao.UnitOfWork;
|
||||||
|
import com.commafeed.backend.model.AbstractModel;
|
||||||
import jakarta.inject.Singleton;
|
import com.commafeed.backend.model.Feed;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@Slf4j
|
|
||||||
@Singleton
|
@Slf4j
|
||||||
public class FeedRefreshEngine {
|
@Singleton
|
||||||
|
public class FeedRefreshEngine {
|
||||||
private final UnitOfWork unitOfWork;
|
|
||||||
private final FeedDAO feedDAO;
|
private final UnitOfWork unitOfWork;
|
||||||
private final FeedRefreshWorker worker;
|
private final FeedDAO feedDAO;
|
||||||
private final FeedRefreshUpdater updater;
|
private final FeedRefreshWorker worker;
|
||||||
private final CommaFeedConfiguration config;
|
private final FeedRefreshUpdater updater;
|
||||||
private final Meter refill;
|
private final CommaFeedConfiguration config;
|
||||||
|
private final Meter refill;
|
||||||
private final BlockingDeque<Feed> queue;
|
|
||||||
|
private final BlockingDeque<Feed> queue;
|
||||||
private final ExecutorService feedProcessingLoopExecutor;
|
|
||||||
private final ExecutorService refillLoopExecutor;
|
private final ExecutorService feedProcessingLoopExecutor;
|
||||||
private final ExecutorService refillExecutor;
|
private final ExecutorService refillLoopExecutor;
|
||||||
private final ThreadPoolExecutor workerExecutor;
|
private final ExecutorService refillExecutor;
|
||||||
private final ThreadPoolExecutor databaseUpdaterExecutor;
|
private final ThreadPoolExecutor workerExecutor;
|
||||||
|
private final ThreadPoolExecutor databaseUpdaterExecutor;
|
||||||
public FeedRefreshEngine(UnitOfWork unitOfWork, FeedDAO feedDAO, FeedRefreshWorker worker, FeedRefreshUpdater updater,
|
|
||||||
CommaFeedConfiguration config, MetricRegistry metrics) {
|
public FeedRefreshEngine(UnitOfWork unitOfWork, FeedDAO feedDAO, FeedRefreshWorker worker, FeedRefreshUpdater updater,
|
||||||
this.unitOfWork = unitOfWork;
|
CommaFeedConfiguration config, MetricRegistry metrics) {
|
||||||
this.feedDAO = feedDAO;
|
this.unitOfWork = unitOfWork;
|
||||||
this.worker = worker;
|
this.feedDAO = feedDAO;
|
||||||
this.updater = updater;
|
this.worker = worker;
|
||||||
this.config = config;
|
this.updater = updater;
|
||||||
this.refill = metrics.meter(MetricRegistry.name(getClass(), "refill"));
|
this.config = config;
|
||||||
|
this.refill = metrics.meter(MetricRegistry.name(getClass(), "refill"));
|
||||||
this.queue = new LinkedBlockingDeque<>();
|
|
||||||
|
this.queue = new LinkedBlockingDeque<>();
|
||||||
this.feedProcessingLoopExecutor = Executors.newSingleThreadExecutor();
|
|
||||||
this.refillLoopExecutor = Executors.newSingleThreadExecutor();
|
this.feedProcessingLoopExecutor = Executors.newSingleThreadExecutor();
|
||||||
this.refillExecutor = newDiscardingSingleThreadExecutorService();
|
this.refillLoopExecutor = Executors.newSingleThreadExecutor();
|
||||||
this.workerExecutor = newBlockingExecutorService(config.feedRefresh().httpThreads());
|
this.refillExecutor = newDiscardingSingleThreadExecutorService();
|
||||||
this.databaseUpdaterExecutor = newBlockingExecutorService(config.feedRefresh().databaseThreads());
|
this.workerExecutor = newBlockingExecutorService(config.feedRefresh().httpThreads());
|
||||||
|
this.databaseUpdaterExecutor = newBlockingExecutorService(config.feedRefresh().databaseThreads());
|
||||||
metrics.register(MetricRegistry.name(getClass(), "queue", "size"), (Gauge<Integer>) queue::size);
|
|
||||||
metrics.register(MetricRegistry.name(getClass(), "worker", "active"), (Gauge<Integer>) workerExecutor::getActiveCount);
|
metrics.register(MetricRegistry.name(getClass(), "queue", "size"), (Gauge<Integer>) queue::size);
|
||||||
metrics.register(MetricRegistry.name(getClass(), "updater", "active"), (Gauge<Integer>) databaseUpdaterExecutor::getActiveCount);
|
metrics.register(MetricRegistry.name(getClass(), "worker", "active"), (Gauge<Integer>) workerExecutor::getActiveCount);
|
||||||
}
|
metrics.register(MetricRegistry.name(getClass(), "updater", "active"), (Gauge<Integer>) databaseUpdaterExecutor::getActiveCount);
|
||||||
|
}
|
||||||
public void start() {
|
|
||||||
startFeedProcessingLoop();
|
public void start() {
|
||||||
startRefillLoop();
|
startFeedProcessingLoop();
|
||||||
}
|
startRefillLoop();
|
||||||
|
}
|
||||||
private void startFeedProcessingLoop() {
|
|
||||||
// take a feed from the queue, process it, rince, repeat
|
private void startFeedProcessingLoop() {
|
||||||
feedProcessingLoopExecutor.submit(() -> {
|
// take a feed from the queue, process it, rince, repeat
|
||||||
while (!feedProcessingLoopExecutor.isShutdown()) {
|
feedProcessingLoopExecutor.submit(() -> {
|
||||||
try {
|
while (!feedProcessingLoopExecutor.isShutdown()) {
|
||||||
// take() is blocking until a feed is available from the queue
|
try {
|
||||||
Feed feed = queue.take();
|
// take() is blocking until a feed is available from the queue
|
||||||
|
Feed feed = queue.take();
|
||||||
// send the feed to be processed
|
|
||||||
log.debug("got feed {} from the queue, send it for processing", feed.getId());
|
// send the feed to be processed
|
||||||
processFeedAsync(feed);
|
log.debug("got feed {} from the queue, send it for processing", feed.getId());
|
||||||
|
processFeedAsync(feed);
|
||||||
// we removed a feed from the queue, try to refill it as it may now be empty
|
|
||||||
if (queue.isEmpty()) {
|
// we removed a feed from the queue, try to refill it as it may now be empty
|
||||||
log.debug("took the last feed from the queue, try to refill");
|
if (queue.isEmpty()) {
|
||||||
refillQueueAsync();
|
log.debug("took the last feed from the queue, try to refill");
|
||||||
}
|
refillQueueAsync();
|
||||||
} catch (InterruptedException e) {
|
}
|
||||||
log.debug("interrupted while waiting for a feed in the queue");
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
log.debug("interrupted while waiting for a feed in the queue");
|
||||||
} catch (Exception e) {
|
Thread.currentThread().interrupt();
|
||||||
log.error(e.getMessage(), e);
|
} catch (Exception e) {
|
||||||
}
|
log.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
});
|
||||||
|
}
|
||||||
private void startRefillLoop() {
|
|
||||||
// refill the queue at regular intervals if it's empty
|
private void startRefillLoop() {
|
||||||
refillLoopExecutor.submit(() -> {
|
// refill the queue at regular intervals if it's empty
|
||||||
while (!refillLoopExecutor.isShutdown()) {
|
refillLoopExecutor.submit(() -> {
|
||||||
try {
|
while (!refillLoopExecutor.isShutdown()) {
|
||||||
if (queue.isEmpty()) {
|
try {
|
||||||
log.debug("refilling queue");
|
if (queue.isEmpty()) {
|
||||||
refillQueueAsync();
|
log.debug("refilling queue");
|
||||||
}
|
refillQueueAsync();
|
||||||
|
}
|
||||||
log.debug("sleeping for 15s");
|
|
||||||
TimeUnit.SECONDS.sleep(15);
|
log.debug("sleeping for 15s");
|
||||||
} catch (InterruptedException e) {
|
TimeUnit.SECONDS.sleep(15);
|
||||||
log.debug("interrupted while sleeping");
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
log.debug("interrupted while sleeping");
|
||||||
} catch (Exception e) {
|
Thread.currentThread().interrupt();
|
||||||
log.error(e.getMessage(), e);
|
} catch (Exception e) {
|
||||||
}
|
log.error(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
});
|
||||||
|
}
|
||||||
public void refreshImmediately(Feed feed) {
|
|
||||||
log.debug("add feed {} at the start of the queue", feed.getId());
|
public void refreshImmediately(Feed feed) {
|
||||||
// remove the feed from the queue if it was already queued to avoid refreshing it twice
|
log.debug("add feed {} at the start of the queue", feed.getId());
|
||||||
queue.removeIf(f -> f.getId().equals(feed.getId()));
|
// remove the feed from the queue if it was already queued to avoid refreshing it twice
|
||||||
queue.addFirst(feed);
|
queue.removeIf(f -> f.getId().equals(feed.getId()));
|
||||||
}
|
queue.addFirst(feed);
|
||||||
|
}
|
||||||
private void refillQueueAsync() {
|
|
||||||
CompletableFuture.runAsync(() -> {
|
private void refillQueueAsync() {
|
||||||
if (!queue.isEmpty()) {
|
CompletableFuture.runAsync(() -> {
|
||||||
return;
|
if (!queue.isEmpty()) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
refill.mark();
|
|
||||||
|
refill.mark();
|
||||||
List<Feed> nextUpdatableFeeds = getNextUpdatableFeeds(getBatchSize());
|
|
||||||
log.debug("found {} feeds that are up for refresh", nextUpdatableFeeds.size());
|
List<Feed> nextUpdatableFeeds = getNextUpdatableFeeds(getBatchSize());
|
||||||
for (Feed feed : nextUpdatableFeeds) {
|
log.debug("found {} feeds that are up for refresh", nextUpdatableFeeds.size());
|
||||||
// add the feed only if it was not already queued
|
for (Feed feed : nextUpdatableFeeds) {
|
||||||
if (queue.stream().noneMatch(f -> f.getId().equals(feed.getId()))) {
|
// add the feed only if it was not already queued
|
||||||
queue.addLast(feed);
|
if (queue.stream().noneMatch(f -> f.getId().equals(feed.getId()))) {
|
||||||
}
|
queue.addLast(feed);
|
||||||
}
|
}
|
||||||
}, refillExecutor).whenComplete((data, ex) -> {
|
}
|
||||||
if (ex != null) {
|
}, refillExecutor).whenComplete((data, ex) -> {
|
||||||
log.error("error while refilling the queue", ex);
|
if (ex != null) {
|
||||||
}
|
log.error("error while refilling the queue", ex);
|
||||||
});
|
}
|
||||||
}
|
});
|
||||||
|
}
|
||||||
private void processFeedAsync(Feed feed) {
|
|
||||||
CompletableFuture.supplyAsync(() -> worker.update(feed), workerExecutor)
|
private void processFeedAsync(Feed feed) {
|
||||||
.thenApplyAsync(r -> updater.update(r.feed(), r.entries()), databaseUpdaterExecutor)
|
CompletableFuture.supplyAsync(() -> worker.update(feed), workerExecutor)
|
||||||
.whenComplete((data, ex) -> {
|
.thenApplyAsync(r -> updater.update(r.feed(), r.entries()), databaseUpdaterExecutor)
|
||||||
if (ex != null) {
|
.whenComplete((data, ex) -> {
|
||||||
log.error("error while processing feed {}", feed.getUrl(), ex);
|
if (ex != null) {
|
||||||
}
|
log.error("error while processing feed {}", feed.getUrl(), ex);
|
||||||
});
|
}
|
||||||
}
|
});
|
||||||
|
}
|
||||||
private List<Feed> getNextUpdatableFeeds(int max) {
|
|
||||||
return unitOfWork.call(() -> {
|
private List<Feed> getNextUpdatableFeeds(int max) {
|
||||||
Instant lastLoginThreshold = config.feedRefresh().userInactivityPeriod().isZero() ? null
|
return unitOfWork.call(() -> {
|
||||||
: Instant.now().minus(config.feedRefresh().userInactivityPeriod());
|
Instant lastLoginThreshold = config.feedRefresh().userInactivityPeriod().isZero() ? null
|
||||||
List<Feed> feeds = feedDAO.findNextUpdatable(max, lastLoginThreshold);
|
: Instant.now().minus(config.feedRefresh().userInactivityPeriod());
|
||||||
// update disabledUntil to prevent feeds from being returned again by feedDAO.findNextUpdatable()
|
List<Feed> feeds = feedDAO.findNextUpdatable(max, lastLoginThreshold);
|
||||||
Instant nextUpdateDate = Instant.now().plus(config.feedRefresh().interval());
|
// update disabledUntil to prevent feeds from being returned again by feedDAO.findNextUpdatable()
|
||||||
feedDAO.setDisabledUntil(feeds.stream().map(AbstractModel::getId).toList(), nextUpdateDate);
|
Instant nextUpdateDate = Instant.now().plus(config.feedRefresh().interval());
|
||||||
return feeds;
|
feedDAO.setDisabledUntil(feeds.stream().map(AbstractModel::getId).toList(), nextUpdateDate);
|
||||||
});
|
return feeds;
|
||||||
}
|
});
|
||||||
|
}
|
||||||
private int getBatchSize() {
|
|
||||||
return Math.min(100, 3 * config.feedRefresh().httpThreads());
|
private int getBatchSize() {
|
||||||
}
|
return Math.min(100, 3 * config.feedRefresh().httpThreads());
|
||||||
|
}
|
||||||
public void stop() {
|
|
||||||
this.feedProcessingLoopExecutor.shutdownNow();
|
public void stop() {
|
||||||
this.refillLoopExecutor.shutdownNow();
|
this.feedProcessingLoopExecutor.shutdownNow();
|
||||||
this.refillExecutor.shutdownNow();
|
this.refillLoopExecutor.shutdownNow();
|
||||||
this.workerExecutor.shutdownNow();
|
this.refillExecutor.shutdownNow();
|
||||||
this.databaseUpdaterExecutor.shutdownNow();
|
this.workerExecutor.shutdownNow();
|
||||||
}
|
this.databaseUpdaterExecutor.shutdownNow();
|
||||||
|
}
|
||||||
/**
|
|
||||||
* returns an ExecutorService with a single thread that discards tasks if a task is already running
|
/**
|
||||||
*/
|
* returns an ExecutorService with a single thread that discards tasks if a task is already running
|
||||||
private ThreadPoolExecutor newDiscardingSingleThreadExecutorService() {
|
*/
|
||||||
ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new SynchronousQueue<>());
|
private ThreadPoolExecutor newDiscardingSingleThreadExecutorService() {
|
||||||
pool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
|
ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new SynchronousQueue<>());
|
||||||
return pool;
|
pool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
|
||||||
}
|
return pool;
|
||||||
|
}
|
||||||
/**
|
|
||||||
* returns an ExecutorService that blocks submissions until a thread is available
|
/**
|
||||||
*/
|
* returns an ExecutorService that blocks submissions until a thread is available
|
||||||
private ThreadPoolExecutor newBlockingExecutorService(int threads) {
|
*/
|
||||||
ThreadPoolExecutor pool = new ThreadPoolExecutor(threads, threads, 0L, TimeUnit.MILLISECONDS, new SynchronousQueue<>());
|
private ThreadPoolExecutor newBlockingExecutorService(int threads) {
|
||||||
pool.setRejectedExecutionHandler((r, e) -> {
|
ThreadPoolExecutor pool = new ThreadPoolExecutor(threads, threads, 0L, TimeUnit.MILLISECONDS, new SynchronousQueue<>());
|
||||||
if (e.isShutdown()) {
|
pool.setRejectedExecutionHandler((r, e) -> {
|
||||||
return;
|
if (e.isShutdown()) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
try {
|
|
||||||
e.getQueue().put(r);
|
try {
|
||||||
} catch (InterruptedException ex) {
|
e.getQueue().put(r);
|
||||||
log.debug("interrupted while waiting for a slot in the queue.", ex);
|
} catch (InterruptedException ex) {
|
||||||
Thread.currentThread().interrupt();
|
log.debug("interrupted while waiting for a slot in the queue.", ex);
|
||||||
}
|
Thread.currentThread().interrupt();
|
||||||
});
|
}
|
||||||
return pool;
|
});
|
||||||
}
|
return pool;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,84 +1,84 @@
|
|||||||
package com.commafeed.backend.feed;
|
package com.commafeed.backend.feed;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.InstantSource;
|
import java.time.InstantSource;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
|
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
import jakarta.inject.Singleton;
|
||||||
|
|
||||||
import com.commafeed.CommaFeedConfiguration;
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
import com.commafeed.CommaFeedConfiguration.FeedRefreshErrorHandling;
|
|
||||||
import com.google.common.primitives.Longs;
|
import com.commafeed.CommaFeedConfiguration;
|
||||||
|
import com.commafeed.CommaFeedConfiguration.FeedRefreshErrorHandling;
|
||||||
import jakarta.inject.Singleton;
|
import com.google.common.primitives.Longs;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class FeedRefreshIntervalCalculator {
|
public class FeedRefreshIntervalCalculator {
|
||||||
|
|
||||||
private final Duration interval;
|
private final Duration interval;
|
||||||
private final Duration maxInterval;
|
private final Duration maxInterval;
|
||||||
private final boolean empirical;
|
private final boolean empirical;
|
||||||
private final FeedRefreshErrorHandling errorHandling;
|
private final FeedRefreshErrorHandling errorHandling;
|
||||||
private final InstantSource instantSource;
|
private final InstantSource instantSource;
|
||||||
|
|
||||||
public FeedRefreshIntervalCalculator(CommaFeedConfiguration config, InstantSource instantSource) {
|
public FeedRefreshIntervalCalculator(CommaFeedConfiguration config, InstantSource instantSource) {
|
||||||
this.interval = config.feedRefresh().interval();
|
this.interval = config.feedRefresh().interval();
|
||||||
this.maxInterval = config.feedRefresh().maxInterval();
|
this.maxInterval = config.feedRefresh().maxInterval();
|
||||||
this.empirical = config.feedRefresh().intervalEmpirical();
|
this.empirical = config.feedRefresh().intervalEmpirical();
|
||||||
this.errorHandling = config.feedRefresh().errors();
|
this.errorHandling = config.feedRefresh().errors();
|
||||||
this.instantSource = instantSource;
|
this.instantSource = instantSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Instant onFetchSuccess(Instant publishedDate, Long averageEntryInterval, Duration validFor) {
|
public Instant onFetchSuccess(Instant publishedDate, Long averageEntryInterval, Duration validFor) {
|
||||||
Instant instant = empirical ? computeEmpiricalRefreshInterval(publishedDate, averageEntryInterval)
|
Instant instant = empirical ? computeEmpiricalRefreshInterval(publishedDate, averageEntryInterval)
|
||||||
: instantSource.instant().plus(interval);
|
: instantSource.instant().plus(interval);
|
||||||
return constrainToBounds(ObjectUtils.max(instant, instantSource.instant().plus(validFor)));
|
return constrainToBounds(ObjectUtils.max(instant, instantSource.instant().plus(validFor)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Instant onFeedNotModified(Instant publishedDate, Long averageEntryInterval) {
|
public Instant onFeedNotModified(Instant publishedDate, Long averageEntryInterval) {
|
||||||
return onFetchSuccess(publishedDate, averageEntryInterval, Duration.ZERO);
|
return onFetchSuccess(publishedDate, averageEntryInterval, Duration.ZERO);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Instant onTooManyRequests(Instant retryAfter, int errorCount) {
|
public Instant onTooManyRequests(Instant retryAfter, int errorCount) {
|
||||||
return constrainToBounds(ObjectUtils.max(retryAfter, onFetchError(errorCount)));
|
return constrainToBounds(ObjectUtils.max(retryAfter, onFetchError(errorCount)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Instant onFetchError(int errorCount) {
|
public Instant onFetchError(int errorCount) {
|
||||||
if (errorCount < errorHandling.retriesBeforeBackoff()) {
|
if (errorCount < errorHandling.retriesBeforeBackoff()) {
|
||||||
return constrainToBounds(instantSource.instant().plus(interval));
|
return constrainToBounds(instantSource.instant().plus(interval));
|
||||||
}
|
}
|
||||||
|
|
||||||
Duration retryInterval = errorHandling.backoffInterval().multipliedBy(errorCount - errorHandling.retriesBeforeBackoff() + 1L);
|
Duration retryInterval = errorHandling.backoffInterval().multipliedBy(errorCount - errorHandling.retriesBeforeBackoff() + 1L);
|
||||||
return constrainToBounds(instantSource.instant().plus(retryInterval));
|
return constrainToBounds(instantSource.instant().plus(retryInterval));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Instant computeEmpiricalRefreshInterval(Instant publishedDate, Long averageEntryInterval) {
|
private Instant computeEmpiricalRefreshInterval(Instant publishedDate, Long averageEntryInterval) {
|
||||||
Instant now = instantSource.instant();
|
Instant now = instantSource.instant();
|
||||||
|
|
||||||
if (publishedDate == null) {
|
if (publishedDate == null) {
|
||||||
return now.plus(maxInterval);
|
return now.plus(maxInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
long daysSinceLastPublication = ChronoUnit.DAYS.between(publishedDate, now);
|
long daysSinceLastPublication = ChronoUnit.DAYS.between(publishedDate, now);
|
||||||
if (daysSinceLastPublication >= 30) {
|
if (daysSinceLastPublication >= 30) {
|
||||||
return now.plus(maxInterval);
|
return now.plus(maxInterval);
|
||||||
} else if (daysSinceLastPublication >= 14) {
|
} else if (daysSinceLastPublication >= 14) {
|
||||||
return now.plus(maxInterval.dividedBy(2));
|
return now.plus(maxInterval.dividedBy(2));
|
||||||
} else if (daysSinceLastPublication >= 7) {
|
} else if (daysSinceLastPublication >= 7) {
|
||||||
return now.plus(maxInterval.dividedBy(4));
|
return now.plus(maxInterval.dividedBy(4));
|
||||||
} else if (averageEntryInterval != null) {
|
} else if (averageEntryInterval != null) {
|
||||||
// use average time between entries to decide when to refresh next, divided by factor
|
// use average time between entries to decide when to refresh next, divided by factor
|
||||||
int factor = 2;
|
int factor = 2;
|
||||||
long millis = Longs.constrainToRange(averageEntryInterval / factor, interval.toMillis(), maxInterval.dividedBy(4).toMillis());
|
long millis = Longs.constrainToRange(averageEntryInterval / factor, interval.toMillis(), maxInterval.dividedBy(4).toMillis());
|
||||||
return now.plusMillis(millis);
|
return now.plusMillis(millis);
|
||||||
} else {
|
} else {
|
||||||
// unknown case
|
// unknown case
|
||||||
return now.plus(maxInterval);
|
return now.plus(maxInterval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Instant constrainToBounds(Instant instant) {
|
private Instant constrainToBounds(Instant instant) {
|
||||||
return ObjectUtils.max(ObjectUtils.min(instant, instantSource.instant().plus(maxInterval)), instantSource.instant().plus(interval));
|
return ObjectUtils.max(ObjectUtils.min(instant, instantSource.instant().plus(maxInterval)), instantSource.instant().plus(interval));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,179 +1,180 @@
|
|||||||
package com.commafeed.backend.feed;
|
package com.commafeed.backend.feed;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import jakarta.inject.Singleton;
|
||||||
|
|
||||||
import com.codahale.metrics.Meter;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import com.codahale.metrics.MetricRegistry;
|
|
||||||
import com.commafeed.backend.Digests;
|
import com.codahale.metrics.Meter;
|
||||||
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
import com.codahale.metrics.MetricRegistry;
|
||||||
import com.commafeed.backend.dao.UnitOfWork;
|
import com.commafeed.backend.Digests;
|
||||||
import com.commafeed.backend.feed.parser.FeedParserResult.Content;
|
import com.commafeed.backend.dao.FeedSubscriptionDAO;
|
||||||
import com.commafeed.backend.feed.parser.FeedParserResult.Entry;
|
import com.commafeed.backend.dao.UnitOfWork;
|
||||||
import com.commafeed.backend.model.Feed;
|
import com.commafeed.backend.feed.parser.FeedParserResult.Content;
|
||||||
import com.commafeed.backend.model.FeedEntry;
|
import com.commafeed.backend.feed.parser.FeedParserResult.Entry;
|
||||||
import com.commafeed.backend.model.FeedSubscription;
|
import com.commafeed.backend.model.Feed;
|
||||||
import com.commafeed.backend.model.Models;
|
import com.commafeed.backend.model.FeedEntry;
|
||||||
import com.commafeed.backend.service.FeedEntryService;
|
import com.commafeed.backend.model.FeedSubscription;
|
||||||
import com.commafeed.backend.service.FeedService;
|
import com.commafeed.backend.model.Models;
|
||||||
import com.commafeed.frontend.ws.WebSocketMessageBuilder;
|
import com.commafeed.backend.service.FeedEntryService;
|
||||||
import com.commafeed.frontend.ws.WebSocketSessions;
|
import com.commafeed.backend.service.FeedService;
|
||||||
import com.google.common.util.concurrent.Striped;
|
import com.commafeed.frontend.ws.WebSocketMessageBuilder;
|
||||||
|
import com.commafeed.frontend.ws.WebSocketSessions;
|
||||||
import jakarta.inject.Singleton;
|
import com.google.common.util.concurrent.Striped;
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
/**
|
|
||||||
* Updates the feed in the database and inserts new entries
|
/**
|
||||||
*/
|
* Updates the feed in the database and inserts new entries
|
||||||
@Slf4j
|
*/
|
||||||
@Singleton
|
@Slf4j
|
||||||
public class FeedRefreshUpdater {
|
@Singleton
|
||||||
|
public class FeedRefreshUpdater {
|
||||||
private final UnitOfWork unitOfWork;
|
|
||||||
private final FeedService feedService;
|
private final UnitOfWork unitOfWork;
|
||||||
private final FeedEntryService feedEntryService;
|
private final FeedService feedService;
|
||||||
private final FeedSubscriptionDAO feedSubscriptionDAO;
|
private final FeedEntryService feedEntryService;
|
||||||
private final WebSocketSessions webSocketSessions;
|
private final FeedSubscriptionDAO feedSubscriptionDAO;
|
||||||
|
private final WebSocketSessions webSocketSessions;
|
||||||
private final Striped<Lock> locks;
|
|
||||||
|
private final Striped<Lock> locks;
|
||||||
private final Meter feedUpdated;
|
|
||||||
private final Meter entryInserted;
|
private final Meter feedUpdated;
|
||||||
|
private final Meter entryInserted;
|
||||||
public FeedRefreshUpdater(UnitOfWork unitOfWork, FeedService feedService, FeedEntryService feedEntryService, MetricRegistry metrics,
|
|
||||||
FeedSubscriptionDAO feedSubscriptionDAO, WebSocketSessions webSocketSessions) {
|
public FeedRefreshUpdater(UnitOfWork unitOfWork, FeedService feedService, FeedEntryService feedEntryService, MetricRegistry metrics,
|
||||||
this.unitOfWork = unitOfWork;
|
FeedSubscriptionDAO feedSubscriptionDAO, WebSocketSessions webSocketSessions) {
|
||||||
this.feedService = feedService;
|
this.unitOfWork = unitOfWork;
|
||||||
this.feedEntryService = feedEntryService;
|
this.feedService = feedService;
|
||||||
this.feedSubscriptionDAO = feedSubscriptionDAO;
|
this.feedEntryService = feedEntryService;
|
||||||
this.webSocketSessions = webSocketSessions;
|
this.feedSubscriptionDAO = feedSubscriptionDAO;
|
||||||
|
this.webSocketSessions = webSocketSessions;
|
||||||
locks = Striped.lazyWeakLock(100000);
|
|
||||||
|
locks = Striped.lazyWeakLock(100000);
|
||||||
feedUpdated = metrics.meter(MetricRegistry.name(getClass(), "feedUpdated"));
|
|
||||||
entryInserted = metrics.meter(MetricRegistry.name(getClass(), "entryInserted"));
|
feedUpdated = metrics.meter(MetricRegistry.name(getClass(), "feedUpdated"));
|
||||||
}
|
entryInserted = metrics.meter(MetricRegistry.name(getClass(), "entryInserted"));
|
||||||
|
}
|
||||||
private AddEntryResult addEntry(final Feed feed, final Entry entry, final List<FeedSubscription> subscriptions) {
|
|
||||||
boolean processed = false;
|
private AddEntryResult addEntry(final Feed feed, final Entry entry, final List<FeedSubscription> subscriptions) {
|
||||||
boolean inserted = false;
|
boolean processed = false;
|
||||||
Set<FeedSubscription> subscriptionsForWhichEntryIsUnread = new HashSet<>();
|
boolean inserted = false;
|
||||||
|
Set<FeedSubscription> subscriptionsForWhichEntryIsUnread = new HashSet<>();
|
||||||
// lock on feed, make sure we are not updating the same feed twice at
|
|
||||||
// the same time
|
// lock on feed, make sure we are not updating the same feed twice at
|
||||||
String key1 = StringUtils.trimToEmpty(String.valueOf(feed.getId()));
|
// the same time
|
||||||
|
String key1 = StringUtils.trimToEmpty(String.valueOf(feed.getId()));
|
||||||
// lock on content, make sure we are not updating the same entry
|
|
||||||
// twice at the same time
|
// lock on content, make sure we are not updating the same entry
|
||||||
Content content = entry.content();
|
// twice at the same time
|
||||||
String key2 = Digests.sha1Hex(StringUtils.trimToEmpty(content.content() + content.title()));
|
Content content = entry.content();
|
||||||
|
String key2 = Digests.sha1Hex(StringUtils.trimToEmpty(content.content() + content.title()));
|
||||||
Iterator<Lock> iterator = locks.bulkGet(Arrays.asList(key1, key2)).iterator();
|
|
||||||
Lock lock1 = iterator.next();
|
Iterator<Lock> iterator = locks.bulkGet(Arrays.asList(key1, key2)).iterator();
|
||||||
Lock lock2 = iterator.next();
|
Lock lock1 = iterator.next();
|
||||||
boolean locked1 = false;
|
Lock lock2 = iterator.next();
|
||||||
boolean locked2 = false;
|
boolean locked1 = false;
|
||||||
try {
|
boolean locked2 = false;
|
||||||
// try to lock, give up after 1 minute
|
try {
|
||||||
locked1 = lock1.tryLock(1, TimeUnit.MINUTES);
|
// try to lock, give up after 1 minute
|
||||||
locked2 = lock2.tryLock(1, TimeUnit.MINUTES);
|
locked1 = lock1.tryLock(1, TimeUnit.MINUTES);
|
||||||
if (locked1 && locked2) {
|
locked2 = lock2.tryLock(1, TimeUnit.MINUTES);
|
||||||
processed = true;
|
if (locked1 && locked2) {
|
||||||
inserted = unitOfWork.call(() -> {
|
processed = true;
|
||||||
boolean newEntry = false;
|
inserted = unitOfWork.call(() -> {
|
||||||
FeedEntry feedEntry = feedEntryService.find(feed, entry);
|
boolean newEntry = false;
|
||||||
if (feedEntry == null) {
|
FeedEntry feedEntry = feedEntryService.find(feed, entry);
|
||||||
feedEntry = feedEntryService.create(feed, entry);
|
if (feedEntry == null) {
|
||||||
newEntry = true;
|
feedEntry = feedEntryService.create(feed, entry);
|
||||||
}
|
newEntry = true;
|
||||||
if (newEntry) {
|
}
|
||||||
entryInserted.mark();
|
if (newEntry) {
|
||||||
for (FeedSubscription sub : subscriptions) {
|
entryInserted.mark();
|
||||||
boolean unread = feedEntryService.applyFilter(sub, feedEntry);
|
for (FeedSubscription sub : subscriptions) {
|
||||||
if (unread) {
|
boolean unread = feedEntryService.applyFilter(sub, feedEntry);
|
||||||
subscriptionsForWhichEntryIsUnread.add(sub);
|
if (unread) {
|
||||||
}
|
subscriptionsForWhichEntryIsUnread.add(sub);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return newEntry;
|
}
|
||||||
});
|
return newEntry;
|
||||||
} else {
|
});
|
||||||
log.error("lock timeout for {} - {}", feed.getUrl(), key1);
|
} else {
|
||||||
}
|
log.error("lock timeout for {} - {}", feed.getUrl(), key1);
|
||||||
} catch (InterruptedException e) {
|
}
|
||||||
log.error("interrupted while waiting for lock for {} : {}", feed.getUrl(), e.getMessage(), e);
|
} catch (InterruptedException e) {
|
||||||
} finally {
|
log.error("interrupted while waiting for lock for {} : {}", feed.getUrl(), e.getMessage(), e);
|
||||||
if (locked1) {
|
} finally {
|
||||||
lock1.unlock();
|
if (locked1) {
|
||||||
}
|
lock1.unlock();
|
||||||
if (locked2) {
|
}
|
||||||
lock2.unlock();
|
if (locked2) {
|
||||||
}
|
lock2.unlock();
|
||||||
}
|
}
|
||||||
return new AddEntryResult(processed, inserted, subscriptionsForWhichEntryIsUnread);
|
}
|
||||||
}
|
return new AddEntryResult(processed, inserted, subscriptionsForWhichEntryIsUnread);
|
||||||
|
}
|
||||||
public boolean update(Feed feed, List<Entry> entries) {
|
|
||||||
boolean processed = true;
|
public boolean update(Feed feed, List<Entry> entries) {
|
||||||
long inserted = 0;
|
boolean processed = true;
|
||||||
Map<FeedSubscription, Long> unreadCountBySubscription = new HashMap<>();
|
long inserted = 0;
|
||||||
|
Map<FeedSubscription, Long> unreadCountBySubscription = new HashMap<>();
|
||||||
if (!entries.isEmpty()) {
|
|
||||||
List<FeedSubscription> subscriptions = null;
|
if (!entries.isEmpty()) {
|
||||||
for (Entry entry : entries) {
|
List<FeedSubscription> subscriptions = null;
|
||||||
if (subscriptions == null) {
|
for (Entry entry : entries) {
|
||||||
subscriptions = unitOfWork.call(() -> feedSubscriptionDAO.findByFeed(feed));
|
if (subscriptions == null) {
|
||||||
}
|
subscriptions = unitOfWork.call(() -> feedSubscriptionDAO.findByFeed(feed));
|
||||||
AddEntryResult addEntryResult = addEntry(feed, entry, subscriptions);
|
}
|
||||||
processed &= addEntryResult.processed;
|
AddEntryResult addEntryResult = addEntry(feed, entry, subscriptions);
|
||||||
inserted += addEntryResult.inserted ? 1 : 0;
|
processed &= addEntryResult.processed;
|
||||||
addEntryResult.subscriptionsForWhichEntryIsUnread.forEach(sub -> unreadCountBySubscription.merge(sub, 1L, Long::sum));
|
inserted += addEntryResult.inserted ? 1 : 0;
|
||||||
}
|
addEntryResult.subscriptionsForWhichEntryIsUnread.forEach(sub -> unreadCountBySubscription.merge(sub, 1L, Long::sum));
|
||||||
|
}
|
||||||
if (inserted == 0) {
|
|
||||||
feed.setMessage("No new entries found");
|
if (inserted == 0) {
|
||||||
} else if (inserted > 0) {
|
feed.setMessage("No new entries found");
|
||||||
feed.setMessage("Found %s new entries".formatted(inserted));
|
} else if (inserted > 0) {
|
||||||
}
|
feed.setMessage("Found %s new entries".formatted(inserted));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!processed) {
|
|
||||||
// requeue asap
|
if (!processed) {
|
||||||
feed.setDisabledUntil(Models.MINIMUM_INSTANT);
|
// requeue asap
|
||||||
}
|
feed.setDisabledUntil(Models.MINIMUM_INSTANT);
|
||||||
|
}
|
||||||
if (inserted > 0) {
|
|
||||||
feedUpdated.mark();
|
if (inserted > 0) {
|
||||||
}
|
feedUpdated.mark();
|
||||||
|
}
|
||||||
unitOfWork.run(() -> feedService.update(feed));
|
|
||||||
|
unitOfWork.run(() -> feedService.update(feed));
|
||||||
notifyOverWebsocket(unreadCountBySubscription);
|
|
||||||
|
notifyOverWebsocket(unreadCountBySubscription);
|
||||||
return processed;
|
|
||||||
}
|
return processed;
|
||||||
|
}
|
||||||
private void notifyOverWebsocket(Map<FeedSubscription, Long> unreadCountBySubscription) {
|
|
||||||
unreadCountBySubscription.forEach((sub, unreadCount) -> webSocketSessions.sendMessage(sub.getUser(),
|
private void notifyOverWebsocket(Map<FeedSubscription, Long> unreadCountBySubscription) {
|
||||||
WebSocketMessageBuilder.newFeedEntries(sub, unreadCount)));
|
unreadCountBySubscription.forEach((sub, unreadCount) -> webSocketSessions.sendMessage(sub.getUser(),
|
||||||
}
|
WebSocketMessageBuilder.newFeedEntries(sub, unreadCount)));
|
||||||
|
}
|
||||||
@AllArgsConstructor
|
|
||||||
private static class AddEntryResult {
|
@AllArgsConstructor
|
||||||
private final boolean processed;
|
private static class AddEntryResult {
|
||||||
private final boolean inserted;
|
private final boolean processed;
|
||||||
private final Set<FeedSubscription> subscriptionsForWhichEntryIsUnread;
|
private final boolean inserted;
|
||||||
}
|
private final Set<FeedSubscription> subscriptionsForWhichEntryIsUnread;
|
||||||
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,124 +1,125 @@
|
|||||||
package com.commafeed.backend.feed;
|
package com.commafeed.backend.feed;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import jakarta.inject.Singleton;
|
||||||
|
|
||||||
import com.codahale.metrics.Meter;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import com.codahale.metrics.MetricRegistry;
|
|
||||||
import com.commafeed.CommaFeedConfiguration;
|
import com.codahale.metrics.Meter;
|
||||||
import com.commafeed.backend.HttpGetter.NotModifiedException;
|
import com.codahale.metrics.MetricRegistry;
|
||||||
import com.commafeed.backend.HttpGetter.TooManyRequestsException;
|
import com.commafeed.CommaFeedConfiguration;
|
||||||
import com.commafeed.backend.feed.FeedFetcher.FeedFetcherResult;
|
import com.commafeed.backend.HttpGetter.NotModifiedException;
|
||||||
import com.commafeed.backend.feed.parser.FeedParserResult.Entry;
|
import com.commafeed.backend.HttpGetter.TooManyRequestsException;
|
||||||
import com.commafeed.backend.model.Feed;
|
import com.commafeed.backend.feed.FeedFetcher.FeedFetcherResult;
|
||||||
|
import com.commafeed.backend.feed.parser.FeedParserResult.Entry;
|
||||||
import jakarta.inject.Singleton;
|
import com.commafeed.backend.model.Feed;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
/**
|
|
||||||
* Calls {@link FeedFetcher} and updates the Feed object, but does not update the database, ({@link FeedRefreshUpdater} does that)
|
/**
|
||||||
*/
|
* Calls {@link FeedFetcher} and updates the Feed object, but does not update the database, ({@link FeedRefreshUpdater} does that)
|
||||||
@Slf4j
|
*/
|
||||||
@Singleton
|
@Slf4j
|
||||||
public class FeedRefreshWorker {
|
@Singleton
|
||||||
|
public class FeedRefreshWorker {
|
||||||
private final FeedRefreshIntervalCalculator refreshIntervalCalculator;
|
|
||||||
private final FeedFetcher fetcher;
|
private final FeedRefreshIntervalCalculator refreshIntervalCalculator;
|
||||||
private final CommaFeedConfiguration config;
|
private final FeedFetcher fetcher;
|
||||||
private final Meter feedFetched;
|
private final CommaFeedConfiguration config;
|
||||||
|
private final Meter feedFetched;
|
||||||
public FeedRefreshWorker(FeedRefreshIntervalCalculator refreshIntervalCalculator, FeedFetcher fetcher, CommaFeedConfiguration config,
|
|
||||||
MetricRegistry metrics) {
|
public FeedRefreshWorker(FeedRefreshIntervalCalculator refreshIntervalCalculator, FeedFetcher fetcher, CommaFeedConfiguration config,
|
||||||
this.refreshIntervalCalculator = refreshIntervalCalculator;
|
MetricRegistry metrics) {
|
||||||
this.fetcher = fetcher;
|
this.refreshIntervalCalculator = refreshIntervalCalculator;
|
||||||
this.config = config;
|
this.fetcher = fetcher;
|
||||||
this.feedFetched = metrics.meter(MetricRegistry.name(getClass(), "feedFetched"));
|
this.config = config;
|
||||||
|
this.feedFetched = metrics.meter(MetricRegistry.name(getClass(), "feedFetched"));
|
||||||
}
|
|
||||||
|
}
|
||||||
public FeedRefreshWorkerResult update(Feed feed) {
|
|
||||||
try {
|
public FeedRefreshWorkerResult update(Feed feed) {
|
||||||
String url = Optional.ofNullable(feed.getUrlAfterRedirect()).orElse(feed.getUrl());
|
try {
|
||||||
FeedFetcherResult result = fetcher.fetch(url, false, feed.getLastModifiedHeader(), feed.getEtagHeader(),
|
String url = Optional.ofNullable(feed.getUrlAfterRedirect()).orElse(feed.getUrl());
|
||||||
feed.getLastPublishedDate(), feed.getLastContentHash());
|
FeedFetcherResult result = fetcher.fetch(url, false, feed.getLastModifiedHeader(), feed.getEtagHeader(),
|
||||||
// stops here if NotModifiedException or any other exception is thrown
|
feed.getLastPublishedDate(), feed.getLastContentHash());
|
||||||
|
// stops here if NotModifiedException or any other exception is thrown
|
||||||
List<Entry> entries = result.feed().entries();
|
|
||||||
|
List<Entry> entries = result.feed().entries();
|
||||||
int maxFeedCapacity = config.database().cleanup().maxFeedCapacity();
|
|
||||||
if (maxFeedCapacity > 0) {
|
int maxFeedCapacity = config.database().cleanup().maxFeedCapacity();
|
||||||
entries = entries.stream().limit(maxFeedCapacity).toList();
|
if (maxFeedCapacity > 0) {
|
||||||
}
|
entries = entries.stream().limit(maxFeedCapacity).toList();
|
||||||
|
}
|
||||||
Duration entriesMaxAge = config.database().cleanup().entriesMaxAge();
|
|
||||||
if (!entriesMaxAge.isZero()) {
|
Duration entriesMaxAge = config.database().cleanup().entriesMaxAge();
|
||||||
Instant threshold = Instant.now().minus(entriesMaxAge);
|
if (!entriesMaxAge.isZero()) {
|
||||||
entries = entries.stream().filter(entry -> entry.published().isAfter(threshold)).toList();
|
Instant threshold = Instant.now().minus(entriesMaxAge);
|
||||||
}
|
entries = entries.stream().filter(entry -> entry.published().isAfter(threshold)).toList();
|
||||||
|
}
|
||||||
String urlAfterRedirect = result.urlAfterRedirect();
|
|
||||||
if (StringUtils.equals(url, urlAfterRedirect)) {
|
String urlAfterRedirect = result.urlAfterRedirect();
|
||||||
urlAfterRedirect = null;
|
if (StringUtils.equals(url, urlAfterRedirect)) {
|
||||||
}
|
urlAfterRedirect = null;
|
||||||
|
}
|
||||||
feed.setUrlAfterRedirect(urlAfterRedirect);
|
|
||||||
feed.setLink(result.feed().link());
|
feed.setUrlAfterRedirect(urlAfterRedirect);
|
||||||
feed.setLastModifiedHeader(result.lastModifiedHeader());
|
feed.setLink(result.feed().link());
|
||||||
feed.setEtagHeader(result.lastETagHeader());
|
feed.setLastModifiedHeader(result.lastModifiedHeader());
|
||||||
feed.setLastContentHash(result.contentHash());
|
feed.setEtagHeader(result.lastETagHeader());
|
||||||
feed.setLastPublishedDate(result.feed().lastPublishedDate());
|
feed.setLastContentHash(result.contentHash());
|
||||||
feed.setAverageEntryInterval(result.feed().averageEntryInterval());
|
feed.setLastPublishedDate(result.feed().lastPublishedDate());
|
||||||
feed.setLastEntryDate(result.feed().lastEntryDate());
|
feed.setAverageEntryInterval(result.feed().averageEntryInterval());
|
||||||
|
feed.setLastEntryDate(result.feed().lastEntryDate());
|
||||||
feed.setErrorCount(0);
|
|
||||||
feed.setMessage(null);
|
feed.setErrorCount(0);
|
||||||
feed.setDisabledUntil(refreshIntervalCalculator.onFetchSuccess(result.feed().lastPublishedDate(),
|
feed.setMessage(null);
|
||||||
result.feed().averageEntryInterval(), result.validFor()));
|
feed.setDisabledUntil(refreshIntervalCalculator.onFetchSuccess(result.feed().lastPublishedDate(),
|
||||||
|
result.feed().averageEntryInterval(), result.validFor()));
|
||||||
return new FeedRefreshWorkerResult(feed, entries);
|
|
||||||
} catch (NotModifiedException e) {
|
return new FeedRefreshWorkerResult(feed, entries);
|
||||||
log.debug("Feed not modified : {} - {}", feed.getUrl(), e.getMessage());
|
} catch (NotModifiedException e) {
|
||||||
|
log.debug("Feed not modified : {} - {}", feed.getUrl(), e.getMessage());
|
||||||
feed.setErrorCount(0);
|
|
||||||
feed.setMessage(e.getMessage());
|
feed.setErrorCount(0);
|
||||||
feed.setDisabledUntil(refreshIntervalCalculator.onFeedNotModified(feed.getLastPublishedDate(), feed.getAverageEntryInterval()));
|
feed.setMessage(e.getMessage());
|
||||||
|
feed.setDisabledUntil(refreshIntervalCalculator.onFeedNotModified(feed.getLastPublishedDate(), feed.getAverageEntryInterval()));
|
||||||
if (e.getNewLastModifiedHeader() != null) {
|
|
||||||
feed.setLastModifiedHeader(e.getNewLastModifiedHeader());
|
if (e.getNewLastModifiedHeader() != null) {
|
||||||
}
|
feed.setLastModifiedHeader(e.getNewLastModifiedHeader());
|
||||||
|
}
|
||||||
if (e.getNewEtagHeader() != null) {
|
|
||||||
feed.setEtagHeader(e.getNewEtagHeader());
|
if (e.getNewEtagHeader() != null) {
|
||||||
}
|
feed.setEtagHeader(e.getNewEtagHeader());
|
||||||
|
}
|
||||||
return new FeedRefreshWorkerResult(feed, Collections.emptyList());
|
|
||||||
} catch (TooManyRequestsException e) {
|
return new FeedRefreshWorkerResult(feed, Collections.emptyList());
|
||||||
log.debug("Too many requests : {}", feed.getUrl());
|
} catch (TooManyRequestsException e) {
|
||||||
|
log.debug("Too many requests : {}", feed.getUrl());
|
||||||
feed.setErrorCount(feed.getErrorCount() + 1);
|
|
||||||
feed.setMessage("Server indicated that we are sending too many requests");
|
feed.setErrorCount(feed.getErrorCount() + 1);
|
||||||
feed.setDisabledUntil(refreshIntervalCalculator.onTooManyRequests(e.getRetryAfter(), feed.getErrorCount()));
|
feed.setMessage("Server indicated that we are sending too many requests");
|
||||||
|
feed.setDisabledUntil(refreshIntervalCalculator.onTooManyRequests(e.getRetryAfter(), feed.getErrorCount()));
|
||||||
return new FeedRefreshWorkerResult(feed, Collections.emptyList());
|
|
||||||
} catch (Exception e) {
|
return new FeedRefreshWorkerResult(feed, Collections.emptyList());
|
||||||
log.debug("unable to refresh feed {}", feed.getUrl(), e);
|
} catch (Exception e) {
|
||||||
|
log.debug("unable to refresh feed {}", feed.getUrl(), e);
|
||||||
feed.setErrorCount(feed.getErrorCount() + 1);
|
|
||||||
feed.setMessage("Unable to refresh feed : " + e.getMessage());
|
feed.setErrorCount(feed.getErrorCount() + 1);
|
||||||
feed.setDisabledUntil(refreshIntervalCalculator.onFetchError(feed.getErrorCount()));
|
feed.setMessage("Unable to refresh feed : " + e.getMessage());
|
||||||
|
feed.setDisabledUntil(refreshIntervalCalculator.onFetchError(feed.getErrorCount()));
|
||||||
return new FeedRefreshWorkerResult(feed, Collections.emptyList());
|
|
||||||
} finally {
|
return new FeedRefreshWorkerResult(feed, Collections.emptyList());
|
||||||
feedFetched.mark();
|
} finally {
|
||||||
}
|
feedFetched.mark();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public record FeedRefreshWorkerResult(Feed feed, List<Entry> entries) {
|
|
||||||
}
|
public record FeedRefreshWorkerResult(Feed feed, List<Entry> entries) {
|
||||||
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,218 +1,218 @@
|
|||||||
package com.commafeed.backend.feed;
|
package com.commafeed.backend.feed;
|
||||||
|
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.hc.client5.http.utils.Base64;
|
import org.apache.hc.client5.http.utils.Base64;
|
||||||
import org.jsoup.Jsoup;
|
import org.jsoup.Jsoup;
|
||||||
import org.jsoup.nodes.Document;
|
import org.jsoup.nodes.Document;
|
||||||
import org.jsoup.nodes.Element;
|
import org.jsoup.nodes.Element;
|
||||||
import org.jsoup.select.Elements;
|
import org.jsoup.select.Elements;
|
||||||
import org.netpreserve.urlcanon.Canonicalizer;
|
import org.netpreserve.urlcanon.Canonicalizer;
|
||||||
import org.netpreserve.urlcanon.ParsedUrl;
|
import org.netpreserve.urlcanon.ParsedUrl;
|
||||||
|
|
||||||
import com.commafeed.backend.feed.FeedEntryKeyword.Mode;
|
import com.commafeed.backend.feed.FeedEntryKeyword.Mode;
|
||||||
import com.commafeed.backend.feed.parser.TextDirectionDetector;
|
import com.commafeed.backend.feed.parser.TextDirectionDetector;
|
||||||
import com.commafeed.backend.model.FeedSubscription;
|
import com.commafeed.backend.model.FeedSubscription;
|
||||||
import com.commafeed.frontend.model.Entry;
|
import com.commafeed.frontend.model.Entry;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility methods related to feed handling
|
* Utility methods related to feed handling
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class FeedUtils {
|
public class FeedUtils {
|
||||||
|
|
||||||
private static final String ESCAPED_QUESTION_MARK = Pattern.quote("?");
|
private static final String ESCAPED_QUESTION_MARK = Pattern.quote("?");
|
||||||
|
|
||||||
public static String truncate(String string, int length) {
|
public static String truncate(String string, int length) {
|
||||||
if (string != null) {
|
if (string != null) {
|
||||||
string = string.substring(0, Math.min(length, string.length()));
|
string = string.substring(0, Math.min(length, string.length()));
|
||||||
}
|
}
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isHttp(String url) {
|
public static boolean isHttp(String url) {
|
||||||
return url.startsWith("http://");
|
return url.startsWith("http://");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isHttps(String url) {
|
public static boolean isHttps(String url) {
|
||||||
return url.startsWith("https://");
|
return url.startsWith("https://");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isAbsoluteUrl(String url) {
|
public static boolean isAbsoluteUrl(String url) {
|
||||||
return isHttp(url) || isHttps(url);
|
return isHttp(url) || isHttps(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalize the url. The resulting url is not meant to be fetched but rather used as a mean to identify a feed and avoid duplicates
|
* Normalize the url. The resulting url is not meant to be fetched but rather used as a mean to identify a feed and avoid duplicates
|
||||||
*/
|
*/
|
||||||
public static String normalizeURL(String url) {
|
public static String normalizeURL(String url) {
|
||||||
if (url == null) {
|
if (url == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParsedUrl parsedUrl = ParsedUrl.parseUrl(url);
|
ParsedUrl parsedUrl = ParsedUrl.parseUrl(url);
|
||||||
Canonicalizer.AGGRESSIVE.canonicalize(parsedUrl);
|
Canonicalizer.AGGRESSIVE.canonicalize(parsedUrl);
|
||||||
String normalized = parsedUrl.toString();
|
String normalized = parsedUrl.toString();
|
||||||
if (normalized == null) {
|
if (normalized == null) {
|
||||||
normalized = url;
|
normalized = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert to lower case, the url probably won't work in some cases
|
// convert to lower case, the url probably won't work in some cases
|
||||||
// after that but we don't care we just want to compare urls to avoid
|
// after that but we don't care we just want to compare urls to avoid
|
||||||
// duplicates
|
// duplicates
|
||||||
normalized = normalized.toLowerCase();
|
normalized = normalized.toLowerCase();
|
||||||
|
|
||||||
// store all urls as http
|
// store all urls as http
|
||||||
if (normalized.startsWith("https")) {
|
if (normalized.startsWith("https")) {
|
||||||
normalized = "http" + normalized.substring(5);
|
normalized = "http" + normalized.substring(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove the www. part
|
// remove the www. part
|
||||||
normalized = normalized.replace("//www.", "//");
|
normalized = normalized.replace("//www.", "//");
|
||||||
|
|
||||||
// feedproxy redirects to feedburner
|
// feedproxy redirects to feedburner
|
||||||
normalized = normalized.replace("feedproxy.google.com", "feeds.feedburner.com");
|
normalized = normalized.replace("feedproxy.google.com", "feeds.feedburner.com");
|
||||||
|
|
||||||
// feedburner feeds have a special treatment
|
// feedburner feeds have a special treatment
|
||||||
if (normalized.split(ESCAPED_QUESTION_MARK)[0].contains("feedburner.com")) {
|
if (normalized.split(ESCAPED_QUESTION_MARK)[0].contains("feedburner.com")) {
|
||||||
normalized = normalized.replace("feeds2.feedburner.com", "feeds.feedburner.com");
|
normalized = normalized.replace("feeds2.feedburner.com", "feeds.feedburner.com");
|
||||||
normalized = normalized.split(ESCAPED_QUESTION_MARK)[0];
|
normalized = normalized.split(ESCAPED_QUESTION_MARK)[0];
|
||||||
normalized = StringUtils.removeEnd(normalized, "/");
|
normalized = StringUtils.removeEnd(normalized, "/");
|
||||||
}
|
}
|
||||||
|
|
||||||
return normalized;
|
return normalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isRTL(String title, String content) {
|
public static boolean isRTL(String title, String content) {
|
||||||
String text = StringUtils.isNotBlank(content) ? content : title;
|
String text = StringUtils.isNotBlank(content) ? content : title;
|
||||||
if (StringUtils.isBlank(text)) {
|
if (StringUtils.isBlank(text)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String stripped = Jsoup.parse(text).text();
|
String stripped = Jsoup.parse(text).text();
|
||||||
if (StringUtils.isBlank(stripped)) {
|
if (StringUtils.isBlank(stripped)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TextDirectionDetector.detect(stripped) == TextDirectionDetector.Direction.RIGHT_TO_LEFT;
|
return TextDirectionDetector.detect(stripped) == TextDirectionDetector.Direction.RIGHT_TO_LEFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String removeTrailingSlash(String url) {
|
public static String removeTrailingSlash(String url) {
|
||||||
if (url.endsWith("/")) {
|
if (url.endsWith("/")) {
|
||||||
url = url.substring(0, url.length() - 1);
|
url = url.substring(0, url.length() - 1);
|
||||||
}
|
}
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param relativeUrl
|
* @param relativeUrl
|
||||||
* the url of the entry
|
* the url of the entry
|
||||||
* @param feedLink
|
* @param feedLink
|
||||||
* the url of the feed as described in the feed
|
* the url of the feed as described in the feed
|
||||||
* @param feedUrl
|
* @param feedUrl
|
||||||
* the url of the feed that we used to fetch the feed
|
* the url of the feed that we used to fetch the feed
|
||||||
* @return an absolute url pointing to the entry
|
* @return an absolute url pointing to the entry
|
||||||
*/
|
*/
|
||||||
public static String toAbsoluteUrl(String relativeUrl, String feedLink, String feedUrl) {
|
public static String toAbsoluteUrl(String relativeUrl, String feedLink, String feedUrl) {
|
||||||
String baseUrl = (feedLink != null && isAbsoluteUrl(feedLink)) ? feedLink : feedUrl;
|
String baseUrl = (feedLink != null && isAbsoluteUrl(feedLink)) ? feedLink : feedUrl;
|
||||||
if (baseUrl == null) {
|
if (baseUrl == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return new URL(new URL(baseUrl), relativeUrl).toString();
|
return new URL(new URL(baseUrl), relativeUrl).toString();
|
||||||
} catch (MalformedURLException e) {
|
} catch (MalformedURLException e) {
|
||||||
log.debug("could not parse url : {}", e.getMessage(), e);
|
log.debug("could not parse url : {}", e.getMessage(), e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getFaviconUrl(FeedSubscription subscription) {
|
public static String getFaviconUrl(FeedSubscription subscription) {
|
||||||
return "rest/feed/favicon/" + subscription.getId();
|
return "rest/feed/favicon/" + subscription.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String proxyImages(String content) {
|
public static String proxyImages(String content) {
|
||||||
if (StringUtils.isBlank(content)) {
|
if (StringUtils.isBlank(content)) {
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
Document doc = Jsoup.parse(content);
|
Document doc = Jsoup.parse(content);
|
||||||
Elements elements = doc.select("img");
|
Elements elements = doc.select("img");
|
||||||
for (Element element : elements) {
|
for (Element element : elements) {
|
||||||
String href = element.attr("src");
|
String href = element.attr("src");
|
||||||
if (StringUtils.isNotBlank(href)) {
|
if (StringUtils.isNotBlank(href)) {
|
||||||
String proxy = proxyImage(href);
|
String proxy = proxyImage(href);
|
||||||
element.attr("src", proxy);
|
element.attr("src", proxy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return doc.body().html();
|
return doc.body().html();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String proxyImage(String url) {
|
public static String proxyImage(String url) {
|
||||||
if (StringUtils.isBlank(url)) {
|
if (StringUtils.isBlank(url)) {
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
return "rest/server/proxy?u=" + imageProxyEncoder(url);
|
return "rest/server/proxy?u=" + imageProxyEncoder(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String rot13(String msg) {
|
public static String rot13(String msg) {
|
||||||
StringBuilder message = new StringBuilder();
|
StringBuilder message = new StringBuilder();
|
||||||
|
|
||||||
for (char c : msg.toCharArray()) {
|
for (char c : msg.toCharArray()) {
|
||||||
if (c >= 'a' && c <= 'm') {
|
if (c >= 'a' && c <= 'm') {
|
||||||
c += 13;
|
c += 13;
|
||||||
} else if (c >= 'n' && c <= 'z') {
|
} else if (c >= 'n' && c <= 'z') {
|
||||||
c -= 13;
|
c -= 13;
|
||||||
} else if (c >= 'A' && c <= 'M') {
|
} else if (c >= 'A' && c <= 'M') {
|
||||||
c += 13;
|
c += 13;
|
||||||
} else if (c >= 'N' && c <= 'Z') {
|
} else if (c >= 'N' && c <= 'Z') {
|
||||||
c -= 13;
|
c -= 13;
|
||||||
}
|
}
|
||||||
message.append(c);
|
message.append(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
return message.toString();
|
return message.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String imageProxyEncoder(String url) {
|
public static String imageProxyEncoder(String url) {
|
||||||
return Base64.encodeBase64String(rot13(url).getBytes());
|
return Base64.encodeBase64String(rot13(url).getBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String imageProxyDecoder(String code) {
|
public static String imageProxyDecoder(String code) {
|
||||||
return rot13(new String(Base64.decodeBase64(code)));
|
return rot13(new String(Base64.decodeBase64(code)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void removeUnwantedFromSearch(List<Entry> entries, List<FeedEntryKeyword> keywords) {
|
public static void removeUnwantedFromSearch(List<Entry> entries, List<FeedEntryKeyword> keywords) {
|
||||||
Iterator<Entry> it = entries.iterator();
|
Iterator<Entry> it = entries.iterator();
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
Entry entry = it.next();
|
Entry entry = it.next();
|
||||||
boolean keep = true;
|
boolean keep = true;
|
||||||
for (FeedEntryKeyword keyword : keywords) {
|
for (FeedEntryKeyword keyword : keywords) {
|
||||||
String title = entry.getTitle() == null ? null : Jsoup.parse(entry.getTitle()).text();
|
String title = entry.getTitle() == null ? null : Jsoup.parse(entry.getTitle()).text();
|
||||||
String content = entry.getContent() == null ? null : Jsoup.parse(entry.getContent()).text();
|
String content = entry.getContent() == null ? null : Jsoup.parse(entry.getContent()).text();
|
||||||
boolean condition = !StringUtils.containsIgnoreCase(content, keyword.getKeyword())
|
boolean condition = !StringUtils.containsIgnoreCase(content, keyword.getKeyword())
|
||||||
&& !StringUtils.containsIgnoreCase(title, keyword.getKeyword());
|
&& !StringUtils.containsIgnoreCase(title, keyword.getKeyword());
|
||||||
if (keyword.getMode() == Mode.EXCLUDE) {
|
if (keyword.getMode() == Mode.EXCLUDE) {
|
||||||
condition = !condition;
|
condition = !condition;
|
||||||
}
|
}
|
||||||
if (condition) {
|
if (condition) {
|
||||||
keep = false;
|
keep = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!keep) {
|
if (!keep) {
|
||||||
it.remove();
|
it.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,70 +1,70 @@
|
|||||||
package com.commafeed.backend.feed.parser;
|
package com.commafeed.backend.feed.parser;
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import jakarta.inject.Singleton;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
import com.ibm.icu.text.CharsetDetector;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import com.ibm.icu.text.CharsetMatch;
|
|
||||||
|
import com.ibm.icu.text.CharsetDetector;
|
||||||
import jakarta.inject.Singleton;
|
import com.ibm.icu.text.CharsetMatch;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class EncodingDetector {
|
class EncodingDetector {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detect feed encoding by using the declared encoding in the xml processing instruction and by detecting the characters used in the
|
* Detect feed encoding by using the declared encoding in the xml processing instruction and by detecting the characters used in the
|
||||||
* feed
|
* feed
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public Charset getEncoding(byte[] bytes) {
|
public Charset getEncoding(byte[] bytes) {
|
||||||
String extracted = extractDeclaredEncoding(bytes);
|
String extracted = extractDeclaredEncoding(bytes);
|
||||||
if (StringUtils.startsWithIgnoreCase(extracted, "iso-8859-")) {
|
if (StringUtils.startsWithIgnoreCase(extracted, "iso-8859-")) {
|
||||||
if (!StringUtils.endsWith(extracted, "1")) {
|
if (!StringUtils.endsWith(extracted, "1")) {
|
||||||
return Charset.forName(extracted);
|
return Charset.forName(extracted);
|
||||||
}
|
}
|
||||||
} else if (StringUtils.startsWithIgnoreCase(extracted, "windows-")) {
|
} else if (StringUtils.startsWithIgnoreCase(extracted, "windows-")) {
|
||||||
return Charset.forName(extracted);
|
return Charset.forName(extracted);
|
||||||
}
|
}
|
||||||
return detectEncoding(bytes);
|
return detectEncoding(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract the declared encoding from the xml
|
* Extract the declared encoding from the xml
|
||||||
*/
|
*/
|
||||||
public String extractDeclaredEncoding(byte[] bytes) {
|
public String extractDeclaredEncoding(byte[] bytes) {
|
||||||
int index = ArrayUtils.indexOf(bytes, (byte) '>');
|
int index = ArrayUtils.indexOf(bytes, (byte) '>');
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String pi = new String(ArrayUtils.subarray(bytes, 0, index + 1)).replace('\'', '"');
|
String pi = new String(ArrayUtils.subarray(bytes, 0, index + 1)).replace('\'', '"');
|
||||||
index = StringUtils.indexOf(pi, "encoding=\"");
|
index = StringUtils.indexOf(pi, "encoding=\"");
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String encoding = pi.substring(index + 10);
|
String encoding = pi.substring(index + 10);
|
||||||
encoding = encoding.substring(0, encoding.indexOf('"'));
|
encoding = encoding.substring(0, encoding.indexOf('"'));
|
||||||
return encoding;
|
return encoding;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detect encoding by analyzing characters in the array
|
* Detect encoding by analyzing characters in the array
|
||||||
*/
|
*/
|
||||||
private Charset detectEncoding(byte[] bytes) {
|
private Charset detectEncoding(byte[] bytes) {
|
||||||
String encoding = "UTF-8";
|
String encoding = "UTF-8";
|
||||||
|
|
||||||
CharsetDetector detector = new CharsetDetector();
|
CharsetDetector detector = new CharsetDetector();
|
||||||
detector.setText(bytes);
|
detector.setText(bytes);
|
||||||
CharsetMatch match = detector.detect();
|
CharsetMatch match = detector.detect();
|
||||||
if (match != null) {
|
if (match != null) {
|
||||||
encoding = match.getName();
|
encoding = match.getName();
|
||||||
}
|
}
|
||||||
if (encoding.equalsIgnoreCase("ISO-8859-1")) {
|
if (encoding.equalsIgnoreCase("ISO-8859-1")) {
|
||||||
encoding = "windows-1252";
|
encoding = "windows-1252";
|
||||||
}
|
}
|
||||||
return Charset.forName(encoding);
|
return Charset.forName(encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,70 +1,70 @@
|
|||||||
package com.commafeed.backend.feed.parser;
|
package com.commafeed.backend.feed.parser;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.ahocorasick.trie.Emit;
|
import jakarta.inject.Singleton;
|
||||||
import org.ahocorasick.trie.Trie;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.ahocorasick.trie.Emit;
|
||||||
|
import org.ahocorasick.trie.Trie;
|
||||||
import jakarta.inject.Singleton;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class FeedCleaner {
|
class FeedCleaner {
|
||||||
|
|
||||||
private static final Pattern DOCTYPE_PATTERN = Pattern.compile("<!DOCTYPE[^>]*>", Pattern.CASE_INSENSITIVE);
|
private static final Pattern DOCTYPE_PATTERN = Pattern.compile("<!DOCTYPE[^>]*>", Pattern.CASE_INSENSITIVE);
|
||||||
|
|
||||||
public String trimInvalidXmlCharacters(String xml) {
|
public String trimInvalidXmlCharacters(String xml) {
|
||||||
if (StringUtils.isBlank(xml)) {
|
if (StringUtils.isBlank(xml)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
boolean firstTagFound = false;
|
boolean firstTagFound = false;
|
||||||
for (int i = 0; i < xml.length(); i++) {
|
for (int i = 0; i < xml.length(); i++) {
|
||||||
char c = xml.charAt(i);
|
char c = xml.charAt(i);
|
||||||
|
|
||||||
if (!firstTagFound) {
|
if (!firstTagFound) {
|
||||||
if (c == '<') {
|
if (c == '<') {
|
||||||
firstTagFound = true;
|
firstTagFound = true;
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c >= 32 || c == 9 || c == 10 || c == 13) {
|
if (c >= 32 || c == 9 || c == 10 || c == 13) {
|
||||||
if (!Character.isHighSurrogate(c) && !Character.isLowSurrogate(c)) {
|
if (!Character.isHighSurrogate(c) && !Character.isLowSurrogate(c)) {
|
||||||
sb.append(c);
|
sb.append(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://stackoverflow.com/a/40836618
|
// https://stackoverflow.com/a/40836618
|
||||||
public String replaceHtmlEntitiesWithNumericEntities(String source) {
|
public String replaceHtmlEntitiesWithNumericEntities(String source) {
|
||||||
// Create a buffer sufficiently large that re-allocations are minimized.
|
// Create a buffer sufficiently large that re-allocations are minimized.
|
||||||
StringBuilder sb = new StringBuilder(source.length() << 1);
|
StringBuilder sb = new StringBuilder(source.length() << 1);
|
||||||
|
|
||||||
Collection<Emit> emits = Trie.builder().ignoreOverlaps().addKeywords(HtmlEntities.HTML_ENTITIES).build().parseText(source);
|
Collection<Emit> emits = Trie.builder().ignoreOverlaps().addKeywords(HtmlEntities.HTML_ENTITIES).build().parseText(source);
|
||||||
|
|
||||||
int prevIndex = 0;
|
int prevIndex = 0;
|
||||||
for (Emit emit : emits) {
|
for (Emit emit : emits) {
|
||||||
int matchIndex = emit.getStart();
|
int matchIndex = emit.getStart();
|
||||||
|
|
||||||
sb.append(source, prevIndex, matchIndex);
|
sb.append(source, prevIndex, matchIndex);
|
||||||
sb.append(HtmlEntities.HTML_TO_NUMERIC_MAP.get(emit.getKeyword()));
|
sb.append(HtmlEntities.HTML_TO_NUMERIC_MAP.get(emit.getKeyword()));
|
||||||
prevIndex = emit.getEnd() + 1;
|
prevIndex = emit.getEnd() + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the remainder of the string (contains no more matches).
|
// Add the remainder of the string (contains no more matches).
|
||||||
sb.append(source.substring(prevIndex));
|
sb.append(source.substring(prevIndex));
|
||||||
|
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String removeDoctypeDeclarations(String xml) {
|
public String removeDoctypeDeclarations(String xml) {
|
||||||
return DOCTYPE_PATTERN.matcher(xml).replaceAll("");
|
return DOCTYPE_PATTERN.matcher(xml).replaceAll("");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,271 +1,285 @@
|
|||||||
package com.commafeed.backend.feed.parser;
|
package com.commafeed.backend.feed.parser;
|
||||||
|
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import jakarta.inject.Singleton;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.apache.commons.math3.stat.descriptive.SummaryStatistics;
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
import org.jdom2.Element;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.jdom2.Namespace;
|
import org.apache.commons.math3.stat.descriptive.SummaryStatistics;
|
||||||
import org.xml.sax.InputSource;
|
import org.jdom2.Element;
|
||||||
|
import org.jdom2.Namespace;
|
||||||
import com.commafeed.backend.feed.FeedUtils;
|
import org.xml.sax.InputSource;
|
||||||
import com.commafeed.backend.feed.parser.FeedParserResult.Content;
|
|
||||||
import com.commafeed.backend.feed.parser.FeedParserResult.Enclosure;
|
import com.commafeed.backend.feed.FeedUtils;
|
||||||
import com.commafeed.backend.feed.parser.FeedParserResult.Entry;
|
import com.commafeed.backend.feed.parser.FeedParserResult.Content;
|
||||||
import com.commafeed.backend.feed.parser.FeedParserResult.Media;
|
import com.commafeed.backend.feed.parser.FeedParserResult.Enclosure;
|
||||||
import com.google.common.collect.Iterables;
|
import com.commafeed.backend.feed.parser.FeedParserResult.Entry;
|
||||||
import com.rometools.modules.mediarss.MediaEntryModule;
|
import com.commafeed.backend.feed.parser.FeedParserResult.Media;
|
||||||
import com.rometools.modules.mediarss.MediaModule;
|
import com.google.common.collect.Iterables;
|
||||||
import com.rometools.modules.mediarss.types.MediaGroup;
|
import com.rometools.modules.mediarss.MediaEntryModule;
|
||||||
import com.rometools.modules.mediarss.types.Metadata;
|
import com.rometools.modules.mediarss.MediaModule;
|
||||||
import com.rometools.modules.mediarss.types.Thumbnail;
|
import com.rometools.modules.mediarss.types.MediaGroup;
|
||||||
import com.rometools.rome.feed.synd.SyndCategory;
|
import com.rometools.modules.mediarss.types.Metadata;
|
||||||
import com.rometools.rome.feed.synd.SyndContent;
|
import com.rometools.modules.mediarss.types.Thumbnail;
|
||||||
import com.rometools.rome.feed.synd.SyndEnclosure;
|
import com.rometools.rome.feed.synd.SyndCategory;
|
||||||
import com.rometools.rome.feed.synd.SyndEntry;
|
import com.rometools.rome.feed.synd.SyndContent;
|
||||||
import com.rometools.rome.feed.synd.SyndFeed;
|
import com.rometools.rome.feed.synd.SyndEnclosure;
|
||||||
import com.rometools.rome.feed.synd.SyndLink;
|
import com.rometools.rome.feed.synd.SyndEntry;
|
||||||
import com.rometools.rome.feed.synd.SyndLinkImpl;
|
import com.rometools.rome.feed.synd.SyndFeed;
|
||||||
import com.rometools.rome.io.FeedException;
|
import com.rometools.rome.feed.synd.SyndLink;
|
||||||
import com.rometools.rome.io.SyndFeedInput;
|
import com.rometools.rome.feed.synd.SyndLinkImpl;
|
||||||
|
import com.rometools.rome.io.SyndFeedInput;
|
||||||
import jakarta.inject.Singleton;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses raw xml into a FeedParserResult object
|
* Parses raw xml into a FeedParserResult object
|
||||||
*/
|
*/
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Singleton
|
@Singleton
|
||||||
public class FeedParser {
|
public class FeedParser {
|
||||||
|
|
||||||
private static final Namespace ATOM_10_NS = Namespace.getNamespace("http://www.w3.org/2005/Atom");
|
private static final Namespace ATOM_10_NS = Namespace.getNamespace("http://www.w3.org/2005/Atom");
|
||||||
|
|
||||||
private static final Instant START = Instant.ofEpochMilli(86400000);
|
private static final Instant START = Instant.ofEpochMilli(86400000);
|
||||||
private static final Instant END = Instant.ofEpochMilli(1000L * Integer.MAX_VALUE - 86400000);
|
private static final Instant END = Instant.ofEpochMilli(1000L * Integer.MAX_VALUE - 86400000);
|
||||||
|
|
||||||
private final EncodingDetector encodingDetector;
|
private final EncodingDetector encodingDetector;
|
||||||
private final FeedCleaner feedCleaner;
|
private final FeedCleaner feedCleaner;
|
||||||
|
|
||||||
public FeedParserResult parse(String feedUrl, byte[] xml) throws FeedException {
|
public FeedParserResult parse(String feedUrl, byte[] xml) throws FeedParsingException {
|
||||||
try {
|
try {
|
||||||
Charset encoding = encodingDetector.getEncoding(xml);
|
Charset encoding = encodingDetector.getEncoding(xml);
|
||||||
String xmlString = feedCleaner.trimInvalidXmlCharacters(new String(xml, encoding));
|
String xmlString = feedCleaner.trimInvalidXmlCharacters(new String(xml, encoding));
|
||||||
if (xmlString == null) {
|
if (xmlString == null) {
|
||||||
throw new FeedException("Input string is null for url " + feedUrl);
|
throw new FeedParsingException("Input string is null for url " + feedUrl);
|
||||||
}
|
}
|
||||||
xmlString = feedCleaner.replaceHtmlEntitiesWithNumericEntities(xmlString);
|
xmlString = feedCleaner.replaceHtmlEntitiesWithNumericEntities(xmlString);
|
||||||
xmlString = feedCleaner.removeDoctypeDeclarations(xmlString);
|
xmlString = feedCleaner.removeDoctypeDeclarations(xmlString);
|
||||||
|
|
||||||
InputSource source = new InputSource(new StringReader(xmlString));
|
InputSource source = new InputSource(new StringReader(xmlString));
|
||||||
SyndFeed feed = new SyndFeedInput().build(source);
|
SyndFeed feed = new SyndFeedInput().build(source);
|
||||||
handleForeignMarkup(feed);
|
handleForeignMarkup(feed);
|
||||||
|
|
||||||
String title = feed.getTitle();
|
String title = feed.getTitle();
|
||||||
String link = feed.getLink();
|
String link = feed.getLink();
|
||||||
List<Entry> entries = buildEntries(feed, feedUrl);
|
List<Entry> entries = buildEntries(feed, feedUrl);
|
||||||
Instant lastEntryDate = entries.stream().findFirst().map(Entry::published).orElse(null);
|
Instant lastEntryDate = entries.stream().findFirst().map(Entry::published).orElse(null);
|
||||||
Instant lastPublishedDate = toValidInstant(feed.getPublishedDate(), false);
|
Instant lastPublishedDate = toValidInstant(feed.getPublishedDate(), false);
|
||||||
if (lastPublishedDate == null || lastEntryDate != null && lastPublishedDate.isBefore(lastEntryDate)) {
|
if (lastPublishedDate == null || lastEntryDate != null && lastPublishedDate.isBefore(lastEntryDate)) {
|
||||||
lastPublishedDate = lastEntryDate;
|
lastPublishedDate = lastEntryDate;
|
||||||
}
|
}
|
||||||
Long averageEntryInterval = averageTimeBetweenEntries(entries);
|
Long averageEntryInterval = averageTimeBetweenEntries(entries);
|
||||||
|
|
||||||
return new FeedParserResult(title, link, lastPublishedDate, averageEntryInterval, lastEntryDate, entries);
|
return new FeedParserResult(title, link, lastPublishedDate, averageEntryInterval, lastEntryDate, entries);
|
||||||
} catch (Exception e) {
|
} catch (FeedParsingException e) {
|
||||||
throw new FeedException(String.format("Could not parse feed from %s : %s", feedUrl, e.getMessage()), e);
|
throw e;
|
||||||
}
|
} catch (Exception e) {
|
||||||
}
|
throw new FeedParsingException(String.format("Could not parse feed from %s : %s", feedUrl, e.getMessage()), e);
|
||||||
|
}
|
||||||
/**
|
}
|
||||||
* Adds atom links for rss feeds
|
|
||||||
*/
|
/**
|
||||||
private void handleForeignMarkup(SyndFeed feed) {
|
* Adds atom links for rss feeds
|
||||||
List<Element> foreignMarkup = feed.getForeignMarkup();
|
*/
|
||||||
if (foreignMarkup == null) {
|
private void handleForeignMarkup(SyndFeed feed) {
|
||||||
return;
|
List<Element> foreignMarkup = feed.getForeignMarkup();
|
||||||
}
|
if (foreignMarkup == null) {
|
||||||
for (Element element : foreignMarkup) {
|
return;
|
||||||
if ("link".equals(element.getName()) && ATOM_10_NS.equals(element.getNamespace())) {
|
}
|
||||||
SyndLink link = new SyndLinkImpl();
|
for (Element element : foreignMarkup) {
|
||||||
link.setRel(element.getAttributeValue("rel"));
|
if ("link".equals(element.getName()) && ATOM_10_NS.equals(element.getNamespace())) {
|
||||||
link.setHref(element.getAttributeValue("href"));
|
SyndLink link = new SyndLinkImpl();
|
||||||
feed.getLinks().add(link);
|
link.setRel(element.getAttributeValue("rel"));
|
||||||
}
|
link.setHref(element.getAttributeValue("href"));
|
||||||
}
|
feed.getLinks().add(link);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private List<Entry> buildEntries(SyndFeed feed, String feedUrl) {
|
}
|
||||||
List<Entry> entries = new ArrayList<>();
|
|
||||||
|
private List<Entry> buildEntries(SyndFeed feed, String feedUrl) {
|
||||||
for (SyndEntry item : feed.getEntries()) {
|
List<Entry> entries = new ArrayList<>();
|
||||||
String guid = item.getUri();
|
|
||||||
if (StringUtils.isBlank(guid)) {
|
for (SyndEntry item : feed.getEntries()) {
|
||||||
guid = item.getLink();
|
String guid = item.getUri();
|
||||||
}
|
if (StringUtils.isBlank(guid)) {
|
||||||
if (StringUtils.isBlank(guid)) {
|
guid = item.getLink();
|
||||||
// no guid and no link, skip entry
|
}
|
||||||
continue;
|
if (StringUtils.isBlank(guid)) {
|
||||||
}
|
// no guid and no link, skip entry
|
||||||
|
continue;
|
||||||
String url = buildEntryUrl(feed, feedUrl, item);
|
}
|
||||||
if (StringUtils.isBlank(url) && FeedUtils.isAbsoluteUrl(guid)) {
|
|
||||||
// if link is empty but guid is used as url, use guid
|
String url = buildEntryUrl(feed, feedUrl, item);
|
||||||
url = guid;
|
if (StringUtils.isBlank(url) && FeedUtils.isAbsoluteUrl(guid)) {
|
||||||
}
|
// if link is empty but guid is used as url, use guid
|
||||||
|
url = guid;
|
||||||
Instant publishedDate = buildEntryPublishedDate(item);
|
}
|
||||||
Content content = buildContent(item);
|
|
||||||
|
Instant publishedDate = buildEntryPublishedDate(item);
|
||||||
entries.add(new Entry(guid, url, publishedDate, content));
|
Content content = buildContent(item);
|
||||||
}
|
|
||||||
|
entries.add(new Entry(guid, url, publishedDate, content));
|
||||||
entries.sort(Comparator.comparing(Entry::published).reversed());
|
}
|
||||||
return entries;
|
|
||||||
}
|
entries.sort(Comparator.comparing(Entry::published).reversed());
|
||||||
|
return entries;
|
||||||
private Content buildContent(SyndEntry item) {
|
}
|
||||||
String title = getTitle(item);
|
|
||||||
String content = getContent(item);
|
private Content buildContent(SyndEntry item) {
|
||||||
String author = StringUtils.trimToNull(item.getAuthor());
|
String title = getTitle(item);
|
||||||
String categories = StringUtils
|
String content = getContent(item);
|
||||||
.trimToNull(item.getCategories().stream().map(SyndCategory::getName).collect(Collectors.joining(", ")));
|
String author = StringUtils.trimToNull(item.getAuthor());
|
||||||
|
String categories = StringUtils
|
||||||
Enclosure enclosure = buildEnclosure(item);
|
.trimToNull(item.getCategories().stream().map(SyndCategory::getName).collect(Collectors.joining(", ")));
|
||||||
Media media = buildMedia(item);
|
|
||||||
return new Content(title, content, author, categories, enclosure, media);
|
Enclosure enclosure = buildEnclosure(item);
|
||||||
}
|
Media media = buildMedia(item);
|
||||||
|
return new Content(title, content, author, categories, enclosure, media);
|
||||||
private Enclosure buildEnclosure(SyndEntry item) {
|
}
|
||||||
SyndEnclosure enclosure = Iterables.getFirst(item.getEnclosures(), null);
|
|
||||||
if (enclosure == null) {
|
private Enclosure buildEnclosure(SyndEntry item) {
|
||||||
return null;
|
SyndEnclosure enclosure = Iterables.getFirst(item.getEnclosures(), null);
|
||||||
}
|
if (enclosure == null) {
|
||||||
|
return null;
|
||||||
return new Enclosure(enclosure.getUrl(), enclosure.getType());
|
}
|
||||||
}
|
|
||||||
|
return new Enclosure(enclosure.getUrl(), enclosure.getType());
|
||||||
private Instant buildEntryPublishedDate(SyndEntry item) {
|
}
|
||||||
Date date = item.getPublishedDate();
|
|
||||||
if (date == null) {
|
private Instant buildEntryPublishedDate(SyndEntry item) {
|
||||||
date = item.getUpdatedDate();
|
Date date = item.getPublishedDate();
|
||||||
}
|
if (date == null) {
|
||||||
return toValidInstant(date, true);
|
date = item.getUpdatedDate();
|
||||||
}
|
}
|
||||||
|
return toValidInstant(date, true);
|
||||||
private String buildEntryUrl(SyndFeed feed, String feedUrl, SyndEntry item) {
|
}
|
||||||
String url = StringUtils.trimToNull(StringUtils.normalizeSpace(item.getLink()));
|
|
||||||
if (url == null || FeedUtils.isAbsoluteUrl(url)) {
|
private String buildEntryUrl(SyndFeed feed, String feedUrl, SyndEntry item) {
|
||||||
// url is absolute, nothing to do
|
String url = StringUtils.trimToNull(StringUtils.normalizeSpace(item.getLink()));
|
||||||
return url;
|
if (url == null || FeedUtils.isAbsoluteUrl(url)) {
|
||||||
}
|
// url is absolute, nothing to do
|
||||||
|
return url;
|
||||||
// url is relative, trying to resolve it
|
}
|
||||||
String feedLink = StringUtils.trimToNull(StringUtils.normalizeSpace(feed.getLink()));
|
|
||||||
return FeedUtils.toAbsoluteUrl(url, feedLink, feedUrl);
|
// url is relative, trying to resolve it
|
||||||
}
|
String feedLink = StringUtils.trimToNull(StringUtils.normalizeSpace(feed.getLink()));
|
||||||
|
return FeedUtils.toAbsoluteUrl(url, feedLink, feedUrl);
|
||||||
private Instant toValidInstant(Date date, boolean nullToNow) {
|
}
|
||||||
Instant now = Instant.now();
|
|
||||||
if (date == null) {
|
private Instant toValidInstant(Date date, boolean nullToNow) {
|
||||||
return nullToNow ? now : null;
|
Instant now = Instant.now();
|
||||||
}
|
if (date == null) {
|
||||||
|
return nullToNow ? now : null;
|
||||||
Instant instant = date.toInstant();
|
}
|
||||||
if (instant.isBefore(START) || instant.isAfter(END)) {
|
|
||||||
return now;
|
Instant instant = date.toInstant();
|
||||||
}
|
if (instant.isBefore(START) || instant.isAfter(END)) {
|
||||||
|
return now;
|
||||||
if (instant.isAfter(now)) {
|
}
|
||||||
return now;
|
|
||||||
}
|
if (instant.isAfter(now)) {
|
||||||
return instant;
|
return now;
|
||||||
}
|
}
|
||||||
|
return instant;
|
||||||
private String getContent(SyndEntry item) {
|
}
|
||||||
String content;
|
|
||||||
if (item.getContents().isEmpty()) {
|
private String getContent(SyndEntry item) {
|
||||||
content = item.getDescription() == null ? null : item.getDescription().getValue();
|
String content;
|
||||||
} else {
|
if (item.getContents().isEmpty()) {
|
||||||
content = item.getContents().stream().map(SyndContent::getValue).collect(Collectors.joining(System.lineSeparator()));
|
content = item.getDescription() == null ? null : item.getDescription().getValue();
|
||||||
}
|
} else {
|
||||||
return StringUtils.trimToNull(content);
|
content = item.getContents().stream().map(SyndContent::getValue).collect(Collectors.joining(System.lineSeparator()));
|
||||||
}
|
}
|
||||||
|
return StringUtils.trimToNull(content);
|
||||||
private String getTitle(SyndEntry item) {
|
}
|
||||||
String title = item.getTitle();
|
|
||||||
if (StringUtils.isBlank(title)) {
|
private String getTitle(SyndEntry item) {
|
||||||
Date date = item.getPublishedDate();
|
String title = item.getTitle();
|
||||||
if (date != null) {
|
if (StringUtils.isBlank(title)) {
|
||||||
title = DateFormat.getInstance().format(date);
|
Date date = item.getPublishedDate();
|
||||||
} else {
|
if (date != null) {
|
||||||
title = "(no title)";
|
title = DateFormat.getInstance().format(date);
|
||||||
}
|
} else {
|
||||||
}
|
title = "(no title)";
|
||||||
return StringUtils.trimToNull(title);
|
}
|
||||||
}
|
}
|
||||||
|
return StringUtils.trimToNull(title);
|
||||||
private Media buildMedia(SyndEntry item) {
|
}
|
||||||
MediaEntryModule module = (MediaEntryModule) item.getModule(MediaModule.URI);
|
|
||||||
if (module == null) {
|
private Media buildMedia(SyndEntry item) {
|
||||||
return null;
|
MediaEntryModule module = (MediaEntryModule) item.getModule(MediaModule.URI);
|
||||||
}
|
if (module == null) {
|
||||||
|
return null;
|
||||||
Media media = buildMedia(module.getMetadata());
|
}
|
||||||
if (media == null && ArrayUtils.isNotEmpty(module.getMediaGroups())) {
|
|
||||||
MediaGroup group = module.getMediaGroups()[0];
|
Media media = buildMedia(module.getMetadata());
|
||||||
media = buildMedia(group.getMetadata());
|
if (media == null && ArrayUtils.isNotEmpty(module.getMediaGroups())) {
|
||||||
}
|
MediaGroup group = module.getMediaGroups()[0];
|
||||||
|
media = buildMedia(group.getMetadata());
|
||||||
return media;
|
}
|
||||||
}
|
|
||||||
|
return media;
|
||||||
private Media buildMedia(Metadata metadata) {
|
}
|
||||||
if (metadata == null) {
|
|
||||||
return null;
|
private Media buildMedia(Metadata metadata) {
|
||||||
}
|
if (metadata == null) {
|
||||||
|
return null;
|
||||||
String description = metadata.getDescription();
|
}
|
||||||
|
|
||||||
String thumbnailUrl = null;
|
String description = metadata.getDescription();
|
||||||
Integer thumbnailWidth = null;
|
|
||||||
Integer thumbnailHeight = null;
|
String thumbnailUrl = null;
|
||||||
if (ArrayUtils.isNotEmpty(metadata.getThumbnail())) {
|
Integer thumbnailWidth = null;
|
||||||
Thumbnail thumbnail = metadata.getThumbnail()[0];
|
Integer thumbnailHeight = null;
|
||||||
thumbnailWidth = thumbnail.getWidth();
|
if (ArrayUtils.isNotEmpty(metadata.getThumbnail())) {
|
||||||
thumbnailHeight = thumbnail.getHeight();
|
Thumbnail thumbnail = metadata.getThumbnail()[0];
|
||||||
if (thumbnail.getUrl() != null) {
|
thumbnailWidth = thumbnail.getWidth();
|
||||||
thumbnailUrl = thumbnail.getUrl().toString();
|
thumbnailHeight = thumbnail.getHeight();
|
||||||
}
|
if (thumbnail.getUrl() != null) {
|
||||||
}
|
thumbnailUrl = thumbnail.getUrl().toString();
|
||||||
|
}
|
||||||
if (description == null && thumbnailUrl == null) {
|
}
|
||||||
return null;
|
|
||||||
}
|
if (description == null && thumbnailUrl == null) {
|
||||||
|
return null;
|
||||||
return new Media(description, thumbnailUrl, thumbnailWidth, thumbnailHeight);
|
}
|
||||||
}
|
|
||||||
|
return new Media(description, thumbnailUrl, thumbnailWidth, thumbnailHeight);
|
||||||
private Long averageTimeBetweenEntries(List<Entry> entries) {
|
}
|
||||||
if (entries.isEmpty() || entries.size() == 1) {
|
|
||||||
return null;
|
private Long averageTimeBetweenEntries(List<Entry> entries) {
|
||||||
}
|
if (entries.isEmpty() || entries.size() == 1) {
|
||||||
|
return null;
|
||||||
SummaryStatistics stats = new SummaryStatistics();
|
}
|
||||||
for (int i = 0; i < entries.size() - 1; i++) {
|
|
||||||
long diff = Math.abs(entries.get(i).published().toEpochMilli() - entries.get(i + 1).published().toEpochMilli());
|
SummaryStatistics stats = new SummaryStatistics();
|
||||||
stats.addValue(diff);
|
for (int i = 0; i < entries.size() - 1; i++) {
|
||||||
}
|
long diff = Math.abs(entries.get(i).published().toEpochMilli() - entries.get(i + 1).published().toEpochMilli());
|
||||||
return (long) stats.getMean();
|
stats.addValue(diff);
|
||||||
}
|
}
|
||||||
|
return (long) stats.getMean();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class FeedParsingException extends Exception {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public FeedParsingException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FeedParsingException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
package com.commafeed.backend.feed.parser;
|
package com.commafeed.backend.feed.parser;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public record FeedParserResult(String title, String link, Instant lastPublishedDate, Long averageEntryInterval, Instant lastEntryDate,
|
public record FeedParserResult(String title, String link, Instant lastPublishedDate, Long averageEntryInterval, Instant lastEntryDate,
|
||||||
List<Entry> entries) {
|
List<Entry> entries) {
|
||||||
public record Entry(String guid, String url, Instant published, Content content) {
|
public record Entry(String guid, String url, Instant published, Content content) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public record Content(String title, String content, String author, String categories, Enclosure enclosure, Media media) {
|
public record Content(String title, String content, String author, String categories, Enclosure enclosure, Media media) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public record Enclosure(String url, String type) {
|
public record Enclosure(String url, String type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public record Media(String description, String thumbnailUrl, Integer thumbnailWidth, Integer thumbnailHeight) {
|
public record Media(String description, String thumbnailUrl, Integer thumbnailWidth, Integer thumbnailHeight) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user