mirror of
https://github.com/Athou/commafeed.git
synced 2026-03-21 21:37:29 +00:00
Compare commits
730 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc76d7e609 | ||
|
|
1b24bf33ed | ||
|
|
58ff378735 | ||
|
|
1cee04a233 | ||
|
|
ac11a0efb8 | ||
|
|
f2ea1e3f7a | ||
|
|
153970c146 | ||
|
|
c21287e642 | ||
|
|
284942a82e | ||
|
|
e796916e73 | ||
|
|
004db1762c | ||
|
|
8e05ba8820 | ||
|
|
f4f386b5e5 | ||
|
|
ecbf8bec23 | ||
|
|
5d8c09ccda | ||
|
|
47c5c3d8a0 | ||
|
|
3ddce16d5b | ||
|
|
acefdc44d9 | ||
|
|
d05c5b9d7f | ||
|
|
5d1237d1f4 | ||
|
|
6bac8631ac | ||
|
|
2c803327ad | ||
|
|
451ae5bc51 | ||
|
|
f41ce8c878 | ||
|
|
177c54c813 | ||
|
|
3765e32fd4 | ||
|
|
aab7a16d18 | ||
|
|
f2463af63c | ||
|
|
212c2c3b56 | ||
|
|
3ab00b0cdd | ||
|
|
fad85e9299 | ||
|
|
3cd5e203e2 | ||
|
|
7b081fa870 | ||
|
|
5ce22051d4 | ||
|
|
1e59489fa5 | ||
|
|
1e691b1255 | ||
|
|
61e1bef63f | ||
|
|
46dbb78fbf | ||
|
|
99890707b3 | ||
|
|
f54c841fdc | ||
|
|
e2a6009ee9 | ||
|
|
a34dd15040 | ||
|
|
24c934003d | ||
|
|
5300e1a245 | ||
|
|
90381c670b | ||
|
|
23edea93db | ||
|
|
a51712e363 | ||
|
|
4310e979e1 | ||
|
|
f690b76d87 | ||
|
|
ac29594b67 | ||
|
|
93f535bb87 | ||
|
|
076eb3cf42 | ||
|
|
7b2e0fffbd | ||
|
|
8eaab0dbc3 | ||
|
|
eaa5bc896e | ||
|
|
42d1db5fc3 | ||
|
|
78c017ddaf | ||
|
|
231551d743 | ||
|
|
d0984eaba7 | ||
|
|
15854a72d1 | ||
|
|
7fd2bf0eda | ||
|
|
6a10a2167e | ||
|
|
1ba99d255c | ||
|
|
ff1c2947b6 | ||
|
|
a690d2e0db | ||
|
|
a3df327396 | ||
|
|
ede0016d8e | ||
|
|
c19b091795 | ||
|
|
9e62c8b9f3 | ||
|
|
9f30dc181c | ||
|
|
37fe44f860 | ||
|
|
68aaab8467 | ||
|
|
b951ed1fcd | ||
|
|
9bd9dc568a | ||
|
|
29e4356fee | ||
|
|
0ed31eaa99 | ||
|
|
1e9869b217 | ||
|
|
78cfc2c827 | ||
|
|
a6e5a0d125 | ||
|
|
ea13aecd27 | ||
|
|
d838e8f28f | ||
|
|
c9a7b9e17c | ||
|
|
8fe2d0bc0e | ||
|
|
71e2f1e1e6 | ||
|
|
1ce9d1b9b2 | ||
|
|
b3d6ae467f | ||
|
|
da8d720dc4 | ||
|
|
824c38f8ce | ||
|
|
b0579a70d8 | ||
|
|
f195eb6d0d | ||
|
|
f9fe2d0976 | ||
|
|
2aeadc8f67 | ||
|
|
ee3eaa1166 | ||
|
|
5dce143756 | ||
|
|
33a0568895 | ||
|
|
721d728906 | ||
|
|
c55cbaf373 | ||
|
|
3fd5cfdecd | ||
|
|
f87d3359c2 | ||
|
|
37f27849bd | ||
|
|
6fe326f052 | ||
|
|
de7e4e9c69 | ||
|
|
6861fe303b | ||
|
|
ba3214bf10 | ||
|
|
bcce77495a | ||
|
|
a165d2b27e | ||
|
|
e63714cab0 | ||
|
|
390c21dd91 | ||
|
|
9defea9c8e | ||
|
|
5906173de7 | ||
|
|
a81de48cfb | ||
|
|
2be61e8b1c | ||
|
|
4d7fc9f354 | ||
|
|
e11fd7b3a1 | ||
|
|
cc0348b113 | ||
|
|
77bb948bf2 | ||
|
|
8e2adcbce4 | ||
|
|
bb141203a8 | ||
|
|
579c22df65 | ||
|
|
694e8291de | ||
|
|
367259fd31 | ||
|
|
e54151d2eb | ||
|
|
ca2c687f26 | ||
|
|
d444a7080d | ||
|
|
08bfcded7f | ||
|
|
1c9e4f978b | ||
|
|
a5f1fba6ee | ||
|
|
88f1cf1913 | ||
|
|
1fb69d2861 | ||
|
|
3aeff66522 | ||
|
|
114cbe0ec5 | ||
|
|
bfe94222b7 | ||
|
|
30061abc54 | ||
|
|
126e07489b | ||
|
|
bd2577c089 | ||
|
|
5039c61e98 | ||
|
|
5f34ab3d7e | ||
|
|
fee47427cf | ||
|
|
15c8289a01 | ||
|
|
141a863079 | ||
|
|
6fa8d4be34 | ||
|
|
984e8a44d5 | ||
|
|
bdb296bce2 | ||
|
|
955a9084c3 | ||
|
|
70f486b0eb | ||
|
|
0bc383c6a8 | ||
|
|
0bb2b36585 | ||
|
|
9e3a24753a | ||
|
|
f2c400799e | ||
|
|
25a8c8a7e3 | ||
|
|
8f95d89fc6 | ||
|
|
39b0cdb9d5 | ||
|
|
42e06b848e | ||
|
|
7c3a13b1c4 | ||
|
|
151248fce2 | ||
|
|
6e8d6fe063 | ||
|
|
ca2da5e631 | ||
|
|
6cd3b70201 | ||
|
|
2dcfba75b5 | ||
|
|
44a51b03d3 | ||
|
|
6ee9e9831e | ||
|
|
68c717cee8 | ||
|
|
b15fc02c34 | ||
|
|
033ebfb497 | ||
|
|
4cceaa7650 | ||
|
|
5df47f1396 | ||
|
|
903f35c01b | ||
|
|
6a34f94277 | ||
|
|
dcc143eb7d | ||
|
|
fb47bf27e8 | ||
|
|
dcf969ff2e | ||
|
|
32c1318355 | ||
|
|
8ca6b89da4 | ||
|
|
b46c3a15f3 | ||
|
|
cbc5e014f7 | ||
|
|
8925b248e4 | ||
|
|
cc6aa2bbc5 | ||
|
|
1989aaf8b4 | ||
|
|
c90c91b748 | ||
|
|
bca23db213 | ||
|
|
c9a92d2043 | ||
|
|
c48e06fa46 | ||
|
|
5529eced91 | ||
|
|
2a0d935471 | ||
|
|
6c68fda572 | ||
|
|
861c1fc3dc | ||
|
|
5971bb4255 | ||
|
|
76ba360631 | ||
|
|
89d3ff3c90 | ||
|
|
34024a913d | ||
|
|
a858380121 | ||
|
|
e1dc870005 | ||
|
|
2fc1cac869 | ||
|
|
f627ff4958 | ||
|
|
5ff8e51948 | ||
|
|
538f25c6bb | ||
|
|
65100ba279 | ||
|
|
79fd470bbf | ||
|
|
866d74665b | ||
|
|
29da74f038 | ||
|
|
3c8ac35a46 | ||
|
|
afe957ba59 | ||
|
|
7e50e99351 | ||
|
|
62ce462cc8 | ||
|
|
108cb06f43 | ||
|
|
95a38675bc | ||
|
|
714681bc50 | ||
|
|
0f8d91d997 | ||
|
|
562297a82f | ||
|
|
b108bf06e5 | ||
|
|
3c819066fd | ||
|
|
5f30cb7e2e | ||
|
|
5a95b95801 | ||
|
|
eb573fdc8b | ||
|
|
238ea54e98 | ||
|
|
e4dfc47fb8 | ||
|
|
a1491c779a | ||
|
|
dabd7552be | ||
|
|
0a4c56af1f | ||
|
|
c3dae5b92c | ||
|
|
2c3105b526 | ||
|
|
20f5081ac8 | ||
|
|
3091eb9d14 | ||
|
|
5bdda42239 | ||
|
|
7eda8b7662 | ||
|
|
fc94ce5d2b | ||
|
|
e5d7161ab7 | ||
|
|
f725cb7fa4 | ||
|
|
830e689fe8 | ||
|
|
2832e8c638 | ||
|
|
d711cbab49 | ||
|
|
2e8fd737af | ||
|
|
a080ede15b | ||
|
|
ab3d41508f | ||
|
|
1ab4a5e925 | ||
|
|
543ce08be6 | ||
|
|
21829056ba | ||
|
|
1af59c87d0 | ||
|
|
799e6c082c | ||
|
|
09635cf0fd | ||
|
|
1dfbd30471 | ||
|
|
48e0a77d1f | ||
|
|
7ae8594c00 | ||
|
|
19663b0f38 | ||
|
|
4bcb9adb83 | ||
|
|
f7505298d7 | ||
|
|
df722ffa8b | ||
|
|
2a852fe08d | ||
|
|
540f796200 | ||
|
|
b726ac84fe | ||
|
|
61ac2bb6a3 | ||
|
|
5d702b3992 | ||
|
|
3bf4a004d4 | ||
|
|
7ac5876d2d | ||
|
|
0f18c612af | ||
|
|
03f4a3c478 | ||
|
|
7069343cf4 | ||
|
|
7fae79f2c5 | ||
|
|
66b714ed39 | ||
|
|
d371ebe354 | ||
|
|
9093d0d5e5 | ||
|
|
1139df0637 | ||
|
|
c1810de316 | ||
|
|
863ced57f8 | ||
|
|
2147aeb4ae | ||
|
|
a810b4fc9a | ||
|
|
abcbb61b4c | ||
|
|
83332223ef | ||
|
|
fd8d981ea0 | ||
|
|
03e3ade09d | ||
|
|
68305f2e00 | ||
|
|
b7d6b06242 | ||
|
|
9098050c5a | ||
|
|
0147ec0a6a | ||
|
|
c6b71605d0 | ||
|
|
64009c82e9 | ||
|
|
5b24cb370f | ||
|
|
2d261cd97b | ||
|
|
9455d91b3d | ||
|
|
cb645c56b4 | ||
|
|
1a6b91dee5 | ||
|
|
8d2edad488 | ||
|
|
522e26b1fa | ||
|
|
259b22c255 | ||
|
|
b61cf82b46 | ||
|
|
4f06f7424c | ||
|
|
d2d65437f8 | ||
|
|
3ae0f7558e | ||
|
|
604801686d | ||
|
|
554d4190ff | ||
|
|
1d71390349 | ||
|
|
fe24c6d682 | ||
|
|
4359d91a23 | ||
|
|
ae42eac7fd | ||
|
|
37a8888a32 | ||
|
|
2d7e065d39 | ||
|
|
35cf640691 | ||
|
|
b308fbe0ad | ||
|
|
d5e2b51b6d | ||
|
|
9b7844542d | ||
|
|
9f6fac0d58 | ||
|
|
f6011dc3f2 | ||
|
|
fdb7fa21f6 | ||
|
|
29bbe41e51 | ||
|
|
004ada8204 | ||
|
|
9a2894944c | ||
|
|
dfcff5029b | ||
|
|
853fc600dd | ||
|
|
a546b21755 | ||
|
|
e40c4e3779 | ||
|
|
60cbf6cff3 | ||
|
|
6d3f4b98d7 | ||
|
|
4812a2b401 | ||
|
|
5f99376d58 | ||
|
|
3e76c142c3 | ||
|
|
28f23a73af | ||
|
|
68b94fed8e | ||
|
|
657b02727c | ||
|
|
7d7a10073c | ||
|
|
9d5f0c791c | ||
|
|
212493e4ff | ||
|
|
9fc8e9c6d7 | ||
|
|
f69ddb71a0 | ||
|
|
290beec0c5 | ||
|
|
dcb2f6f8cd | ||
|
|
d200845906 | ||
|
|
a52e02695d | ||
|
|
febd7c3063 | ||
|
|
d5ae0b99f0 | ||
|
|
8b10c608fc | ||
|
|
0d49b91cc6 | ||
|
|
2af4b83e09 | ||
|
|
cde3ca3d9e | ||
|
|
429798190a | ||
|
|
583db4c70f | ||
|
|
3ec35eec91 | ||
|
|
65bfbfc7fd | ||
|
|
1b93701df2 | ||
|
|
d6debc55f5 | ||
|
|
87fd9ae686 | ||
|
|
3225a3b337 | ||
|
|
4eb98a6c31 | ||
|
|
38a6e2fc98 | ||
|
|
c171cf1487 | ||
|
|
b64a0f1d55 | ||
|
|
3ab124b2db | ||
|
|
d710f3995f | ||
|
|
f53c209082 | ||
|
|
9997be3462 | ||
|
|
c3b06e375c | ||
|
|
1476c5a932 | ||
|
|
8e1c9b9703 | ||
|
|
27c89f7cc7 | ||
|
|
9210198766 | ||
|
|
ce6fa0bf8f | ||
|
|
cd6629b424 | ||
|
|
f25a62ad71 | ||
|
|
cec3c872b6 | ||
|
|
e666e71281 | ||
|
|
3d0c303d41 | ||
|
|
d70a97cf77 | ||
|
|
c67c433258 | ||
|
|
0da6bd5ab6 | ||
|
|
e5cdb1580e | ||
|
|
2c10292073 | ||
|
|
30036a456e | ||
|
|
6349ae9e2b | ||
|
|
8d746669c3 | ||
|
|
0081abc9a7 | ||
|
|
a2f9ac05fe | ||
|
|
6c1f24bad7 | ||
|
|
77cd01e91f | ||
|
|
5487aac81d | ||
|
|
8a6257dc63 | ||
|
|
8146c69ebf | ||
|
|
78ece1abf2 | ||
|
|
baab35c4c5 | ||
|
|
357f9d46f9 | ||
|
|
4eb26302a7 | ||
|
|
a2071d9527 | ||
|
|
65c32c52ff | ||
|
|
fa4353f47d | ||
|
|
46fea1a3e5 | ||
|
|
497cf111d1 | ||
|
|
b1f2fd26e3 | ||
|
|
ae60d4a60f | ||
|
|
ae78e4691d | ||
|
|
9c058cf6d6 | ||
|
|
1ac9af23c5 | ||
|
|
f783bb660e | ||
|
|
e5c271ca1c | ||
|
|
f927247955 | ||
|
|
087e38bec8 | ||
|
|
bab3c8e6b0 | ||
|
|
54ac5d9e27 | ||
|
|
36519d9053 | ||
|
|
ccce4c622d | ||
|
|
4cbf677e55 | ||
|
|
1dbac44a93 | ||
|
|
7e1cfb5cd2 | ||
|
|
df9fb956fa | ||
|
|
16dc383f2b | ||
|
|
0dd7c4851b | ||
|
|
fce4e75eef | ||
|
|
16b578a76d | ||
|
|
483db9881e | ||
|
|
a4053c6084 | ||
|
|
e4f4b46047 | ||
|
|
36f77d5408 | ||
|
|
b3533771dc | ||
|
|
45372cba92 | ||
|
|
dd7fb5bb0d | ||
|
|
41bdc19a22 | ||
|
|
8b7f22021a | ||
|
|
f0160e4d2b | ||
|
|
39d727f98f | ||
|
|
13cc8ac70d | ||
|
|
eb2a219ec8 | ||
|
|
4a59565b20 | ||
|
|
4b7fa96308 | ||
|
|
1ebc8a1e7b | ||
|
|
df2a9aae20 | ||
|
|
dd8287c9d7 | ||
|
|
22fcb08dad | ||
|
|
8c2cf181bd | ||
|
|
69adae36b6 | ||
|
|
8ab700dfa9 | ||
|
|
0177529b45 | ||
|
|
4c6ae3364e | ||
|
|
6df8511a6d | ||
|
|
6fa39517f8 | ||
|
|
c69ce39424 | ||
|
|
a47f6736ac | ||
|
|
79bd7cfff3 | ||
|
|
bc02f23f0f | ||
|
|
715dffb6c8 | ||
|
|
702b3eb971 | ||
|
|
17f62bf491 | ||
|
|
28471302ee | ||
|
|
d8bfdd5d3b | ||
|
|
a36e68e9c3 | ||
|
|
343aed16fb | ||
|
|
142d873c8b | ||
|
|
a94b3e05d3 | ||
|
|
26a79d58f0 | ||
|
|
7c5e68e47d | ||
|
|
ba68627060 | ||
|
|
5bb6a7d4d4 | ||
|
|
76f7999046 | ||
|
|
547693df4f | ||
|
|
0206f8211a | ||
|
|
e061f2e259 | ||
|
|
560ccff04a | ||
|
|
2f0a84557b | ||
|
|
3ae7318ded | ||
|
|
6b7d66e833 | ||
|
|
ec8e594a5c | ||
|
|
858041772e | ||
|
|
b355c04d87 | ||
|
|
4918eaf752 | ||
|
|
80706f006d | ||
|
|
8a7fec1207 | ||
|
|
22a5b6e85e | ||
|
|
a51c533712 | ||
|
|
1f74674a11 | ||
|
|
2eada58ce5 | ||
|
|
31e74bd4a8 | ||
|
|
903f73ee78 | ||
|
|
b21198b239 | ||
|
|
e20ff09457 | ||
|
|
674393eabc | ||
|
|
d78a131713 | ||
|
|
e3816bf05b | ||
|
|
37fe1c60cc | ||
|
|
e705a0d32b | ||
|
|
eb658a644b | ||
|
|
cb905bfc8c | ||
|
|
d0accf6a84 | ||
|
|
55e6f89fc1 | ||
|
|
60695a0ffc | ||
|
|
8a8e4655cd | ||
|
|
2f4b390be1 | ||
|
|
31146cc713 | ||
|
|
9e020ff268 | ||
|
|
7e825192d0 | ||
|
|
8871ae894f | ||
|
|
2808f4b1a2 | ||
|
|
0324c22061 | ||
|
|
57227f9544 | ||
|
|
59c5131f1a | ||
|
|
ccbc07d7d8 | ||
|
|
a0247f0036 | ||
|
|
0979c2767b | ||
|
|
9a9613bba3 | ||
|
|
6451f5f3b7 | ||
|
|
4a4430ce9b | ||
|
|
a38d3dcf72 | ||
|
|
60e1e0d037 | ||
|
|
8071b85b3d | ||
|
|
c867bfb846 | ||
|
|
24b32ab69b | ||
|
|
b1fc65262f | ||
|
|
5af3fea74c | ||
|
|
dde38985e4 | ||
|
|
3f0084fa1c | ||
|
|
8936d4fdce | ||
|
|
4c47b7d838 | ||
|
|
093a9cb8e4 | ||
|
|
f27b3f8933 | ||
|
|
74a9e48e55 | ||
|
|
bafef26ffc | ||
|
|
f8e66170bf | ||
|
|
00bf99fe5a | ||
|
|
05dd66177f | ||
|
|
d5a9e6401e | ||
|
|
660ba67433 | ||
|
|
7ad948065b | ||
|
|
40fcb85c93 | ||
|
|
dcddb80f7b | ||
|
|
8e349aea19 | ||
|
|
3d72725ae0 | ||
|
|
270cb340f5 | ||
|
|
42b5462889 | ||
|
|
b98ab8d011 | ||
|
|
b4264a8ba3 | ||
|
|
a395246d1e | ||
|
|
4b7a2afd07 | ||
|
|
7f49ff20cf | ||
|
|
4e9995e610 | ||
|
|
9f61442cec | ||
|
|
9339847d09 | ||
|
|
39e57cb3ef | ||
|
|
f3a574d05c | ||
|
|
297c76006a | ||
|
|
62d025d827 | ||
|
|
999799ea68 | ||
|
|
331f68253e | ||
|
|
70d3c7a4be | ||
|
|
b3c75a0286 | ||
|
|
9946120304 | ||
|
|
7030a67389 | ||
|
|
eda5ef6965 | ||
|
|
0324479fda | ||
|
|
aeafecb88d | ||
|
|
fde7fbe21a | ||
|
|
7116efc490 | ||
|
|
1ac6058200 | ||
|
|
32b80b64f4 | ||
|
|
9e348767dc | ||
|
|
bce72e1152 | ||
|
|
64aba75be2 | ||
|
|
ca65e13f9a | ||
|
|
54797607c6 | ||
|
|
e174254a95 | ||
|
|
4378e24b49 | ||
|
|
35d276ea98 | ||
|
|
678c89d9c0 | ||
|
|
0a42223de0 | ||
|
|
54d3f3b007 | ||
|
|
3ee58ee464 | ||
|
|
3b5ff016fe | ||
|
|
8a8e786f5e | ||
|
|
2a15f68ffb | ||
|
|
9387e014c1 | ||
|
|
1ef37fcaff | ||
|
|
c5906a481f | ||
|
|
ac0bc916a1 | ||
|
|
5bbe76d56e | ||
|
|
1e6195d74c | ||
|
|
85acea7e64 | ||
|
|
0e4ff99602 | ||
|
|
575d2a0940 | ||
|
|
c548462eef | ||
|
|
3b4cc66b24 | ||
|
|
6d7273f822 | ||
|
|
65014d330a | ||
|
|
d9e3cf0190 | ||
|
|
2d8ee54d28 | ||
|
|
98c3bb780d | ||
|
|
7247c10615 | ||
|
|
0787284d80 | ||
|
|
1c73bffc95 | ||
|
|
6f79815933 | ||
|
|
bb108d594a | ||
|
|
f7716c8834 | ||
|
|
5ba076b1dd | ||
|
|
7861b5a414 | ||
|
|
f36a5988d8 | ||
|
|
8b57240db3 | ||
|
|
7b52efd2d1 | ||
|
|
4901b838e2 | ||
|
|
2313a60f32 | ||
|
|
c38e958588 | ||
|
|
43b1e14f41 | ||
|
|
1e23b3c355 | ||
|
|
85e1556148 | ||
|
|
b65f333a89 | ||
|
|
3dbcbb8280 | ||
|
|
06e464854a | ||
|
|
f7a944a78a | ||
|
|
7f53531489 | ||
|
|
8386c2889f | ||
|
|
13d2332984 | ||
|
|
ce496c205a | ||
|
|
66547661b5 | ||
|
|
8568a29461 | ||
|
|
5d42229aec | ||
|
|
ad8c928cf1 | ||
|
|
cc90883342 | ||
|
|
a4071da5de | ||
|
|
c65dbf978b | ||
|
|
c4ea804fee | ||
|
|
f71720c809 | ||
|
|
03ba601491 | ||
|
|
bdee3fc1b5 | ||
|
|
2e472fa90d | ||
|
|
aad7e896f2 | ||
|
|
2478fc2967 | ||
|
|
2db96c968d | ||
|
|
9bc1a69ace | ||
|
|
cca74e9e54 | ||
|
|
8185411071 | ||
|
|
c89addab2e | ||
|
|
6c617bf9e7 | ||
|
|
5847e340bf | ||
|
|
5a5fd8f425 | ||
|
|
d6283e326d | ||
|
|
c63deb70dd | ||
|
|
c071781099 | ||
|
|
0820b4b70a | ||
|
|
ac42d11251 | ||
|
|
324248ff1e | ||
|
|
f32e83d43b | ||
|
|
3820aaed21 | ||
|
|
a45ef79c6f | ||
|
|
9b9266a6c9 | ||
|
|
06e22030c3 | ||
|
|
ca146c977b | ||
|
|
6a96a3617f | ||
|
|
6dd6e05e0c | ||
|
|
1fb33d51d3 | ||
|
|
4841f2d7f6 | ||
|
|
ad388ae056 | ||
|
|
a80769fae3 | ||
|
|
b34c6f4c34 | ||
|
|
d6d084fbd1 | ||
|
|
1fca44c0da | ||
|
|
8bf1d0b776 | ||
|
|
484412514f | ||
|
|
6987449a7e | ||
|
|
18dac92fc1 | ||
|
|
54774fcfe5 | ||
|
|
b431229273 | ||
|
|
658dde158e | ||
|
|
ced3ada6fc | ||
|
|
0db236639b | ||
|
|
036ce7f94f | ||
|
|
68c887ffe0 | ||
|
|
e96da49d0a | ||
|
|
794684bc4e | ||
|
|
dd944c5293 | ||
|
|
be878454a9 | ||
|
|
e567f81046 | ||
|
|
6164ca5f91 | ||
|
|
655332e3fd | ||
|
|
7e300fea87 | ||
|
|
cea3e0aba8 | ||
|
|
459e270561 | ||
|
|
cba660e785 | ||
|
|
758301a39d | ||
|
|
a8d0bae16e | ||
|
|
583cc39849 | ||
|
|
3585bd3d2d | ||
|
|
3a895b6418 | ||
|
|
bb67733723 | ||
|
|
f380fd553f | ||
|
|
d22ef12adf | ||
|
|
eaec088348 | ||
|
|
fa1d0b9151 | ||
|
|
c0a418b8b1 | ||
|
|
1a4f633a28 | ||
|
|
c92ae40db6 | ||
|
|
0b42bea600 | ||
|
|
d8565cb3d3 | ||
|
|
f68798c10e | ||
|
|
a2ab927433 | ||
|
|
c7eae71c56 | ||
|
|
c3784c2606 | ||
|
|
60fe263b53 | ||
|
|
aaa0cfd0c8 | ||
|
|
a209b2774a | ||
|
|
84d67b6166 | ||
|
|
a7a215e6c7 | ||
|
|
8686fe4e97 | ||
|
|
afe2e8f95b | ||
|
|
f580226c27 | ||
|
|
e93db46e0a | ||
|
|
daea4b7f84 | ||
|
|
eb942b07b1 | ||
|
|
804ca38db7 | ||
|
|
7278c0beae | ||
|
|
096e3a0f5f | ||
|
|
5090c15f20 | ||
|
|
cb7e74fc21 | ||
|
|
ff90041ed4 | ||
|
|
f8fbe1844a | ||
|
|
1902172a04 | ||
|
|
2df384b847 | ||
|
|
65bb35b4de | ||
|
|
97516100f5 | ||
|
|
009ec7a59b | ||
|
|
02890c2b69 | ||
|
|
0f690bf00e | ||
|
|
cfe427b34c | ||
|
|
a44c76cdc3 | ||
|
|
730bde3d0d | ||
|
|
aa006fe22a | ||
|
|
ca77090ecd | ||
|
|
5619d1a4c5 | ||
|
|
b7c80c397d | ||
|
|
d1e7cd2f85 | ||
|
|
7da7aeb796 | ||
|
|
26b46166aa | ||
|
|
6d5eb51a5d | ||
|
|
917b6b318f | ||
|
|
bfd95687b8 | ||
|
|
4198ee1af1 | ||
|
|
e9b1280ae6 | ||
|
|
3c42831db0 | ||
|
|
b8482006b9 |
1
.github/stale.yml
vendored
1
.github/stale.yml
vendored
@@ -7,6 +7,7 @@ exemptLabels:
|
|||||||
- pinned
|
- pinned
|
||||||
- security
|
- security
|
||||||
- enhancement
|
- enhancement
|
||||||
|
- feature-request
|
||||||
- bug
|
- bug
|
||||||
# Label to use when marking an issue as stale
|
# Label to use when marking an issue as stale
|
||||||
staleLabel: wontfix
|
staleLabel: wontfix
|
||||||
|
|||||||
50
.github/workflows/ci.yml
vendored
50
.github/workflows/ci.yml
vendored
@@ -7,7 +7,7 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
JAVA_VERSION: 21
|
JAVA_VERSION: 25
|
||||||
DOCKER_BUILD_SUMMARY: false
|
DOCKER_BUILD_SUMMARY: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -23,13 +23,13 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
# Checkout
|
# Checkout
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
# Setup
|
# Setup
|
||||||
- name: Set up GraalVM
|
- name: Set up GraalVM
|
||||||
uses: graalvm/setup-graalvm@7f488cf82a3629ee755e4e97342c01d6bed318fa # v1
|
uses: graalvm/setup-graalvm@03e8abf916fd0e281b2efe7b2da3378bb0a1d085 # v1
|
||||||
with:
|
with:
|
||||||
java-version: ${{ env.JAVA_VERSION }}
|
java-version: ${{ env.JAVA_VERSION }}
|
||||||
distribution: "graalvm"
|
distribution: "graalvm"
|
||||||
@@ -48,39 +48,39 @@ jobs:
|
|||||||
run: mkdir -p target/pages/documentation/custom-css
|
run: mkdir -p target/pages/documentation/custom-css
|
||||||
|
|
||||||
- name: Convert readme file to html
|
- name: Convert readme file to html
|
||||||
uses: jaywcjlove/markdown-to-html-cli@d2c8ffd676de1801e2586904bc540a938e4bc480 # v5.0.3
|
uses: jaywcjlove/markdown-to-html-cli@cff9330af4ca8048b197a76d9eb1db189c2a7cee # v5.0.4
|
||||||
with:
|
with:
|
||||||
source: README.md
|
source: README.md
|
||||||
output: target/pages/index.html
|
output: target/pages/index.html
|
||||||
|
|
||||||
- name: Convert config documentation to html
|
- name: Convert config documentation to html
|
||||||
uses: jaywcjlove/markdown-to-html-cli@d2c8ffd676de1801e2586904bc540a938e4bc480 # v5.0.3
|
uses: jaywcjlove/markdown-to-html-cli@cff9330af4ca8048b197a76d9eb1db189c2a7cee # v5.0.4
|
||||||
with:
|
with:
|
||||||
source: commafeed-server/target/quarkus-generated-doc/config/commafeed-server.md
|
source: commafeed-server/target/quarkus-generated-doc/config/commafeed-server.md
|
||||||
output: target/pages/documentation/index.html
|
output: target/pages/documentation/index.html
|
||||||
|
|
||||||
- name: Convert custom css documentation to html
|
- name: Convert custom css documentation to html
|
||||||
uses: jaywcjlove/markdown-to-html-cli@d2c8ffd676de1801e2586904bc540a938e4bc480 # v5.0.3
|
uses: jaywcjlove/markdown-to-html-cli@cff9330af4ca8048b197a76d9eb1db189c2a7cee # v5.0.4
|
||||||
with:
|
with:
|
||||||
source: documentation/CUSTOMCSS.md
|
source: documentation/CUSTOMCSS.md
|
||||||
output: target/pages/documentation/custom-css/index.html
|
output: target/pages/documentation/custom-css/index.html
|
||||||
|
|
||||||
# Upload artifacts
|
# Upload artifacts
|
||||||
- name: Upload cross-platform app
|
- name: Upload cross-platform app
|
||||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
|
||||||
if: matrix.os == 'ubuntu-latest' # we only need to upload the cross-platform artifact once per database
|
if: matrix.os == 'ubuntu-latest' # we only need to upload the cross-platform artifact once per database
|
||||||
with:
|
with:
|
||||||
name: commafeed-${{ matrix.database }}-jvm
|
name: commafeed-${{ matrix.database }}-jvm
|
||||||
path: commafeed-server/target/commafeed-*.zip
|
path: commafeed-server/target/commafeed-*.zip
|
||||||
|
|
||||||
- name: Upload native executable
|
- name: Upload native executable
|
||||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
|
||||||
with:
|
with:
|
||||||
name: commafeed-${{ matrix.database }}-${{ runner.os }}-${{ runner.arch }}
|
name: commafeed-${{ matrix.database }}-${{ runner.os }}-${{ runner.arch }}
|
||||||
path: commafeed-server/target/commafeed-*-runner*
|
path: commafeed-server/target/commafeed-*-runner*
|
||||||
|
|
||||||
- name: Upload pages
|
- name: Upload pages
|
||||||
uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3
|
uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4
|
||||||
if: matrix.os == 'ubuntu-latest' && matrix.database == 'h2' # we only need to upload the pages once
|
if: matrix.os == 'ubuntu-latest' && matrix.database == 'h2' # we only need to upload the pages once
|
||||||
with:
|
with:
|
||||||
path: target/pages
|
path: target/pages
|
||||||
@@ -98,23 +98,23 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
# Checkout
|
# Checkout
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
# Setup
|
# Setup
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3
|
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3
|
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
|
||||||
|
|
||||||
- name: Install required packages
|
- name: Install required packages
|
||||||
run: sudo apt-get install -y rename unzip
|
run: sudo apt-get install -y rename unzip
|
||||||
|
|
||||||
# Prepare artifacts
|
# Prepare artifacts
|
||||||
- name: Download artifacts
|
- name: Download artifacts
|
||||||
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||||
with:
|
with:
|
||||||
pattern: commafeed-${{ matrix.database }}-*
|
pattern: commafeed-${{ matrix.database }}-*
|
||||||
path: ./artifacts
|
path: ./artifacts
|
||||||
@@ -135,7 +135,7 @@ jobs:
|
|||||||
|
|
||||||
# Docker
|
# Docker
|
||||||
- name: Login to Container Registry
|
- name: Login to Container Registry
|
||||||
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3
|
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4
|
||||||
if: ${{ env.DOCKERHUB_USERNAME != '' }}
|
if: ${{ env.DOCKERHUB_USERNAME != '' }}
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
@@ -143,7 +143,7 @@ jobs:
|
|||||||
|
|
||||||
## build but don't push for PRs and renovate
|
## build but don't push for PRs and renovate
|
||||||
- name: Docker build - native
|
- name: Docker build - native
|
||||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
|
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: commafeed-server/src/main/docker/Dockerfile.native
|
file: commafeed-server/src/main/docker/Dockerfile.native
|
||||||
@@ -151,7 +151,7 @@ jobs:
|
|||||||
platforms: linux/amd64,linux/arm64/v8
|
platforms: linux/amd64,linux/arm64/v8
|
||||||
|
|
||||||
- name: Docker build - jvm
|
- name: Docker build - jvm
|
||||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
|
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: commafeed-server/src/main/docker/Dockerfile.jvm
|
file: commafeed-server/src/main/docker/Dockerfile.jvm
|
||||||
@@ -160,7 +160,7 @@ jobs:
|
|||||||
|
|
||||||
## build and push tag
|
## build and push tag
|
||||||
- name: Docker build and push tag - native
|
- name: Docker build and push tag - native
|
||||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
|
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7
|
||||||
if: ${{ github.ref_type == 'tag' }}
|
if: ${{ github.ref_type == 'tag' }}
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
@@ -172,7 +172,7 @@ jobs:
|
|||||||
athou/commafeed:${{ github.ref_name }}-${{ matrix.database }}
|
athou/commafeed:${{ github.ref_name }}-${{ matrix.database }}
|
||||||
|
|
||||||
- name: Docker build and push tag - jvm
|
- name: Docker build and push tag - jvm
|
||||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
|
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7
|
||||||
if: ${{ github.ref_type == 'tag' }}
|
if: ${{ github.ref_type == 'tag' }}
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
@@ -185,7 +185,7 @@ jobs:
|
|||||||
|
|
||||||
## build and push master
|
## build and push master
|
||||||
- name: Docker build and push master - native
|
- name: Docker build and push master - native
|
||||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
|
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7
|
||||||
if: ${{ github.ref_name == 'master' }}
|
if: ${{ github.ref_name == 'master' }}
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
@@ -195,7 +195,7 @@ jobs:
|
|||||||
tags: athou/commafeed:master-${{ matrix.database }}
|
tags: athou/commafeed:master-${{ matrix.database }}
|
||||||
|
|
||||||
- name: Docker build and push master - jvm
|
- name: Docker build and push master - jvm
|
||||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
|
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7
|
||||||
if: ${{ github.ref_name == 'master' }}
|
if: ${{ github.ref_name == 'master' }}
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
@@ -215,12 +215,12 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Download artifacts
|
- name: Download artifacts
|
||||||
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||||
with:
|
with:
|
||||||
pattern: commafeed-*
|
pattern: commafeed-*
|
||||||
path: ./artifacts
|
path: ./artifacts
|
||||||
@@ -236,7 +236,7 @@ jobs:
|
|||||||
version: ${{ github.ref_name }}
|
version: ${{ github.ref_name }}
|
||||||
|
|
||||||
- name: Create GitHub release
|
- name: Create GitHub release
|
||||||
uses: ncipollo/release-action@bcfe5470707e8832e12347755757cec0eb3c22af # v1
|
uses: ncipollo/release-action@339a81892b84b4eeb0f6e744e4574d79d0d9b8dd # v1
|
||||||
with:
|
with:
|
||||||
name: CommaFeed ${{ github.ref_name }}
|
name: CommaFeed ${{ github.ref_name }}
|
||||||
body: ${{ steps.changelog_reader.outputs.changes }}
|
body: ${{ steps.changelog_reader.outputs.changes }}
|
||||||
@@ -249,12 +249,12 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Update Docker Hub Description
|
- name: Update Docker Hub Description
|
||||||
uses: peter-evans/dockerhub-description@432a30c9e07499fd01da9f8a49f0faf9e0ca5b77 # v4
|
uses: peter-evans/dockerhub-description@1b9a80c056b620d92cedb9d9b5a223409c68ddfa # v5
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|||||||
78
.github/workflows/scorecard.yml
vendored
78
.github/workflows/scorecard.yml
vendored
@@ -1,78 +0,0 @@
|
|||||||
# This workflow uses actions that are not certified by GitHub. They are provided
|
|
||||||
# by a third-party and are governed by separate terms of service, privacy
|
|
||||||
# policy, and support documentation.
|
|
||||||
|
|
||||||
name: Scorecard supply-chain security
|
|
||||||
on:
|
|
||||||
# For Branch-Protection check. Only the default branch is supported. See
|
|
||||||
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
|
|
||||||
branch_protection_rule:
|
|
||||||
# To guarantee Maintained check is occasionally updated. See
|
|
||||||
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
|
|
||||||
schedule:
|
|
||||||
- cron: '42 13 * * 4'
|
|
||||||
push:
|
|
||||||
branches: [ "master" ]
|
|
||||||
|
|
||||||
# Declare default permissions as read only.
|
|
||||||
permissions: read-all
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
analysis:
|
|
||||||
name: Scorecard analysis
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
# `publish_results: true` only works when run from the default branch. conditional can be removed if disabled.
|
|
||||||
if: github.event.repository.default_branch == github.ref_name || github.event_name == 'pull_request'
|
|
||||||
permissions:
|
|
||||||
# Needed to upload the results to code-scanning dashboard.
|
|
||||||
security-events: write
|
|
||||||
# Needed to publish results and get a badge (see publish_results below).
|
|
||||||
id-token: write
|
|
||||||
# Uncomment the permissions below if installing in a private repository.
|
|
||||||
# contents: read
|
|
||||||
# actions: read
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: "Checkout code"
|
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
|
|
||||||
- name: "Run analysis"
|
|
||||||
uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2
|
|
||||||
with:
|
|
||||||
results_file: results.sarif
|
|
||||||
results_format: sarif
|
|
||||||
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
|
|
||||||
# - you want to enable the Branch-Protection check on a *public* repository, or
|
|
||||||
# - you are installing Scorecard on a *private* repository
|
|
||||||
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action?tab=readme-ov-file#authentication-with-fine-grained-pat-optional.
|
|
||||||
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
|
|
||||||
|
|
||||||
# Public repositories:
|
|
||||||
# - Publish results to OpenSSF REST API for easy access by consumers
|
|
||||||
# - Allows the repository to include the Scorecard badge.
|
|
||||||
# - See https://github.com/ossf/scorecard-action#publishing-results.
|
|
||||||
# For private repositories:
|
|
||||||
# - `publish_results` will always be set to `false`, regardless
|
|
||||||
# of the value entered here.
|
|
||||||
publish_results: true
|
|
||||||
|
|
||||||
# (Optional) Uncomment file_mode if you have a .gitattributes with files marked export-ignore
|
|
||||||
# file_mode: git
|
|
||||||
|
|
||||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
|
||||||
# format to the repository Actions tab.
|
|
||||||
- name: "Upload artifact"
|
|
||||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
|
||||||
with:
|
|
||||||
name: SARIF file
|
|
||||||
path: results.sarif
|
|
||||||
retention-days: 5
|
|
||||||
|
|
||||||
# Upload the results to GitHub's code scanning dashboard (optional).
|
|
||||||
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
|
|
||||||
- name: "Upload to code-scanning"
|
|
||||||
uses: github/codeql-action/upload-sarif@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3
|
|
||||||
with:
|
|
||||||
sarif_file: results.sarif
|
|
||||||
41
.github/workflows/sonar.yml
vendored
41
.github/workflows/sonar.yml
vendored
@@ -1,41 +0,0 @@
|
|||||||
name: SonarQube
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
pull_request:
|
|
||||||
types: [ opened, synchronize, reopened ]
|
|
||||||
|
|
||||||
env:
|
|
||||||
JAVA_VERSION: 21
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
# Checkout
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
# Setup
|
|
||||||
- name: Set up JDK
|
|
||||||
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4
|
|
||||||
with:
|
|
||||||
java-version: ${{ env.JAVA_VERSION }}
|
|
||||||
distribution: "temurin"
|
|
||||||
cache: "maven"
|
|
||||||
|
|
||||||
- name: Install Playwright dependencies
|
|
||||||
run: sudo apt-get install -y libgbm1
|
|
||||||
|
|
||||||
# Run test coverage and SonarQube analysis
|
|
||||||
- name: Analyze with SonarQube
|
|
||||||
env:
|
|
||||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
|
||||||
run: mvn --batch-mode verify sonar:sonar -Dsonar.projectKey=Athou_commafeed
|
|
||||||
19
.mvn/wrapper/maven-wrapper.properties
vendored
19
.mvn/wrapper/maven-wrapper.properties
vendored
@@ -1,18 +1,3 @@
|
|||||||
# Licensed to the Apache Software Foundation (ASF) under one
|
wrapperVersion=3.3.4
|
||||||
# or more contributor license agreements. See the NOTICE file
|
|
||||||
# distributed with this work for additional information
|
|
||||||
# regarding copyright ownership. The ASF licenses this file
|
|
||||||
# to you under the Apache License, Version 2.0 (the
|
|
||||||
# "License"); you may not use this file except in compliance
|
|
||||||
# with the License. You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing,
|
|
||||||
# software distributed under the License is distributed on an
|
|
||||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
# KIND, either express or implied. See the License for the
|
|
||||||
# specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
distributionType=only-script
|
distributionType=only-script
|
||||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip
|
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.14/apache-maven-3.9.14-bin.zip
|
||||||
|
|||||||
50
CHANGELOG.md
50
CHANGELOG.md
@@ -1,5 +1,55 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [7.0.0]
|
||||||
|
|
||||||
|
- Replaced the JEXL filter expression for marking feed entries as read automatically with a user-friendly visual query builder. Expressions are now evaluated with Common Expression Language, which is safer than JEXL and sanboxed by default.
|
||||||
|
- Added a per-feed setting for sending push notifications to ntfy, Gotify or Pushover when new feed entries are discovered (#1610)
|
||||||
|
- Added a per-feed setting for marking entries as read after a number of days (#2041)
|
||||||
|
- The default value of `commafeed.http-client.block-local-addresses` is now false, allowing users to subscribe to feeds only available on their local network. This may be a security risk (SSRF) if your instance is accessible by untrusted users, so you may want to set it to true if you host a public instance of CommaFeed with user registeration enabled.
|
||||||
|
- When `commafeed.http-client.block-local-addresses` is enabled, SSRF is now also mitigated by blocking public websites redirecting to local ones.
|
||||||
|
|
||||||
|
## [6.2.0]
|
||||||
|
|
||||||
|
- Starred entries are no longer deleted after a certain amount of time, they are now kept indefinitely. The new `commafeed.database.cleanup.keep-starred-entries` setting can be disabled to restore the previous behavior if you want to keep deleting starred entries during normal entries cleanup (#1581)
|
||||||
|
|
||||||
|
## [6.1.1]
|
||||||
|
|
||||||
|
- Fix old starred entries not loading if they were marked as read (#2031)
|
||||||
|
|
||||||
|
## [6.1.0]
|
||||||
|
|
||||||
|
- When clicking on the password reset link, a random password is no longer generated automatically. The user is now redirected to a page where they can set their own password (#2023)
|
||||||
|
- Use browser preferred language instead of English when using CommaFeed for the first time (#2018)
|
||||||
|
- The profile menu is now closed when scrolling the page (#2019)
|
||||||
|
- The "disable pull to refresh" feature is now disabled by default (#2030)
|
||||||
|
|
||||||
|
## [6.0.0]
|
||||||
|
|
||||||
|
- When booting CommaFeed for the first time, the default "admin" account is no longer created automatically. A setup wizard will guide you through the creation of an admin account
|
||||||
|
- Default password complexity requirements have been lowered for local network deployments, where strict password rules are often unnecessary. The `commafeed.users.strict-password-policy` setting has been replaced by `commafeed.users.minimum-password-length` with a default value of `4` (#1916)
|
||||||
|
- Email addresses are no longer required when creating users and when they update their profile. The `commafeed.users.email-address-required` setting has been added to restore the previous behavior (#1914)
|
||||||
|
- Java 25+ is now required to build and run CommaFeed
|
||||||
|
|
||||||
|
## [5.12.1]
|
||||||
|
|
||||||
|
- The favicon is now crispier (#1978)
|
||||||
|
- The ReadKit iOS app now works via the Fever API (#1602)
|
||||||
|
|
||||||
|
## [5.12.0]
|
||||||
|
|
||||||
|
- Added a setting to disable the "disable pull to refresh" feature because it messes with some browsers (#1168)
|
||||||
|
- Emojis in feeds are now correctly displayed (#1955)
|
||||||
|
- Don't show "Star/Unstar" in the context menu if the entry is too old to be starred (#1935)
|
||||||
|
- Invalid relative urls in feeds no longer prevent those feeds from being parsed (#1939)
|
||||||
|
- Fix an issue that could prevent large feeds from being parsed when using Java 24+ (#1961)
|
||||||
|
- Enforce user password validation when created in the admin view (#1937)
|
||||||
|
- The process in the docker native image is now called "commafeed" instead of "application"
|
||||||
|
|
||||||
|
## [5.11.1]
|
||||||
|
|
||||||
|
- The search limit of 3 characters has been removed (#1887)
|
||||||
|
- Fix an issue that caused feed filtering expressions to be incorrectly converted to lowercase when saving them (#1899)
|
||||||
|
|
||||||
## [5.11.0]
|
## [5.11.0]
|
||||||
|
|
||||||
- Add an option to navigate to the next unread category/feed when marking all entries as read (#1807)
|
- Add an option to navigate to the next unread category/feed when marking all entries as read (#1807)
|
||||||
|
|||||||
15
README.md
15
README.md
@@ -17,6 +17,7 @@ Google Reader inspired self-hosted RSS reader, based on Quarkus and React/TypeSc
|
|||||||
- REST API
|
- REST API
|
||||||
- Fever-compatible API for native mobile apps
|
- Fever-compatible API for native mobile apps
|
||||||
- Can automatically mark articles as read based on user-defined rules
|
- Can automatically mark articles as read based on user-defined rules
|
||||||
|
- Push notifications when new articles are published
|
||||||
- Highly customizable with [custom CSS](https://athou.github.io/commafeed/documentation/custom-css) and JavaScript
|
- Highly customizable with [custom CSS](https://athou.github.io/commafeed/documentation/custom-css) and JavaScript
|
||||||
- [Browser extension](https://github.com/Athou/commafeed-browser-extension)
|
- [Browser extension](https://github.com/Athou/commafeed-browser-extension)
|
||||||
- Compiles to native code for blazing fast startup and low memory usage
|
- Compiles to native code for blazing fast startup and low memory usage
|
||||||
@@ -26,11 +27,18 @@ Google Reader inspired self-hosted RSS reader, based on Quarkus and React/TypeSc
|
|||||||
- MySQL
|
- MySQL
|
||||||
- MariaDB
|
- MariaDB
|
||||||
|
|
||||||
## Deployment
|
## Usage
|
||||||
|
|
||||||
|
### Public instance
|
||||||
|
|
||||||
|
A free public instance is available at https://www.commafeed.com.
|
||||||
|
|
||||||
|
It has no ads, no tracking, and your data is never exploited or sold to third parties. The service is funded entirely through donations.
|
||||||
|
However, this public instance does have a few limitations compared to self-hosted setups, outlined [here](https://github.com/Athou/commafeed/discussions/1567).
|
||||||
|
|
||||||
### Docker
|
### Docker
|
||||||
|
|
||||||
Docker is the easiest way to get started with CommaFeed.
|
Docker is the easiest way to get started with self-hosted CommaFeed.
|
||||||
|
|
||||||
Docker images are built automatically and are available at https://hub.docker.com/r/athou/commafeed
|
Docker images are built automatically and are available at https://hub.docker.com/r/athou/commafeed
|
||||||
|
|
||||||
@@ -103,7 +111,7 @@ There are multiple ways to configure CommaFeed:
|
|||||||
- Environment variables (keys in UPPER_CASE)
|
- Environment variables (keys in UPPER_CASE)
|
||||||
- a `.env` file in the working directory (keys in UPPER_CASE)
|
- a `.env` file in the working directory (keys in UPPER_CASE)
|
||||||
|
|
||||||
The properties file is recommended because CommaFeed will be able to warn about invalid properties and typos.
|
When in doubt, the properties file is recommended because CommaFeed will be able to warn about invalid properties and typos.
|
||||||
|
|
||||||
All [CommaFeed settings](https://athou.github.io/commafeed/documentation) are optional and have sensible default values.
|
All [CommaFeed settings](https://athou.github.io/commafeed/documentation) are optional and have sensible default values.
|
||||||
|
|
||||||
@@ -113,7 +121,6 @@ meaning that you will have to log back in after each restart of the application.
|
|||||||
All other Quarkus settings can be found [here](https://quarkus.io/guides/all-config).
|
All other Quarkus settings can be found [here](https://quarkus.io/guides/all-config).
|
||||||
|
|
||||||
When started, the server will listen on http://localhost:8082.
|
When started, the server will listen on http://localhost:8082.
|
||||||
The default user is `admin` and the default password is `admin`.
|
|
||||||
|
|
||||||
### Updates
|
### Updates
|
||||||
|
|
||||||
|
|||||||
3
commafeed-client/.gitignore
vendored
3
commafeed-client/.gitignore
vendored
@@ -23,9 +23,6 @@ dist-ssr
|
|||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
# rollup-plugin-visualizer
|
|
||||||
/stats.html
|
|
||||||
|
|
||||||
# vite
|
# vite
|
||||||
vite.config.ts.timestamp-*.mjs
|
vite.config.ts.timestamp-*.mjs
|
||||||
|
|
||||||
|
|||||||
1
commafeed-client/.husky/pre-commit
Normal file
1
commafeed-client/.husky/pre-commit
Normal file
@@ -0,0 +1 @@
|
|||||||
|
cd commafeed-client && npx lint-staged
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://biomejs.dev/schemas/2.1.3/schema.json",
|
"$schema": "https://biomejs.dev/schemas/2.4.7/schema.json",
|
||||||
"formatter": {
|
"formatter": {
|
||||||
"indentStyle": "space",
|
"indentStyle": "space",
|
||||||
"indentWidth": 4,
|
"indentWidth": 4,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="favicon.svg" />
|
||||||
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
<link rel="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" />
|
||||||
|
|||||||
3
commafeed-client/lint-staged.config.js
Normal file
3
commafeed-client/lint-staged.config.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export default {
|
||||||
|
"src/**/*.{js,jsx,ts,tsx}": () => ["npm run i18n:extract", "git diff --exit-code commafeed-client/src/locales/en/messages.po"],
|
||||||
|
}
|
||||||
4985
commafeed-client/package-lock.json
generated
4985
commafeed-client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -12,72 +12,75 @@
|
|||||||
"test:ci": "vitest run",
|
"test:ci": "vitest run",
|
||||||
"lint": "biome check",
|
"lint": "biome check",
|
||||||
"lint:fix": "biome check --write",
|
"lint:fix": "biome check --write",
|
||||||
"i18n:extract": "lingui extract --clean"
|
"i18n:extract": "lingui extract --clean",
|
||||||
|
"prepare": "cd .. && husky ./commafeed-client/.husky"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.14.0",
|
"@emotion/react": "^11.14.0",
|
||||||
"@fontsource/open-sans": "^5.2.6",
|
"@fontsource/open-sans": "^5.2.7",
|
||||||
"@lingui/core": "^5.4.0",
|
"@lingui/core": "^5.9.3",
|
||||||
"@lingui/react": "^5.4.0",
|
"@lingui/react": "^5.9.3",
|
||||||
"@mantine/core": "^8.2.3",
|
"@mantine/core": "^8.3.16",
|
||||||
"@mantine/form": "^8.2.3",
|
"@mantine/form": "^8.3.16",
|
||||||
"@mantine/hooks": "^8.2.3",
|
"@mantine/hooks": "^8.3.16",
|
||||||
"@mantine/modals": "^8.2.3",
|
"@mantine/modals": "^8.3.16",
|
||||||
"@mantine/notifications": "^8.2.3",
|
"@mantine/notifications": "^8.3.16",
|
||||||
"@mantine/spotlight": "^8.2.3",
|
"@mantine/spotlight": "^8.3.16",
|
||||||
"@monaco-editor/react": "^4.7.0",
|
"@monaco-editor/react": "^4.7.0",
|
||||||
"@reduxjs/toolkit": "^2.8.2",
|
"@react-querybuilder/mantine": "^8.14.0",
|
||||||
"axios": "^1.11.0",
|
"@reduxjs/toolkit": "^2.11.2",
|
||||||
"dayjs": "^1.11.13",
|
"@rolldown/plugin-babel": "^0.2.2",
|
||||||
|
"axios": "^1.13.6",
|
||||||
|
"dayjs": "^1.11.20",
|
||||||
"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.55.1",
|
||||||
"mousetrap": "^1.6.5",
|
"mousetrap": "^1.6.5",
|
||||||
"react": "^19.1.1",
|
"react": "^19.2.4",
|
||||||
"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-dom": "^19.2.4",
|
||||||
"react-dom": "^19.1.1",
|
|
||||||
"react-draggable": "^4.5.0",
|
"react-draggable": "^4.5.0",
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.6.0",
|
||||||
"react-infinite-scroller": "^1.2.6",
|
"react-infinite-scroller": "^1.2.6",
|
||||||
|
"react-querybuilder": "^8.14.0",
|
||||||
"react-redux": "^9.2.0",
|
"react-redux": "^9.2.0",
|
||||||
"react-router-dom": "^7.7.1",
|
"react-router-dom": "^7.13.1",
|
||||||
"react-swipeable": "^7.0.2",
|
"react-swipeable": "^7.0.2",
|
||||||
"style-to-object": "^1.0.9",
|
"style-to-object": "^1.0.14",
|
||||||
"throttle-debounce": "^5.0.2",
|
"throttle-debounce": "^5.0.2",
|
||||||
"tinycon": "^0.6.8",
|
"tinycon": "^0.6.8",
|
||||||
"tss-react": "^4.9.19",
|
"tss-react": "^4.9.20",
|
||||||
"websocket-heartbeat-js": "^1.1.3"
|
"websocket-heartbeat-js": "^1.1.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "^2.1.3",
|
"@biomejs/biome": "^2.4.7",
|
||||||
"@lingui/babel-plugin-lingui-macro": "^5.4.0",
|
"@lingui/babel-plugin-lingui-macro": "^5.9.3",
|
||||||
"@lingui/cli": "^5.4.0",
|
"@lingui/cli": "^5.9.3",
|
||||||
"@lingui/vite-plugin": "^5.4.0",
|
"@lingui/vite-plugin": "^5.9.3",
|
||||||
"@testing-library/jest-dom": "^6.6.4",
|
"@testing-library/jest-dom": "^6.9.1",
|
||||||
"@testing-library/react": "^16.3.0",
|
"@testing-library/react": "^16.3.2",
|
||||||
"@testing-library/user-event": "^14.6.1",
|
"@testing-library/user-event": "^14.6.1",
|
||||||
"@types/mousetrap": "^1.6.15",
|
"@types/mousetrap": "^1.6.15",
|
||||||
"@types/react": "^19.1.9",
|
"@types/react": "^19.2.14",
|
||||||
"@types/react-dom": "^19.1.7",
|
"@types/react-dom": "^19.2.3",
|
||||||
"@types/react-infinite-scroller": "^1.2.5",
|
"@types/react-infinite-scroller": "^1.2.5",
|
||||||
"@types/throttle-debounce": "^5.0.2",
|
"@types/throttle-debounce": "^5.0.2",
|
||||||
"@types/tinycon": "^0.6.7",
|
"@types/tinycon": "^0.6.7",
|
||||||
"@vitejs/plugin-react": "^4.7.0",
|
"@vitejs/plugin-react": "^6.0.1",
|
||||||
"babel-plugin-macros": "^3.1.0",
|
"babel-plugin-react-compiler": "1.0.0",
|
||||||
"babel-plugin-react-compiler": "^19.1.0-rc.2",
|
"husky": "^9.1.7",
|
||||||
"jsdom": "^26.1.0",
|
"jsdom": "^29.0.0",
|
||||||
"rollup-plugin-visualizer": "^6.0.3",
|
"lint-staged": "^16.4.0",
|
||||||
"typescript": "^5.9.2",
|
"typescript": "^5.9.3",
|
||||||
"vite": "^7.0.6",
|
"vite": "^8.0.0",
|
||||||
"vite-plugin-checker": "^0.10.2",
|
"vite-plugin-checker": "^0.12.0",
|
||||||
"vite-tsconfig-paths": "^5.1.4",
|
"vitest": "^4.1.0",
|
||||||
"vitest": "^3.2.4"
|
"yaml": "^2.8.2"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"react-infinite-scroller": {
|
"react-infinite-scroller": {
|
||||||
"react": "^19.1.1"
|
"react": "^19.2.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,19 +6,16 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.commafeed</groupId>
|
<groupId>com.commafeed</groupId>
|
||||||
<artifactId>commafeed</artifactId>
|
<artifactId>commafeed</artifactId>
|
||||||
<version>5.11.0</version>
|
<version>7.0.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>commafeed-client</artifactId>
|
<artifactId>commafeed-client</artifactId>
|
||||||
<name>CommaFeed Client</name>
|
<name>CommaFeed Client</name>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<sonar.sources>package.json,src</sonar.sources>
|
|
||||||
<sonar.coverage.exclusions>**/*</sonar.coverage.exclusions>
|
|
||||||
|
|
||||||
<!-- renovate: datasource=node-version depName=node -->
|
<!-- renovate: datasource=node-version depName=node -->
|
||||||
<node.version>v22.18.0</node.version>
|
<node.version>v24.14.0</node.version>
|
||||||
<!-- renovate: datasource=npm depName=npm -->
|
<!-- renovate: datasource=npm depName=npm -->
|
||||||
<npm.version>11.5.2</npm.version>
|
<npm.version>11.11.1</npm.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
@@ -26,7 +23,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>com.github.eirslett</groupId>
|
<groupId>com.github.eirslett</groupId>
|
||||||
<artifactId>frontend-maven-plugin</artifactId>
|
<artifactId>frontend-maven-plugin</artifactId>
|
||||||
<version>1.15.1</version>
|
<version>2.0.0</version>
|
||||||
<?m2e ignore?>
|
<?m2e ignore?>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
@@ -75,7 +72,7 @@
|
|||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>maven-resources-plugin</artifactId>
|
<artifactId>maven-resources-plugin</artifactId>
|
||||||
<version>3.3.1</version>
|
<version>3.5.0</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<id>copy web interface to resources</id>
|
<id>copy web interface to resources</id>
|
||||||
@@ -97,4 +94,49 @@
|
|||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
<profiles>
|
||||||
|
<!-- This profile is used to kill the Biome process on Windows -->
|
||||||
|
<!-- npm ci can fail if Biome is running (e.g., in the IDE) because it locks some files -->
|
||||||
|
<profile>
|
||||||
|
<id>kill-biome</id>
|
||||||
|
<activation>
|
||||||
|
<os>
|
||||||
|
<family>Windows</family>
|
||||||
|
</os>
|
||||||
|
</activation>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>exec-maven-plugin</artifactId>
|
||||||
|
<version>3.6.3</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>kill-biome</id>
|
||||||
|
<phase>initialize</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>exec</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<executable>taskkill</executable>
|
||||||
|
<arguments>
|
||||||
|
<argument>/F</argument>
|
||||||
|
<argument>/IM</argument>
|
||||||
|
<argument>biome.exe</argument>
|
||||||
|
</arguments>
|
||||||
|
<successCodes>
|
||||||
|
<successCode>0</successCode>
|
||||||
|
<!-- taskkill returns 128 if the process is not found, which is fine in this case -->
|
||||||
|
<successCode>128</successCode>
|
||||||
|
</successCodes>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
62
commafeed-client/public/favicon.svg
Normal file
62
commafeed-client/public/favicon.svg
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
height="393.84613"
|
||||||
|
width="393.84613"
|
||||||
|
viewBox="0 0 5.0480766 5.0480766"
|
||||||
|
version="1.1"
|
||||||
|
id="svg3"
|
||||||
|
sodipodi:docname="favicon.svg"
|
||||||
|
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs3" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview3"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:zoom="1.21875"
|
||||||
|
inkscape:cx="207.17949"
|
||||||
|
inkscape:cy="187.07692"
|
||||||
|
inkscape:window-width="1440"
|
||||||
|
inkscape:window-height="855"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg3" />
|
||||||
|
<rect
|
||||||
|
fill="#f88a14"
|
||||||
|
rx="0.53846151"
|
||||||
|
ry="0.53846151"
|
||||||
|
height="5.0480766"
|
||||||
|
width="5.0480766"
|
||||||
|
id="rect1"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
style="stroke-width:0.769231" />
|
||||||
|
<path
|
||||||
|
d="m 1.3450904,0.64548657 c 2.9002,0 2.9002,2.91010003 2.9002,2.91010003"
|
||||||
|
fill="none"
|
||||||
|
stroke="#ffffff"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-width="0.78125"
|
||||||
|
id="path1" />
|
||||||
|
<path
|
||||||
|
d="m 1.3377904,1.9915866 c 1.5705,-0.00908 1.5705,1.5639 1.5705,1.5639"
|
||||||
|
fill="none"
|
||||||
|
stroke="#ffffff"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-width="0.78125"
|
||||||
|
id="path2" />
|
||||||
|
<path
|
||||||
|
d="m 2.0192904,3.5227866 c 0,0.23366 -0.10712,0.47418 -0.24663,0.6537 -0.1814,0.2333 -0.5705,0.5618 -0.6913,0.5653 0.0402,-0.0662 0.263,-0.5654 0.2563,-0.5654 -0.36423004,0 -0.65950004,-0.29265 -0.65950004,-0.65365 0,-0.361 0.29527,-0.65365 0.65950004,-0.65365 0.36423,0 0.68159,0.29265 0.68159,0.65365 z"
|
||||||
|
fill="#ffffff"
|
||||||
|
id="path3" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.9 KiB |
@@ -5,11 +5,11 @@ import { ModalsProvider } from "@mantine/modals"
|
|||||||
import { Notifications } from "@mantine/notifications"
|
import { Notifications } from "@mantine/notifications"
|
||||||
import type React from "react"
|
import type React from "react"
|
||||||
import { useEffect, useState } from "react"
|
import { useEffect, useState } from "react"
|
||||||
import { isSafari } from "react-device-detect"
|
|
||||||
import { HashRouter, Navigate, Route, Routes, useNavigate } from "react-router-dom"
|
import { HashRouter, Navigate, Route, Routes, useNavigate } from "react-router-dom"
|
||||||
import Tinycon from "tinycon"
|
import Tinycon from "tinycon"
|
||||||
import { Constants } from "@/app/constants"
|
import { Constants } from "@/app/constants"
|
||||||
import { redirectTo } from "@/app/redirect/slice"
|
import { redirectTo } from "@/app/redirect/slice"
|
||||||
|
import { redirectToInitialSetup } from "@/app/redirect/thunks"
|
||||||
import { reloadServerInfos } from "@/app/server/thunks"
|
import { reloadServerInfos } from "@/app/server/thunks"
|
||||||
import { useAppDispatch, useAppSelector } from "@/app/store"
|
import { useAppDispatch, useAppSelector } from "@/app/store"
|
||||||
import { categoryUnreadCount } from "@/app/utils"
|
import { categoryUnreadCount } from "@/app/utils"
|
||||||
@@ -31,8 +31,10 @@ import { FeedEntriesPage } from "@/pages/app/FeedEntriesPage"
|
|||||||
import Layout from "@/pages/app/Layout"
|
import Layout from "@/pages/app/Layout"
|
||||||
import { SettingsPage } from "@/pages/app/SettingsPage"
|
import { SettingsPage } from "@/pages/app/SettingsPage"
|
||||||
import { TagDetailsPage } from "@/pages/app/TagDetailsPage"
|
import { TagDetailsPage } from "@/pages/app/TagDetailsPage"
|
||||||
|
import { InitialSetupPage } from "@/pages/auth/InitialSetupPage"
|
||||||
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 { PasswordResetPage } from "@/pages/auth/PasswordResetPage"
|
||||||
import { RegistrationPage } from "@/pages/auth/RegistrationPage"
|
import { RegistrationPage } from "@/pages/auth/RegistrationPage"
|
||||||
import { WelcomePage } from "@/pages/WelcomePage"
|
import { WelcomePage } from "@/pages/WelcomePage"
|
||||||
|
|
||||||
@@ -83,9 +85,11 @@ function AppRoutes() {
|
|||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Navigate to={`/app/category/${Constants.categories.all.id}`} replace />} />
|
<Route path="/" element={<Navigate to={`/app/category/${Constants.categories.all.id}`} replace />} />
|
||||||
<Route path="welcome" element={<WelcomePage />} />
|
<Route path="welcome" element={<WelcomePage />} />
|
||||||
|
<Route path="setup" element={<InitialSetupPage />} />
|
||||||
<Route path="login" element={<LoginPage />} />
|
<Route path="login" element={<LoginPage />} />
|
||||||
<Route path="register" element={<RegistrationPage />} />
|
<Route path="register" element={<RegistrationPage />} />
|
||||||
<Route path="passwordRecovery" element={<PasswordRecoveryPage />} />
|
<Route path="passwordRecovery" element={<PasswordRecoveryPage />} />
|
||||||
|
<Route path="passwordReset" element={<PasswordResetPage />} />
|
||||||
<Route path="app" element={<Layout header={<Header />} sidebar={<Tree />} sidebarVisible={sidebarVisible} />}>
|
<Route path="app" element={<Layout header={<Header />} sidebar={<Tree />} sidebarVisible={sidebarVisible} />}>
|
||||||
<Route path="category">
|
<Route path="category">
|
||||||
<Route path=":id" element={<FeedEntriesPage sourceType="category" />} />
|
<Route path=":id" element={<FeedEntriesPage sourceType="category" />} />
|
||||||
@@ -113,6 +117,18 @@ function AppRoutes() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function InitialSetupHandler() {
|
||||||
|
const serverInfos = useAppSelector(state => state.server.serverInfos)
|
||||||
|
const dispatch = useAppDispatch()
|
||||||
|
useEffect(() => {
|
||||||
|
if (serverInfos?.initialSetupRequired) {
|
||||||
|
dispatch(redirectToInitialSetup())
|
||||||
|
}
|
||||||
|
}, [serverInfos, dispatch])
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
function RedirectHandler() {
|
function RedirectHandler() {
|
||||||
const target = useAppSelector(state => state.redirect.to)
|
const target = useAppSelector(state => state.redirect.to)
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
@@ -179,6 +195,8 @@ function CustomJsHandler() {
|
|||||||
document.body.appendChild(script)
|
document.body.appendChild(script)
|
||||||
|
|
||||||
setScriptLoaded(true)
|
setScriptLoaded(true)
|
||||||
|
|
||||||
|
return () => script.remove()
|
||||||
}, [scriptLoaded, loading])
|
}, [scriptLoaded, loading])
|
||||||
|
|
||||||
return null
|
return null
|
||||||
@@ -191,6 +209,8 @@ function CustomCssHandler() {
|
|||||||
link.type = "text/css"
|
link.type = "text/css"
|
||||||
link.href = "custom_css.css"
|
link.href = "custom_css.css"
|
||||||
document.head.appendChild(link)
|
document.head.appendChild(link)
|
||||||
|
|
||||||
|
return () => link.remove()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return null
|
return null
|
||||||
@@ -200,6 +220,7 @@ export function App() {
|
|||||||
useI18n()
|
useI18n()
|
||||||
const unreadCountTitle = useAppSelector(state => state.user.settings?.unreadCountTitle)
|
const unreadCountTitle = useAppSelector(state => state.user.settings?.unreadCountTitle)
|
||||||
const unreadCountFavicon = useAppSelector(state => state.user.settings?.unreadCountFavicon)
|
const unreadCountFavicon = useAppSelector(state => state.user.settings?.unreadCountFavicon)
|
||||||
|
const disablePullToRefresh = useAppSelector(state => state.user.settings?.disablePullToRefresh)
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -213,14 +234,10 @@ export function App() {
|
|||||||
<BrowserExtensionBadgeUnreadCountHandler />
|
<BrowserExtensionBadgeUnreadCountHandler />
|
||||||
<CustomJsHandler />
|
<CustomJsHandler />
|
||||||
<CustomCssHandler />
|
<CustomCssHandler />
|
||||||
|
<DisablePullToRefresh enabled={disablePullToRefresh} />
|
||||||
{/* 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>
|
||||||
|
<InitialSetupHandler />
|
||||||
<RedirectHandler />
|
<RedirectHandler />
|
||||||
<AppRoutes />
|
<AppRoutes />
|
||||||
</HashRouter>
|
</HashRouter>
|
||||||
|
|||||||
@@ -12,12 +12,15 @@ import type {
|
|||||||
FeedModificationRequest,
|
FeedModificationRequest,
|
||||||
GetEntriesPaginatedRequest,
|
GetEntriesPaginatedRequest,
|
||||||
IDRequest,
|
IDRequest,
|
||||||
|
InitialSetupRequest,
|
||||||
LoginRequest,
|
LoginRequest,
|
||||||
MarkRequest,
|
MarkRequest,
|
||||||
Metrics,
|
Metrics,
|
||||||
MultipleMarkRequest,
|
MultipleMarkRequest,
|
||||||
|
PasswordResetConfirmationRequest,
|
||||||
PasswordResetRequest,
|
PasswordResetRequest,
|
||||||
ProfileModificationRequest,
|
ProfileModificationRequest,
|
||||||
|
PushNotificationSettings,
|
||||||
RegistrationRequest,
|
RegistrationRequest,
|
||||||
ServerInfo,
|
ServerInfo,
|
||||||
Settings,
|
Settings,
|
||||||
@@ -32,16 +35,17 @@ const axiosInstance = axios.create({ baseURL: "./rest", withCredentials: true })
|
|||||||
axiosInstance.interceptors.response.use(
|
axiosInstance.interceptors.response.use(
|
||||||
response => response,
|
response => response,
|
||||||
error => {
|
error => {
|
||||||
if (isAuthenticationError(error)) {
|
if (isAuthenticationError(error) && window.location.hash !== "#/login") {
|
||||||
const data = error.response?.data
|
const data = error.response?.data
|
||||||
window.location.hash = data?.allowRegistrations ? "/welcome" : "/login"
|
window.location.hash = data?.allowRegistrations ? "/welcome" : "/login"
|
||||||
|
window.location.reload()
|
||||||
}
|
}
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
function isAuthenticationError(error: unknown): error is AxiosError<AuthenticationError> {
|
function isAuthenticationError(error: unknown): error is AxiosError<AuthenticationError> {
|
||||||
return axios.isAxiosError(error) && !!error.response && [401, 403].includes(error.response.status)
|
return axios.isAxiosError(error) && error.response?.status === 401
|
||||||
}
|
}
|
||||||
|
|
||||||
export const client = {
|
export const client = {
|
||||||
@@ -93,9 +97,13 @@ export const client = {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
register: async (req: RegistrationRequest) => await axiosInstance.post("user/register", req),
|
register: async (req: RegistrationRequest) => await axiosInstance.post("user/register", req),
|
||||||
|
initialSetup: async (req: InitialSetupRequest) => await axiosInstance.post("user/initialSetup", req),
|
||||||
passwordReset: async (req: PasswordResetRequest) => await axiosInstance.post("user/passwordReset", req),
|
passwordReset: async (req: PasswordResetRequest) => await axiosInstance.post("user/passwordReset", req),
|
||||||
|
passwordResetCallback: async (req: PasswordResetConfirmationRequest) => await axiosInstance.post("user/passwordResetCallback", req),
|
||||||
getSettings: async () => await axiosInstance.get<Settings>("user/settings"),
|
getSettings: async () => await axiosInstance.get<Settings>("user/settings"),
|
||||||
saveSettings: async (settings: Settings) => await axiosInstance.post("user/settings", settings),
|
saveSettings: async (settings: Settings) => await axiosInstance.post("user/settings", settings),
|
||||||
|
sendTestPushNotification: async (settings: PushNotificationSettings) =>
|
||||||
|
await axiosInstance.post("user/pushNotificationTest", settings),
|
||||||
getProfile: async () => await axiosInstance.get<UserModel>("user/profile"),
|
getProfile: async () => await axiosInstance.get<UserModel>("user/profile"),
|
||||||
saveProfile: async (req: ProfileModificationRequest) => await axiosInstance.post("user/profile", req),
|
saveProfile: async (req: ProfileModificationRequest) => await axiosInstance.post("user/profile", req),
|
||||||
deleteProfile: async () => await axiosInstance.post("user/profile/deleteAccount"),
|
deleteProfile: async () => await axiosInstance.post("user/profile/deleteAccount"),
|
||||||
|
|||||||
@@ -40,7 +40,9 @@ export const loadMoreEntries = createAppAsyncThunk("entries/loadMore", async (_,
|
|||||||
const state = thunkApi.getState()
|
const state = thunkApi.getState()
|
||||||
const { source } = state.entries
|
const { source } = state.entries
|
||||||
const offset =
|
const offset =
|
||||||
state.user.settings?.readingMode === "all" ? state.entries.entries.length : state.entries.entries.filter(e => !e.read).length
|
state.user.settings?.readingMode === "all" || (source.type === "category" && source.id === "starred")
|
||||||
|
? state.entries.entries.length
|
||||||
|
: state.entries.entries.filter(e => !e.read).length
|
||||||
const endpoint = getEndpoint(state.entries.source.type)
|
const endpoint = getEndpoint(state.entries.source.type)
|
||||||
const result = await endpoint(buildGetEntriesPaginatedRequest(state, source, offset))
|
const result = await endpoint(buildGetEntriesPaginatedRequest(state, source, offset))
|
||||||
return result.data
|
return result.data
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ export const redirectToLogin = createAppAsyncThunk("redirect/login", (_, thunkAp
|
|||||||
|
|
||||||
export const redirectToRegistration = createAppAsyncThunk("redirect/register", (_, thunkApi) => thunkApi.dispatch(redirectTo("/register")))
|
export const redirectToRegistration = createAppAsyncThunk("redirect/register", (_, thunkApi) => thunkApi.dispatch(redirectTo("/register")))
|
||||||
|
|
||||||
|
export const redirectToInitialSetup = createAppAsyncThunk("redirect/initialSetup", (_, thunkApi) => thunkApi.dispatch(redirectTo("/setup")))
|
||||||
|
|
||||||
export const redirectToApiDocumentation = createAppAsyncThunk("redirect/api", () => {
|
export const redirectToApiDocumentation = createAppAsyncThunk("redirect/api", () => {
|
||||||
window.location.href = "api-documentation/"
|
window.location.href = "api-documentation/"
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { configureStore } from "@reduxjs/toolkit"
|
import { configureStore } from "@reduxjs/toolkit"
|
||||||
import { type TypedUseSelectorHook, useDispatch, useSelector } from "react-redux"
|
import { shallowEqual, type TypedUseSelectorHook, useDispatch, useSelector } from "react-redux"
|
||||||
import { entriesSlice } from "@/app/entries/slice"
|
import { entriesSlice } from "@/app/entries/slice"
|
||||||
import { redirectSlice } from "@/app/redirect/slice"
|
import { redirectSlice } from "@/app/redirect/slice"
|
||||||
import { serverSlice } from "@/app/server/slice"
|
import { serverSlice } from "@/app/server/slice"
|
||||||
@@ -41,3 +41,4 @@ export type AppDispatch = typeof store.dispatch
|
|||||||
|
|
||||||
export const useAppDispatch: () => AppDispatch = useDispatch
|
export const useAppDispatch: () => AppDispatch = useDispatch
|
||||||
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
|
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
|
||||||
|
export const useShallowEqualAppSelector: TypedUseSelectorHook<RootState> = selector => useSelector(selector, shallowEqual)
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ const createFeed = (id: number, unread: number): Subscription => ({
|
|||||||
feedUrl: "",
|
feedUrl: "",
|
||||||
feedLink: "",
|
feedLink: "",
|
||||||
iconUrl: "",
|
iconUrl: "",
|
||||||
|
pushNotificationsEnabled: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const root = createCategory("root")
|
const root = createCategory("root")
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ export interface Subscription {
|
|||||||
position: number
|
position: number
|
||||||
newestItemTime?: number
|
newestItemTime?: number
|
||||||
filter?: string
|
filter?: string
|
||||||
|
filterLegacy?: string
|
||||||
|
pushNotificationsEnabled: boolean
|
||||||
|
autoMarkAsReadAfterDays?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Category {
|
export interface Category {
|
||||||
@@ -109,6 +112,8 @@ export interface FeedModificationRequest {
|
|||||||
categoryId?: string
|
categoryId?: string
|
||||||
position?: number
|
position?: number
|
||||||
filter?: string
|
filter?: string
|
||||||
|
pushNotificationsEnabled: boolean
|
||||||
|
autoMarkAsReadAfterDays?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GetEntriesRequest {
|
export interface GetEntriesRequest {
|
||||||
@@ -196,6 +201,12 @@ export interface PasswordResetRequest {
|
|||||||
email: string
|
email: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PasswordResetConfirmationRequest {
|
||||||
|
email: string
|
||||||
|
token: string
|
||||||
|
password: string
|
||||||
|
}
|
||||||
|
|
||||||
export interface ProfileModificationRequest {
|
export interface ProfileModificationRequest {
|
||||||
currentPassword: string
|
currentPassword: string
|
||||||
email: string
|
email: string
|
||||||
@@ -209,17 +220,27 @@ export interface RegistrationRequest {
|
|||||||
email: string
|
email: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface InitialSetupRequest {
|
||||||
|
name: string
|
||||||
|
password: string
|
||||||
|
email?: string
|
||||||
|
}
|
||||||
|
|
||||||
export interface ServerInfo {
|
export interface ServerInfo {
|
||||||
announcement?: string
|
announcement?: string
|
||||||
version: string
|
version: string
|
||||||
gitCommit: string
|
gitCommit: string
|
||||||
allowRegistrations: boolean
|
allowRegistrations: boolean
|
||||||
|
emailAddressRequired: boolean
|
||||||
smtpEnabled: boolean
|
smtpEnabled: boolean
|
||||||
demoAccountEnabled: boolean
|
demoAccountEnabled: boolean
|
||||||
websocketEnabled: boolean
|
websocketEnabled: boolean
|
||||||
websocketPingInterval: number
|
websocketPingInterval: number
|
||||||
treeReloadInterval: number
|
treeReloadInterval: number
|
||||||
forceRefreshCooldownDuration: number
|
forceRefreshCooldownDuration: number
|
||||||
|
initialSetupRequired: boolean
|
||||||
|
minimumPasswordLength: number
|
||||||
|
pushNotificationsEnabled: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SharingSettings {
|
export interface SharingSettings {
|
||||||
@@ -233,8 +254,18 @@ export interface SharingSettings {
|
|||||||
buffer: boolean
|
buffer: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type PushNotificationType = "ntfy" | "gotify" | "pushover"
|
||||||
|
|
||||||
|
export interface PushNotificationSettings {
|
||||||
|
type?: PushNotificationType
|
||||||
|
serverUrl?: string
|
||||||
|
userId?: string
|
||||||
|
userSecret?: string
|
||||||
|
topic?: string
|
||||||
|
}
|
||||||
|
|
||||||
export interface Settings {
|
export interface Settings {
|
||||||
language: string
|
language?: string
|
||||||
readingMode: ReadingMode
|
readingMode: ReadingMode
|
||||||
readingOrder: ReadingOrder
|
readingOrder: ReadingOrder
|
||||||
showRead: boolean
|
showRead: boolean
|
||||||
@@ -252,8 +283,10 @@ export interface Settings {
|
|||||||
mobileFooter: boolean
|
mobileFooter: boolean
|
||||||
unreadCountTitle: boolean
|
unreadCountTitle: boolean
|
||||||
unreadCountFavicon: boolean
|
unreadCountFavicon: boolean
|
||||||
|
disablePullToRefresh: boolean
|
||||||
primaryColor?: string
|
primaryColor?: string
|
||||||
sharingSettings: SharingSettings
|
sharingSettings: SharingSettings
|
||||||
|
pushNotificationSettings: PushNotificationSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LocalSettings {
|
export interface LocalSettings {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { createSlice, isAnyOf, type PayloadAction } from "@reduxjs/toolkit"
|
|||||||
import type { LocalSettings, Settings, UserModel, ViewMode } from "@/app/types"
|
import type { LocalSettings, Settings, UserModel, ViewMode } from "@/app/types"
|
||||||
import {
|
import {
|
||||||
changeCustomContextMenu,
|
changeCustomContextMenu,
|
||||||
|
changeDisablePullToRefresh,
|
||||||
changeEntriesToKeepOnTopWhenScrolling,
|
changeEntriesToKeepOnTopWhenScrolling,
|
||||||
changeExternalLinkIconDisplayMode,
|
changeExternalLinkIconDisplayMode,
|
||||||
changeLanguage,
|
changeLanguage,
|
||||||
@@ -11,6 +12,7 @@ import {
|
|||||||
changeMarkAllAsReadNavigateToUnread,
|
changeMarkAllAsReadNavigateToUnread,
|
||||||
changeMobileFooter,
|
changeMobileFooter,
|
||||||
changePrimaryColor,
|
changePrimaryColor,
|
||||||
|
changePushNotificationSettings,
|
||||||
changeReadingMode,
|
changeReadingMode,
|
||||||
changeReadingOrder,
|
changeReadingOrder,
|
||||||
changeScrollMarks,
|
changeScrollMarks,
|
||||||
@@ -135,6 +137,10 @@ export const userSlice = createSlice({
|
|||||||
if (!state.settings) return
|
if (!state.settings) return
|
||||||
state.settings.unreadCountFavicon = action.meta.arg
|
state.settings.unreadCountFavicon = action.meta.arg
|
||||||
})
|
})
|
||||||
|
builder.addCase(changeDisablePullToRefresh.pending, (state, action) => {
|
||||||
|
if (!state.settings) return
|
||||||
|
state.settings.disablePullToRefresh = action.meta.arg
|
||||||
|
})
|
||||||
builder.addCase(changePrimaryColor.pending, (state, action) => {
|
builder.addCase(changePrimaryColor.pending, (state, action) => {
|
||||||
if (!state.settings) return
|
if (!state.settings) return
|
||||||
state.settings.primaryColor = action.meta.arg
|
state.settings.primaryColor = action.meta.arg
|
||||||
@@ -143,6 +149,11 @@ export const userSlice = createSlice({
|
|||||||
if (!state.settings) return
|
if (!state.settings) return
|
||||||
state.settings.sharingSettings[action.meta.arg.site] = action.meta.arg.value
|
state.settings.sharingSettings[action.meta.arg.site] = action.meta.arg.value
|
||||||
})
|
})
|
||||||
|
builder.addCase(changePushNotificationSettings.pending, (state, action) => {
|
||||||
|
if (!state.settings) return
|
||||||
|
state.settings.pushNotificationSettings = action.meta.arg
|
||||||
|
})
|
||||||
|
|
||||||
builder.addMatcher(
|
builder.addMatcher(
|
||||||
isAnyOf(
|
isAnyOf(
|
||||||
changeLanguage.fulfilled,
|
changeLanguage.fulfilled,
|
||||||
@@ -159,8 +170,10 @@ export const userSlice = createSlice({
|
|||||||
changeMobileFooter.fulfilled,
|
changeMobileFooter.fulfilled,
|
||||||
changeUnreadCountTitle.fulfilled,
|
changeUnreadCountTitle.fulfilled,
|
||||||
changeUnreadCountFavicon.fulfilled,
|
changeUnreadCountFavicon.fulfilled,
|
||||||
|
changeDisablePullToRefresh.fulfilled,
|
||||||
changePrimaryColor.fulfilled,
|
changePrimaryColor.fulfilled,
|
||||||
changeSharingSetting.fulfilled
|
changeSharingSetting.fulfilled,
|
||||||
|
changePushNotificationSettings.fulfilled
|
||||||
),
|
),
|
||||||
() => {
|
() => {
|
||||||
showNotification({
|
showNotification({
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createAppAsyncThunk } from "@/app/async-thunk"
|
import { createAppAsyncThunk } from "@/app/async-thunk"
|
||||||
import { client } from "@/app/client"
|
import { client } from "@/app/client"
|
||||||
import { reloadEntries } from "@/app/entries/thunks"
|
import { reloadEntries } from "@/app/entries/thunks"
|
||||||
import type { IconDisplayMode, ReadingMode, ReadingOrder, ScrollMode, SharingSettings } from "@/app/types"
|
import type { IconDisplayMode, PushNotificationSettings, ReadingMode, ReadingOrder, ScrollMode, SharingSettings } from "@/app/types"
|
||||||
|
|
||||||
export const reloadSettings = createAppAsyncThunk("settings/reload", async () => await client.user.getSettings().then(r => r.data))
|
export const reloadSettings = createAppAsyncThunk("settings/reload", async () => await client.user.getSettings().then(r => r.data))
|
||||||
|
|
||||||
@@ -122,6 +122,15 @@ export const changeUnreadCountFavicon = createAppAsyncThunk("settings/unreadCoun
|
|||||||
client.user.saveSettings({ ...settings, unreadCountFavicon })
|
client.user.saveSettings({ ...settings, unreadCountFavicon })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const changeDisablePullToRefresh = createAppAsyncThunk(
|
||||||
|
"settings/disablePullToRefresh",
|
||||||
|
(disablePullToRefresh: boolean, thunkApi) => {
|
||||||
|
const { settings } = thunkApi.getState().user
|
||||||
|
if (!settings) return
|
||||||
|
client.user.saveSettings({ ...settings, disablePullToRefresh })
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
export const changePrimaryColor = createAppAsyncThunk("settings/primaryColor", (primaryColor: string, thunkApi) => {
|
export const changePrimaryColor = createAppAsyncThunk("settings/primaryColor", (primaryColor: string, thunkApi) => {
|
||||||
const { settings } = thunkApi.getState().user
|
const { settings } = thunkApi.getState().user
|
||||||
if (!settings) return
|
if (!settings) return
|
||||||
@@ -148,3 +157,15 @@ export const changeSharingSetting = createAppAsyncThunk(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export const changePushNotificationSettings = createAppAsyncThunk(
|
||||||
|
"settings/pushNotificationSettings",
|
||||||
|
(pushNotificationSettings: PushNotificationSettings, thunkApi) => {
|
||||||
|
const { settings } = thunkApi.getState().user
|
||||||
|
if (!settings) return
|
||||||
|
client.user.saveSettings({
|
||||||
|
...settings,
|
||||||
|
pushNotificationSettings,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
html,
|
|
||||||
body {
|
|
||||||
overscroll-behavior: none;
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
export const DisablePullToRefresh = () => {
|
export const DisablePullToRefresh = ({ enabled }: { enabled: boolean | undefined }) => {
|
||||||
import("./DisablePullToRefresh.css")
|
return enabled ? <style>{`html, body { overscroll-behavior: none; }`}</style> : null
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { Trans } from "@lingui/react/macro"
|
||||||
|
import { Checkbox, type CheckboxProps } from "@mantine/core"
|
||||||
|
import type { ReactNode } from "react"
|
||||||
|
import { useAppSelector } from "@/app/store"
|
||||||
|
|
||||||
|
export const ReceivePushNotificationsChechbox = (props: CheckboxProps) => {
|
||||||
|
const pushNotificationsEnabled = useAppSelector(state => state.server.serverInfos?.pushNotificationsEnabled)
|
||||||
|
const pushNotificationsConfigured = useAppSelector(state => !!state.user.settings?.pushNotificationSettings.type)
|
||||||
|
|
||||||
|
const disabled = !pushNotificationsEnabled || !pushNotificationsConfigured
|
||||||
|
let description: ReactNode = ""
|
||||||
|
if (!pushNotificationsEnabled) {
|
||||||
|
description = <Trans>Push notifications are not enabled on this CommaFeed instance.</Trans>
|
||||||
|
} else if (!pushNotificationsConfigured) {
|
||||||
|
description = <Trans>Push notifications are not configured in your user settings.</Trans>
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Checkbox label={<Trans>Receive push notifications</Trans>} disabled={disabled} description={description} {...props} />
|
||||||
|
}
|
||||||
@@ -145,6 +145,7 @@ export function FeedEntry(props: Readonly<FeedEntryProps>) {
|
|||||||
component="article"
|
component="article"
|
||||||
id={Constants.dom.entryId(props.entry)}
|
id={Constants.dom.entryId(props.entry)}
|
||||||
data-id={props.entry.id}
|
data-id={props.entry.id}
|
||||||
|
data-feed-id={props.entry.feedId}
|
||||||
withBorder
|
withBorder
|
||||||
radius={borderRadius}
|
radius={borderRadius}
|
||||||
className={cx(classes.paper, {
|
className={cx(classes.paper, {
|
||||||
|
|||||||
@@ -61,19 +61,21 @@ export function FeedEntryContextMenu(props: Readonly<FeedEntryContextMenuProps>)
|
|||||||
|
|
||||||
<Separator />
|
<Separator />
|
||||||
|
|
||||||
<Item onClick={async () => await dispatch(starEntry({ entry: props.entry, starred: !props.entry.starred }))}>
|
|
||||||
<Group>
|
|
||||||
{props.entry.starred ? <TbStarOff size={iconSize} /> : <TbStar size={iconSize} />}
|
|
||||||
{props.entry.starred ? <Trans>Unstar</Trans> : <Trans>Star</Trans>}
|
|
||||||
</Group>
|
|
||||||
</Item>
|
|
||||||
{props.entry.markable && (
|
{props.entry.markable && (
|
||||||
<Item onClick={async () => await dispatch(markEntry({ entry: props.entry, read: !props.entry.read }))}>
|
<>
|
||||||
<Group>
|
<Item onClick={async () => await dispatch(starEntry({ entry: props.entry, starred: !props.entry.starred }))}>
|
||||||
{props.entry.read ? <TbMail size={iconSize} /> : <TbMailOpened size={iconSize} />}
|
<Group>
|
||||||
{props.entry.read ? <Trans>Keep unread</Trans> : <Trans>Mark as read</Trans>}
|
{props.entry.starred ? <TbStarOff size={iconSize} /> : <TbStar size={iconSize} />}
|
||||||
</Group>
|
{props.entry.starred ? <Trans>Unstar</Trans> : <Trans>Star</Trans>}
|
||||||
</Item>
|
</Group>
|
||||||
|
</Item>
|
||||||
|
<Item onClick={async () => await dispatch(markEntry({ entry: props.entry, read: !props.entry.read }))}>
|
||||||
|
<Group>
|
||||||
|
{props.entry.read ? <TbMail size={iconSize} /> : <TbMailOpened size={iconSize} />}
|
||||||
|
{props.entry.read ? <Trans>Keep unread</Trans> : <Trans>Mark as read</Trans>}
|
||||||
|
</Group>
|
||||||
|
</Item>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
<Item onClick={async () => await dispatch(markEntriesUpToEntry(props.entry))}>
|
<Item onClick={async () => await dispatch(markEntriesUpToEntry(props.entry))}>
|
||||||
<Group>
|
<Group>
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
import { Stack } from "@mantine/core"
|
||||||
|
import { MantineValueSelector, QueryBuilderMantine } from "@react-querybuilder/mantine"
|
||||||
|
import {
|
||||||
|
type CombinatorSelectorProps,
|
||||||
|
defaultOperators,
|
||||||
|
defaultRuleProcessorCEL,
|
||||||
|
type Field,
|
||||||
|
type FormatQueryOptions,
|
||||||
|
formatQuery,
|
||||||
|
QueryBuilder,
|
||||||
|
type RuleGroupType,
|
||||||
|
} from "react-querybuilder"
|
||||||
|
import { isCELIdentifier, isCELMember, isCELStringLiteral, parseCEL } from "react-querybuilder/parseCEL"
|
||||||
|
import "react-querybuilder/dist/query-builder.css"
|
||||||
|
|
||||||
|
const fields: Field[] = [
|
||||||
|
{ name: "title", label: "Title" },
|
||||||
|
{ name: "content", label: "Content" },
|
||||||
|
{ name: "url", label: "URL" },
|
||||||
|
{ name: "author", label: "Author" },
|
||||||
|
{ name: "categories", label: "Categories" },
|
||||||
|
{ name: "titleLower", label: "Title (lower case)" },
|
||||||
|
{ name: "contentLower", label: "Content (lower case)" },
|
||||||
|
{ name: "urlLower", label: "URL (lower case)" },
|
||||||
|
{ name: "authorLower", label: "Author (lower case)" },
|
||||||
|
{ name: "categoriesLower", label: "Categories (lower case)" },
|
||||||
|
]
|
||||||
|
|
||||||
|
const textOperators = new Set(["=", "!=", "contains", "beginsWith", "endsWith", "doesNotContain", "doesNotBeginWith", "doesNotEndWith"])
|
||||||
|
|
||||||
|
function toCelString(query: RuleGroupType): string {
|
||||||
|
if (query.rules.length === 0) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
const celFormatOptions: FormatQueryOptions = {
|
||||||
|
format: "cel",
|
||||||
|
ruleProcessor: (rule, options, meta) => {
|
||||||
|
if (rule.operator === "matches") {
|
||||||
|
const escapedValue = String(rule.value).replaceAll("\\", "\\\\").replaceAll('"', String.raw`\"`)
|
||||||
|
return `${rule.field}.matches("${escapedValue}")`
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultRuleProcessorCEL(rule, options, meta)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return formatQuery(query, celFormatOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
function fromCelString(celString: string): RuleGroupType {
|
||||||
|
return parseCEL(celString ?? "", {
|
||||||
|
customExpressionHandler: expr => {
|
||||||
|
if (
|
||||||
|
isCELMember(expr) &&
|
||||||
|
expr.right?.value === "matches" &&
|
||||||
|
expr.left &&
|
||||||
|
isCELIdentifier(expr.left) &&
|
||||||
|
expr.list &&
|
||||||
|
isCELStringLiteral(expr.list.value[0])
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
field: expr.left.value,
|
||||||
|
operator: "matches",
|
||||||
|
value: JSON.parse(expr.list.value[0].value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const getOperators = () => {
|
||||||
|
const filteredDefault = defaultOperators.filter(op => textOperators.has(op.name))
|
||||||
|
return [
|
||||||
|
...filteredDefault,
|
||||||
|
{
|
||||||
|
name: "matches",
|
||||||
|
label: "matches pattern",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
function CombinatorSelector(props: Readonly<CombinatorSelectorProps>) {
|
||||||
|
if (props.rules.length === 0) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return <MantineValueSelector {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FilteringExpressionEditorProps {
|
||||||
|
initialValue: string | undefined
|
||||||
|
onChange: (value: string) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export function FilteringExpressionEditor({ initialValue, onChange }: Readonly<FilteringExpressionEditorProps>) {
|
||||||
|
const handleQueryChange = (newQuery: RuleGroupType) => {
|
||||||
|
onChange(toCelString(newQuery))
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack gap="sm">
|
||||||
|
<QueryBuilderMantine>
|
||||||
|
<QueryBuilder
|
||||||
|
fields={fields}
|
||||||
|
defaultQuery={fromCelString(initialValue ?? "")}
|
||||||
|
onQueryChange={handleQueryChange}
|
||||||
|
getOperators={getOperators}
|
||||||
|
addRuleToNewGroups
|
||||||
|
resetOnFieldChange={false}
|
||||||
|
controlClassnames={{ queryBuilder: "queryBuilder-branches" }}
|
||||||
|
controlElements={{ combinatorSelector: CombinatorSelector }}
|
||||||
|
/>
|
||||||
|
</QueryBuilderMantine>
|
||||||
|
</Stack>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -63,11 +63,7 @@ export function Header() {
|
|||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
const { _ } = useLingui()
|
const { _ } = useLingui()
|
||||||
|
|
||||||
const searchForm = useForm<{ search: string }>({
|
const searchForm = useForm<{ search: string }>()
|
||||||
validate: {
|
|
||||||
search: value => (value.length > 0 && value.length < 3 ? _(msg`Search requires at least 3 characters`) : null),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
const { setValues } = searchForm
|
const { setValues } = searchForm
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
} from "@mantine/core"
|
} from "@mantine/core"
|
||||||
import { showNotification } from "@mantine/notifications"
|
import { showNotification } from "@mantine/notifications"
|
||||||
import dayjs from "dayjs"
|
import dayjs from "dayjs"
|
||||||
import { type ReactNode, useState } from "react"
|
import { type ReactNode, useEffect, useState } from "react"
|
||||||
import {
|
import {
|
||||||
TbChartLine,
|
TbChartLine,
|
||||||
TbHeartFilled,
|
TbHeartFilled,
|
||||||
@@ -29,6 +29,7 @@ import {
|
|||||||
TbUsers,
|
TbUsers,
|
||||||
TbWorldDownload,
|
TbWorldDownload,
|
||||||
} from "react-icons/tb"
|
} from "react-icons/tb"
|
||||||
|
import { throttle } from "throttle-debounce"
|
||||||
import { client } from "@/app/client"
|
import { client } from "@/app/client"
|
||||||
import { redirectToAbout, redirectToAdminUsers, redirectToDonate, redirectToMetrics, redirectToSettings } from "@/app/redirect/thunks"
|
import { redirectToAbout, redirectToAdminUsers, redirectToDonate, redirectToMetrics, redirectToSettings } from "@/app/redirect/thunks"
|
||||||
import { useAppDispatch, useAppSelector } from "@/app/store"
|
import { useAppDispatch, useAppSelector } from "@/app/store"
|
||||||
@@ -96,6 +97,14 @@ const viewModeData: ViewModeControlItem[] = [
|
|||||||
|
|
||||||
export function ProfileMenu(props: Readonly<ProfileMenuProps>) {
|
export function ProfileMenu(props: Readonly<ProfileMenuProps>) {
|
||||||
const [opened, setOpened] = useState(false)
|
const [opened, setOpened] = useState(false)
|
||||||
|
|
||||||
|
// close profile menu on scroll
|
||||||
|
useEffect(() => {
|
||||||
|
const listener = throttle(100, () => setOpened(false))
|
||||||
|
window.addEventListener("scroll", listener)
|
||||||
|
return () => window.removeEventListener("scroll", listener)
|
||||||
|
}, [])
|
||||||
|
|
||||||
const now = useNow()
|
const now = useNow()
|
||||||
const profile = useAppSelector(state => state.user.profile)
|
const profile = useAppSelector(state => state.user.profile)
|
||||||
const admin = useAppSelector(state => state.user.profile?.admin)
|
const admin = useAppSelector(state => state.user.profile?.admin)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { useAppDispatch, useAppSelector } from "@/app/store"
|
|||||||
import type { IconDisplayMode, ScrollMode, SharingSettings } from "@/app/types"
|
import type { IconDisplayMode, ScrollMode, SharingSettings } from "@/app/types"
|
||||||
import {
|
import {
|
||||||
changeCustomContextMenu,
|
changeCustomContextMenu,
|
||||||
|
changeDisablePullToRefresh,
|
||||||
changeEntriesToKeepOnTopWhenScrolling,
|
changeEntriesToKeepOnTopWhenScrolling,
|
||||||
changeExternalLinkIconDisplayMode,
|
changeExternalLinkIconDisplayMode,
|
||||||
changeLanguage,
|
changeLanguage,
|
||||||
@@ -42,6 +43,7 @@ export function DisplaySettings() {
|
|||||||
const mobileFooter = useAppSelector(state => state.user.settings?.mobileFooter)
|
const mobileFooter = useAppSelector(state => state.user.settings?.mobileFooter)
|
||||||
const unreadCountTitle = useAppSelector(state => state.user.settings?.unreadCountTitle)
|
const unreadCountTitle = useAppSelector(state => state.user.settings?.unreadCountTitle)
|
||||||
const unreadCountFavicon = useAppSelector(state => state.user.settings?.unreadCountFavicon)
|
const unreadCountFavicon = useAppSelector(state => state.user.settings?.unreadCountFavicon)
|
||||||
|
const disablePullToRefresh = useAppSelector(state => state.user.settings?.disablePullToRefresh)
|
||||||
const sharingSettings = useAppSelector(state => state.user.settings?.sharingSettings)
|
const sharingSettings = useAppSelector(state => state.user.settings?.sharingSettings)
|
||||||
const primaryColor = useAppSelector(state => state.user.settings?.primaryColor) || Constants.theme.defaultPrimaryColor
|
const primaryColor = useAppSelector(state => state.user.settings?.primaryColor) || Constants.theme.defaultPrimaryColor
|
||||||
const { _ } = useLingui()
|
const { _ } = useLingui()
|
||||||
@@ -141,6 +143,47 @@ export function DisplaySettings() {
|
|||||||
onChange={async e => await dispatch(changeMobileFooter(e.currentTarget.checked))}
|
onChange={async e => await dispatch(changeMobileFooter(e.currentTarget.checked))}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Divider label={<Trans>Scrolling</Trans>} labelPosition="center" />
|
||||||
|
|
||||||
|
<Switch
|
||||||
|
label={<Trans>Disable "Pull to refresh" browser behavior</Trans>}
|
||||||
|
description={<Trans>This setting can cause scrolling issues on some browsers (e.g. Safari)</Trans>}
|
||||||
|
checked={disablePullToRefresh}
|
||||||
|
onChange={async e => await dispatch(changeDisablePullToRefresh(e.currentTarget.checked))}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Radio.Group
|
||||||
|
label={<Trans>Scroll selected entry to the top of the page</Trans>}
|
||||||
|
value={scrollMode}
|
||||||
|
onChange={async value => await dispatch(changeScrollMode(value as ScrollMode))}
|
||||||
|
>
|
||||||
|
<Group mt="xs">
|
||||||
|
{Object.entries(scrollModeOptions).map(e => (
|
||||||
|
<Radio key={e[0]} value={e[0]} label={e[1]} />
|
||||||
|
))}
|
||||||
|
</Group>
|
||||||
|
</Radio.Group>
|
||||||
|
|
||||||
|
<NumberInput
|
||||||
|
label={<Trans>Entries to keep above the selected entry when scrolling</Trans>}
|
||||||
|
description={<Trans>Only applies to compact, cozy and detailed modes</Trans>}
|
||||||
|
min={0}
|
||||||
|
value={entriesToKeepOnTop}
|
||||||
|
onChange={async value => await dispatch(changeEntriesToKeepOnTopWhenScrolling(+value))}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Switch
|
||||||
|
label={<Trans>Scroll smoothly when navigating between entries</Trans>}
|
||||||
|
checked={scrollSpeed ? scrollSpeed > 0 : false}
|
||||||
|
onChange={async e => await dispatch(changeScrollSpeed(e.currentTarget.checked))}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Switch
|
||||||
|
label={<Trans>In expanded view, scrolling through entries mark them as read</Trans>}
|
||||||
|
checked={scrollMarks}
|
||||||
|
onChange={async e => await dispatch(changeScrollMarks(e.currentTarget.checked))}
|
||||||
|
/>
|
||||||
|
|
||||||
<Divider label={<Trans>Browser tab</Trans>} labelPosition="center" />
|
<Divider label={<Trans>Browser tab</Trans>} labelPosition="center" />
|
||||||
|
|
||||||
<Switch
|
<Switch
|
||||||
@@ -177,40 +220,6 @@ export function DisplaySettings() {
|
|||||||
onChange={async e => await dispatch(changeCustomContextMenu(e.currentTarget.checked))}
|
onChange={async e => await dispatch(changeCustomContextMenu(e.currentTarget.checked))}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Divider label={<Trans>Scrolling</Trans>} labelPosition="center" />
|
|
||||||
|
|
||||||
<Radio.Group
|
|
||||||
label={<Trans>Scroll selected entry to the top of the page</Trans>}
|
|
||||||
value={scrollMode}
|
|
||||||
onChange={async value => await dispatch(changeScrollMode(value as ScrollMode))}
|
|
||||||
>
|
|
||||||
<Group mt="xs">
|
|
||||||
{Object.entries(scrollModeOptions).map(e => (
|
|
||||||
<Radio key={e[0]} value={e[0]} label={e[1]} />
|
|
||||||
))}
|
|
||||||
</Group>
|
|
||||||
</Radio.Group>
|
|
||||||
|
|
||||||
<NumberInput
|
|
||||||
label={<Trans>Entries to keep above the selected entry when scrolling</Trans>}
|
|
||||||
description={<Trans>Only applies to compact, cozy and detailed modes</Trans>}
|
|
||||||
min={0}
|
|
||||||
value={entriesToKeepOnTop}
|
|
||||||
onChange={async value => await dispatch(changeEntriesToKeepOnTopWhenScrolling(+value))}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Switch
|
|
||||||
label={<Trans>Scroll smoothly when navigating between entries</Trans>}
|
|
||||||
checked={scrollSpeed ? scrollSpeed > 0 : false}
|
|
||||||
onChange={async e => await dispatch(changeScrollSpeed(e.currentTarget.checked))}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Switch
|
|
||||||
label={<Trans>In expanded view, scrolling through entries mark them as read</Trans>}
|
|
||||||
checked={scrollMarks}
|
|
||||||
onChange={async e => await dispatch(changeScrollMarks(e.currentTarget.checked))}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Divider label={<Trans>Sharing sites</Trans>} labelPosition="center" />
|
<Divider label={<Trans>Sharing sites</Trans>} labelPosition="center" />
|
||||||
|
|
||||||
<SimpleGrid cols={2}>
|
<SimpleGrid cols={2}>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { msg } from "@lingui/core/macro"
|
|
||||||
import { useLingui } from "@lingui/react"
|
import { useLingui } from "@lingui/react"
|
||||||
import { Trans } from "@lingui/react/macro"
|
import { Trans } from "@lingui/react/macro"
|
||||||
import { Anchor, Box, Button, Checkbox, Divider, Group, Input, PasswordInput, Stack, Text, TextInput } from "@mantine/core"
|
import { Anchor, Box, Button, Checkbox, Divider, Group, Input, PasswordInput, Stack, Text, TextInput } from "@mantine/core"
|
||||||
@@ -13,6 +12,7 @@ import { useAppDispatch, useAppSelector } from "@/app/store"
|
|||||||
import type { ProfileModificationRequest } from "@/app/types"
|
import type { ProfileModificationRequest } from "@/app/types"
|
||||||
import { reloadProfile } from "@/app/user/thunks"
|
import { reloadProfile } from "@/app/user/thunks"
|
||||||
import { Alert } from "@/components/Alert"
|
import { Alert } from "@/components/Alert"
|
||||||
|
import { useValidationRules } from "@/hooks/useValidationRules"
|
||||||
|
|
||||||
interface FormData extends ProfileModificationRequest {
|
interface FormData extends ProfileModificationRequest {
|
||||||
newPasswordConfirmation?: string
|
newPasswordConfirmation?: string
|
||||||
@@ -20,13 +20,17 @@ interface FormData extends ProfileModificationRequest {
|
|||||||
|
|
||||||
export function ProfileSettings() {
|
export function ProfileSettings() {
|
||||||
const profile = useAppSelector(state => state.user.profile)
|
const profile = useAppSelector(state => state.user.profile)
|
||||||
|
const serverInfos = useAppSelector(state => state.server.serverInfos)
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
const { _ } = useLingui()
|
const { _ } = useLingui()
|
||||||
|
const validationRules = useValidationRules()
|
||||||
|
|
||||||
const form = useForm<FormData>({
|
const form = useForm<FormData>({
|
||||||
validate: {
|
validate: {
|
||||||
newPasswordConfirmation: (value, values) => (value !== values.newPassword ? _(msg`Passwords do not match`) : null),
|
newPassword: validationRules.password,
|
||||||
|
newPasswordConfirmation: (value, values) => validationRules.passwordConfirmation(value, values.newPassword),
|
||||||
},
|
},
|
||||||
|
validateInputOnChange: true,
|
||||||
})
|
})
|
||||||
const { setValues } = form
|
const { setValues } = form
|
||||||
|
|
||||||
@@ -134,7 +138,12 @@ export function ProfileSettings() {
|
|||||||
required
|
required
|
||||||
{...form.getInputProps("currentPassword")}
|
{...form.getInputProps("currentPassword")}
|
||||||
/>
|
/>
|
||||||
<TextInput type="email" label={<Trans>E-mail</Trans>} {...form.getInputProps("email")} required />
|
<TextInput
|
||||||
|
type="email"
|
||||||
|
label={<Trans>E-mail</Trans>}
|
||||||
|
{...form.getInputProps("email")}
|
||||||
|
required={serverInfos?.emailAddressRequired}
|
||||||
|
/>
|
||||||
<PasswordInput
|
<PasswordInput
|
||||||
label={<Trans>New password</Trans>}
|
label={<Trans>New password</Trans>}
|
||||||
description={<Trans>Changing password will generate a new API key</Trans>}
|
description={<Trans>Changing password will generate a new API key</Trans>}
|
||||||
|
|||||||
@@ -0,0 +1,124 @@
|
|||||||
|
import { msg } from "@lingui/core/macro"
|
||||||
|
import { useLingui } from "@lingui/react"
|
||||||
|
import { Trans } from "@lingui/react/macro"
|
||||||
|
import { Button, Divider, Group, Select, Stack, TextInput } from "@mantine/core"
|
||||||
|
import { useForm } from "@mantine/form"
|
||||||
|
import { useEffect } from "react"
|
||||||
|
import { useAsyncCallback } from "react-async-hook"
|
||||||
|
import { TbDeviceFloppy, TbSend } from "react-icons/tb"
|
||||||
|
import { client, errorToStrings } from "@/app/client"
|
||||||
|
import { redirectToSelectedSource } from "@/app/redirect/thunks"
|
||||||
|
import { useAppDispatch, useAppSelector } from "@/app/store"
|
||||||
|
import type { PushNotificationSettings as PushNotificationSettingsModel } from "@/app/types"
|
||||||
|
import { changePushNotificationSettings } from "@/app/user/thunks"
|
||||||
|
import { Alert } from "@/components/Alert"
|
||||||
|
|
||||||
|
export function PushNotificationSettings() {
|
||||||
|
const notificationSettings = useAppSelector(state => state.user.settings?.pushNotificationSettings)
|
||||||
|
const pushNotificationsEnabled = useAppSelector(state => state.server.serverInfos?.pushNotificationsEnabled)
|
||||||
|
const { _ } = useLingui()
|
||||||
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
|
const form = useForm<PushNotificationSettingsModel>()
|
||||||
|
useEffect(() => {
|
||||||
|
if (notificationSettings) form.initialize(notificationSettings)
|
||||||
|
}, [form.initialize, notificationSettings])
|
||||||
|
|
||||||
|
const handleSubmit = (values: PushNotificationSettingsModel) => {
|
||||||
|
dispatch(changePushNotificationSettings(values))
|
||||||
|
}
|
||||||
|
|
||||||
|
const sendTestPushNotification = useAsyncCallback(client.user.sendTestPushNotification)
|
||||||
|
|
||||||
|
const typeInputProps = form.getInputProps("type")
|
||||||
|
|
||||||
|
if (!pushNotificationsEnabled) {
|
||||||
|
return <Trans>Push notifications are not enabled on this CommaFeed instance.</Trans>
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<form onSubmit={form.onSubmit(handleSubmit)}>
|
||||||
|
<Stack>
|
||||||
|
{sendTestPushNotification.status === "success" && (
|
||||||
|
<Alert level="success" messages={[_(msg`Test notification sent successfully.`)]} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
{sendTestPushNotification.status === "error" && (
|
||||||
|
<Alert level="error" messages={errorToStrings(sendTestPushNotification.error)} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Select
|
||||||
|
label={<Trans>Push notification service</Trans>}
|
||||||
|
description={
|
||||||
|
<Trans>
|
||||||
|
Receive push notifications when new feed entries are discovered. Enable "Receive push notifications" in the
|
||||||
|
settings of each feed for which you want to receive notifications.
|
||||||
|
</Trans>
|
||||||
|
}
|
||||||
|
data={[
|
||||||
|
{ value: "ntfy", label: "ntfy" },
|
||||||
|
{ value: "gotify", label: "Gotify" },
|
||||||
|
{ value: "pushover", label: "Pushover" },
|
||||||
|
]}
|
||||||
|
clearable
|
||||||
|
{...typeInputProps}
|
||||||
|
onChange={value => {
|
||||||
|
typeInputProps.onChange(value)
|
||||||
|
form.setFieldValue("serverUrl", "")
|
||||||
|
form.setFieldValue("topic", "")
|
||||||
|
form.setFieldValue("userSecret", "")
|
||||||
|
form.setFieldValue("userId", "")
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{form.values.type === "ntfy" && (
|
||||||
|
<>
|
||||||
|
<TextInput
|
||||||
|
label={<Trans>Server URL</Trans>}
|
||||||
|
placeholder="https://ntfy.sh"
|
||||||
|
required
|
||||||
|
{...form.getInputProps("serverUrl")}
|
||||||
|
/>
|
||||||
|
<TextInput label={<Trans>Topic</Trans>} placeholder="commafeed" required {...form.getInputProps("topic")} />
|
||||||
|
<TextInput label={<Trans>Access token</Trans>} {...form.getInputProps("userSecret")} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{form.values.type === "gotify" && (
|
||||||
|
<>
|
||||||
|
<TextInput
|
||||||
|
label={<Trans>Server URL</Trans>}
|
||||||
|
placeholder="https://gotify.example.com"
|
||||||
|
required
|
||||||
|
{...form.getInputProps("serverUrl")}
|
||||||
|
/>
|
||||||
|
<TextInput label={<Trans>App token</Trans>} required {...form.getInputProps("userSecret")} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{form.values.type === "pushover" && (
|
||||||
|
<>
|
||||||
|
<TextInput label={<Trans>User key</Trans>} required {...form.getInputProps("userId")} />
|
||||||
|
<TextInput label={<Trans>API token</Trans>} required {...form.getInputProps("userSecret")} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Group>
|
||||||
|
<Button variant="default" onClick={async () => await dispatch(redirectToSelectedSource())}>
|
||||||
|
<Trans>Cancel</Trans>
|
||||||
|
</Button>
|
||||||
|
<Button type="submit" leftSection={<TbDeviceFloppy size={16} />}>
|
||||||
|
<Trans>Save</Trans>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Divider orientation="vertical" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
leftSection={<TbSend size={16} />}
|
||||||
|
onClick={() => sendTestPushNotification.execute(form.values)}
|
||||||
|
loading={sendTestPushNotification.loading}
|
||||||
|
>
|
||||||
|
<Trans>Test</Trans>
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -95,6 +95,7 @@ export function Tree() {
|
|||||||
expanded={false}
|
expanded={false}
|
||||||
level={0}
|
level={0}
|
||||||
hasError={false}
|
hasError={false}
|
||||||
|
hasWarning={false}
|
||||||
onClick={categoryClicked}
|
onClick={categoryClicked}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
@@ -110,6 +111,7 @@ export function Tree() {
|
|||||||
expanded={false}
|
expanded={false}
|
||||||
level={0}
|
level={0}
|
||||||
hasError={false}
|
hasError={false}
|
||||||
|
hasWarning={false}
|
||||||
onClick={categoryClicked}
|
onClick={categoryClicked}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
@@ -118,6 +120,7 @@ export function Tree() {
|
|||||||
if (!isCategoryDisplayed(category)) return null
|
if (!isCategoryDisplayed(category)) return null
|
||||||
|
|
||||||
const hasError = !category.expanded && flattenCategoryTree(category).some(c => c.feeds.some(f => f.errorCount > errorThreshold))
|
const hasError = !category.expanded && flattenCategoryTree(category).some(c => c.feeds.some(f => f.errorCount > errorThreshold))
|
||||||
|
const hasWarning = !category.expanded && flattenCategoryTree(category).some(c => c.feeds.some(f => !!f.filterLegacy))
|
||||||
return (
|
return (
|
||||||
<TreeNode
|
<TreeNode
|
||||||
id={category.id}
|
id={category.id}
|
||||||
@@ -130,6 +133,7 @@ export function Tree() {
|
|||||||
expanded={category.expanded}
|
expanded={category.expanded}
|
||||||
level={level}
|
level={level}
|
||||||
hasError={hasError}
|
hasError={hasError}
|
||||||
|
hasWarning={hasWarning}
|
||||||
onClick={categoryClicked}
|
onClick={categoryClicked}
|
||||||
onIconClick={e => categoryIconClicked(e, category)}
|
onIconClick={e => categoryIconClicked(e, category)}
|
||||||
key={category.id}
|
key={category.id}
|
||||||
@@ -151,6 +155,7 @@ export function Tree() {
|
|||||||
selected={source.type === "feed" && source.id === String(feed.id)}
|
selected={source.type === "feed" && source.id === String(feed.id)}
|
||||||
level={level}
|
level={level}
|
||||||
hasError={feed.errorCount > errorThreshold}
|
hasError={feed.errorCount > errorThreshold}
|
||||||
|
hasWarning={!!feed.filterLegacy}
|
||||||
onClick={feedClicked}
|
onClick={feedClicked}
|
||||||
key={feed.id}
|
key={feed.id}
|
||||||
/>
|
/>
|
||||||
@@ -168,6 +173,7 @@ export function Tree() {
|
|||||||
selected={source.type === "tag" && source.id === tag}
|
selected={source.type === "tag" && source.id === tag}
|
||||||
level={0}
|
level={0}
|
||||||
hasError={false}
|
hasError={false}
|
||||||
|
hasWarning={false}
|
||||||
onClick={tagClicked}
|
onClick={tagClicked}
|
||||||
key={tag}
|
key={tag}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ interface TreeNodeProps {
|
|||||||
expanded?: boolean
|
expanded?: boolean
|
||||||
level: number
|
level: number
|
||||||
hasError: boolean
|
hasError: boolean
|
||||||
|
hasWarning: boolean
|
||||||
hasNewEntries: boolean
|
hasNewEntries: boolean
|
||||||
onClick: (e: React.MouseEvent, id: string) => void
|
onClick: (e: React.MouseEvent, id: string) => void
|
||||||
onIconClick?: (e: React.MouseEvent, id: string) => void
|
onIconClick?: (e: React.MouseEvent, id: string) => void
|
||||||
@@ -24,15 +25,18 @@ const useStyles = tss
|
|||||||
.withParams<{
|
.withParams<{
|
||||||
selected: boolean
|
selected: boolean
|
||||||
hasError: boolean
|
hasError: boolean
|
||||||
|
hasWarning: boolean
|
||||||
hasUnread: boolean
|
hasUnread: boolean
|
||||||
}>()
|
}>()
|
||||||
.create(({ theme, colorScheme, selected, hasError, hasUnread }) => {
|
.create(({ theme, colorScheme, selected, hasError, hasWarning, hasUnread }) => {
|
||||||
let backgroundColor = "inherit"
|
let backgroundColor = "inherit"
|
||||||
if (selected) backgroundColor = colorScheme === "dark" ? theme.colors.dark[4] : theme.colors.gray[1]
|
if (selected) backgroundColor = colorScheme === "dark" ? theme.colors.dark[4] : theme.colors.gray[1]
|
||||||
|
|
||||||
let color: string
|
let color: string
|
||||||
if (hasError) {
|
if (hasError) {
|
||||||
color = theme.colors.red[6]
|
color = theme.colors.red[6]
|
||||||
|
} else if (hasWarning) {
|
||||||
|
color = theme.colors.yellow[6]
|
||||||
} else if (colorScheme === "dark") {
|
} else if (colorScheme === "dark") {
|
||||||
color = hasUnread ? theme.colors.dark[0] : theme.colors.dark[3]
|
color = hasUnread ? theme.colors.dark[0] : theme.colors.dark[3]
|
||||||
} else {
|
} else {
|
||||||
@@ -63,6 +67,7 @@ export function TreeNode(props: Readonly<TreeNodeProps>) {
|
|||||||
const { classes } = useStyles({
|
const { classes } = useStyles({
|
||||||
selected: props.selected,
|
selected: props.selected,
|
||||||
hasError: props.hasError,
|
hasError: props.hasError,
|
||||||
|
hasWarning: props.hasWarning,
|
||||||
hasUnread: props.unread > 0,
|
hasUnread: props.unread > 0,
|
||||||
})
|
})
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -6,7 +6,11 @@ const useStyles = tss.create(() => ({
|
|||||||
badge: {
|
badge: {
|
||||||
width: "3.2rem",
|
width: "3.2rem",
|
||||||
// for some reason, mantine Badge has "cursor: 'default'"
|
// for some reason, mantine Badge has "cursor: 'default'"
|
||||||
cursor: "pointer",
|
cursor: "inherit",
|
||||||
|
},
|
||||||
|
indicator: {
|
||||||
|
// ensure the indicator is not shown above the app header
|
||||||
|
zIndex: 0,
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
@@ -23,7 +27,15 @@ export function UnreadCount(
|
|||||||
const count = props.unreadCount >= 10000 ? "10k+" : props.unreadCount
|
const count = props.unreadCount >= 10000 ? "10k+" : props.unreadCount
|
||||||
return (
|
return (
|
||||||
<Tooltip label={props.unreadCount} disabled={props.unreadCount === count} openDelay={Constants.tooltip.delay}>
|
<Tooltip label={props.unreadCount} disabled={props.unreadCount === count} openDelay={Constants.tooltip.delay}>
|
||||||
<Indicator disabled={!props.showIndicator} size={4} offset={10} position="middle-start">
|
<Indicator
|
||||||
|
disabled={!props.showIndicator}
|
||||||
|
size={4}
|
||||||
|
offset={10}
|
||||||
|
position="middle-start"
|
||||||
|
classNames={{
|
||||||
|
indicator: classes.indicator,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Badge className={`${classes.badge} cf-badge`} variant="light" fullWidth>
|
<Badge className={`${classes.badge} cf-badge`} variant="light" fullWidth>
|
||||||
{count}
|
{count}
|
||||||
</Badge>
|
</Badge>
|
||||||
|
|||||||
17
commafeed-client/src/hooks/useValidationRules.ts
Normal file
17
commafeed-client/src/hooks/useValidationRules.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { msg } from "@lingui/core/macro"
|
||||||
|
import { useLingui } from "@lingui/react"
|
||||||
|
import { useAppSelector } from "@/app/store"
|
||||||
|
|
||||||
|
export function useValidationRules() {
|
||||||
|
const minimumPasswordLength = useAppSelector(state => state.server.serverInfos?.minimumPasswordLength)
|
||||||
|
const { _ } = useLingui()
|
||||||
|
|
||||||
|
return {
|
||||||
|
password: (value: string | undefined) =>
|
||||||
|
value && minimumPasswordLength && value.length < minimumPasswordLength
|
||||||
|
? _(msg`Password must be at least ${minimumPasswordLength} characters`)
|
||||||
|
: null,
|
||||||
|
passwordConfirmation: (newPasswordConfirmation: string | undefined, newPassword: string | undefined) =>
|
||||||
|
newPasswordConfirmation && newPasswordConfirmation !== newPassword ? _(msg`Passwords do not match`) : null,
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -17,10 +17,6 @@ msgstr ""
|
|||||||
msgid "<0>CommaFeed is an open-source project. Sources are hosted on </0><1>GitHub</1>."
|
msgid "<0>CommaFeed is an open-source project. Sources are hosted on </0><1>GitHub</1>."
|
||||||
msgstr "<0>CommaFeed és un projecte de codi obert. El codi font està allotjat a </0><1>GitHub</1>."
|
msgstr "<0>CommaFeed és un projecte de codi obert. El codi font està allotjat a </0><1>GitHub</1>."
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "<0>Complete syntax is available </0><1>here</1><2>.</2>"
|
|
||||||
msgstr "<0>La sintaxi completa està disponible </0><1>aquí</1><2>.</2>"
|
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "<0>Have an account?</0><1>Log in!</1>"
|
msgid "<0>Have an account?</0><1>Log in!</1>"
|
||||||
msgstr "<0>Teniu un compte?</0><1>Inicieu la sessió!</1>"
|
msgstr "<0>Teniu un compte?</0><1>Inicieu la sessió!</1>"
|
||||||
@@ -33,18 +29,22 @@ 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/pages/app/AboutPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Sobre"
|
msgstr "Sobre"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Access token"
|
||||||
|
msgstr "Token d'accés"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Actions"
|
msgid "Actions"
|
||||||
msgstr "Accions"
|
msgstr "Accions"
|
||||||
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
msgid "Add"
|
msgid "Add"
|
||||||
msgstr "Afegir"
|
msgstr "Afegeix"
|
||||||
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
msgid "Add category"
|
msgid "Add category"
|
||||||
@@ -54,17 +54,22 @@ msgstr "Afegeix categoria"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Afegeix usuari"
|
msgstr "Afegeix usuari"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Administrador"
|
msgstr "Administrador"
|
||||||
|
|
||||||
#: src/pages/app/FeedEntriesPage.tsx
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
msgid "Admin user name"
|
||||||
#: src/components/header/Header.tsx
|
msgstr "Nom d'usuari de l'administrador"
|
||||||
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedEntriesPage.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Tot"
|
msgstr "Tot"
|
||||||
|
|
||||||
@@ -83,7 +88,7 @@ msgstr "Un fitxer opml és un fitxer XML que conté URL i categories de canals.
|
|||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Analyze feed"
|
msgid "Analyze feed"
|
||||||
msgstr "Analitzar el feed"
|
msgstr "Analitza el canal"
|
||||||
|
|
||||||
#: src/components/AnnouncementDialog.tsx
|
#: src/components/AnnouncementDialog.tsx
|
||||||
msgid "Announcement"
|
msgid "Announcement"
|
||||||
@@ -91,11 +96,19 @@ msgstr "Anunci"
|
|||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "API key"
|
msgid "API key"
|
||||||
msgstr "clau API"
|
msgstr "Clau API"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "API token"
|
||||||
|
msgstr "Token d'API"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "App token"
|
||||||
|
msgstr "Token d'aplicació"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Are you sure you want to delete category <0>{categoryName}</0>?"
|
msgid "Are you sure you want to delete category <0>{categoryName}</0>?"
|
||||||
msgstr "Estàs segur que vols suprimir la categoria <0>{categoryName}</0>?"
|
msgstr "Esteu segur que voleu suprimir la categoria <0>{categoryName}</0>?"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Are you sure you want to delete user <0>{userName}</0> ?"
|
msgid "Are you sure you want to delete user <0>{userName}</0> ?"
|
||||||
@@ -115,61 +128,67 @@ msgstr "Esteu segur que voleu marcar les entrades més antigues de {threshold} d
|
|||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Are you sure you want to unsubscribe from <0>{feedName}</0>?"
|
msgid "Are you sure you want to unsubscribe from <0>{feedName}</0>?"
|
||||||
msgstr "Estàs segur que vols cancel·lar la subscripció a <0>{feedName}</0>?"
|
msgstr "Esteu segur que voleu cancel·lar la subscripció a <0>{feedName}</0>?"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
msgid "Asc"
|
msgid "Asc"
|
||||||
msgstr "Asc"
|
msgstr "Asc"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Available variables are 'title', 'content', 'url' 'author' and 'categories' and their content is converted to lower case to ease string comparison."
|
msgid "Auto-mark as read"
|
||||||
msgstr "Les variables disponibles són \"títol\", \"contingut\", \"url\" \"autor\" i \"categories\" i el seu contingut es converteix en minúscules per facilitar la comparació de cadenes."
|
msgstr "Marcar com a llegit automàticament"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Back"
|
msgid "Back"
|
||||||
msgstr "Enrere"
|
msgstr "Enrere"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Tornar a iniciar sessió"
|
msgstr "Torna a iniciar sessió"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Blue"
|
msgid "Blue"
|
||||||
msgstr "Blau"
|
msgstr "Blau"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "Browser extension"
|
||||||
|
msgstr "Extensió del navegador"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Browser extension required for Chrome"
|
msgid "Browser extension required for Chrome"
|
||||||
msgstr "Extensió del navegador necessària per a Chrome"
|
msgstr "Extensió del navegador necessària per a Chrome"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
msgid "Browser extention"
|
|
||||||
msgstr "Extensió del navegador"
|
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr "Pestanya del navegador"
|
msgstr "Pestanya del navegador"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
msgid "Build a filter expression to indicate what you want to read. Entries that don't match will be marked as read automatically."
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
msgstr "Creeu una expressió de filtratge per indicar què voleu llegir. Les entrades que no coincideixin es marcaran com a llegides automàticament."
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.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
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Cancel·la"
|
msgstr "Cancel·la"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Categoria"
|
msgstr "Categoria"
|
||||||
|
|
||||||
@@ -209,11 +228,11 @@ msgstr "CommaFeed versió {version} ({version})."
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Compacte"
|
msgstr "Compacte"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Confirma"
|
msgstr "Confirma"
|
||||||
|
|
||||||
@@ -221,10 +240,19 @@ msgstr "Confirma"
|
|||||||
msgid "Confirm password"
|
msgid "Confirm password"
|
||||||
msgstr "Confirmeu la contrasenya"
|
msgstr "Confirmeu la contrasenya"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Confirm Password"
|
||||||
|
msgstr "Confirma la contrasenya"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Cozy"
|
msgid "Cozy"
|
||||||
msgstr "Acollidor"
|
msgstr "Acollidor"
|
||||||
|
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Create Admin Account"
|
||||||
|
msgstr "Crea un compte d'administrador"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Ctrl"
|
msgid "Ctrl"
|
||||||
msgstr "Ctrl"
|
msgstr "Ctrl"
|
||||||
@@ -249,8 +277,8 @@ msgstr "Codi JS personalitzat que s'executarà en carregar la pàgina"
|
|||||||
msgid "Cyan"
|
msgid "Cyan"
|
||||||
msgstr "Cian"
|
msgstr "Cian"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Dark"
|
msgid "Dark"
|
||||||
msgstr "Fosc"
|
msgstr "Fosc"
|
||||||
|
|
||||||
@@ -258,6 +286,10 @@ msgstr "Fosc"
|
|||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Data de creació"
|
msgstr "Data de creació"
|
||||||
|
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "days"
|
||||||
|
msgstr "dies"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Eliminar"
|
msgstr "Eliminar"
|
||||||
@@ -283,14 +315,18 @@ msgstr "Desc"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr "Detallat"
|
msgstr "Detallat"
|
||||||
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
msgid "Disable \"Pull to refresh\" browser behavior"
|
||||||
|
msgstr "Desactiva el comportament \"Arrossega per actualitzar\"\\ del navegador"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Mostra"
|
msgstr "Mostra"
|
||||||
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/app/DonatePage.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr "Donar"
|
msgstr "Donar"
|
||||||
|
|
||||||
@@ -302,11 +338,13 @@ 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/pages/auth/PasswordRecoveryPage.tsx
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "Correu electrònic"
|
msgstr "Correu electrònic"
|
||||||
|
|
||||||
@@ -319,10 +357,10 @@ msgstr "Adreça de correu electrònic"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Edita l'usuari"
|
msgstr "Edita l'usuari"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "activat"
|
msgstr "Activat"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Enter"
|
msgid "Enter"
|
||||||
@@ -344,10 +382,6 @@ msgstr "Encapçalaments d'entrada"
|
|||||||
msgid "Error"
|
msgid "Error"
|
||||||
msgstr "Error"
|
msgstr "Error"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "Example: {example}."
|
|
||||||
msgstr "Exemple: {exemple}."
|
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Expanded"
|
msgid "Expanded"
|
||||||
msgstr "Ampliat"
|
msgstr "Ampliat"
|
||||||
@@ -356,8 +390,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/pages/WelcomePage.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/pages/WelcomePage.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr "Opcions de l'extensió"
|
msgstr "Opcions de l'extensió"
|
||||||
|
|
||||||
@@ -365,9 +399,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"
|
||||||
|
|
||||||
@@ -399,9 +433,9 @@ msgstr "La recuperació forçada de feeds encara no està disponible."
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Heu oblidat la contrasenya?"
|
msgstr "Heu oblidat la contrasenya?"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.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."
|
||||||
|
|
||||||
@@ -409,9 +443,9 @@ 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/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "URL del feed generat"
|
msgstr "URL del feed generat"
|
||||||
|
|
||||||
@@ -430,7 +464,7 @@ msgstr "Vés a la documentació de l'API."
|
|||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Goodies"
|
msgid "Goodies"
|
||||||
msgstr "Bones"
|
msgstr "Extres"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Grape"
|
msgid "Grape"
|
||||||
@@ -448,10 +482,6 @@ msgstr "Verd"
|
|||||||
msgid "Id"
|
msgid "Id"
|
||||||
msgstr "Id"
|
msgstr "Id"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
|
|
||||||
msgstr "Si no està buida, una expressió que s'avalua com a \"vertader\" o \"fals\". "
|
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "If the entry doesn't entirely fit on the screen"
|
msgid "If the entry doesn't entirely fit on the screen"
|
||||||
msgstr "Si l'entrada no encaixa del tot a la pantalla"
|
msgstr "Si l'entrada no encaixa del tot a la pantalla"
|
||||||
@@ -472,13 +502,21 @@ msgstr "En la vista ampliada, en desplaçar-se per les entrades, es marquen com
|
|||||||
msgid "Indigo"
|
msgid "Indigo"
|
||||||
msgstr "Indi"
|
msgstr "Indi"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Initial Setup"
|
||||||
|
msgstr "Configuració inicial"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Invalid password reset link. Please request a new one."
|
||||||
|
msgstr "L'enllaç de restabliment de la contrasenya no és vàlid. Sol·liciteu-ne un de nou."
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Mantenir sense llegir"
|
msgstr "Mantenir sense llegir"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
#: src/components/content/FeedEntries.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Dreceres de teclat"
|
msgstr "Dreceres de teclat"
|
||||||
|
|
||||||
@@ -506,9 +544,9 @@ msgstr "Clar"
|
|||||||
msgid "Lime"
|
msgid "Lime"
|
||||||
msgstr "Llima"
|
msgstr "Llima"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "Enllaç"
|
msgstr "Enllaç"
|
||||||
|
|
||||||
@@ -532,9 +570,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ó"
|
||||||
|
|
||||||
@@ -546,8 +584,8 @@ msgstr "Tanca sessió"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr "Prem llargament la tecla"
|
msgstr "Prem llargament la tecla"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Gestionar usuaris"
|
msgstr "Gestionar usuaris"
|
||||||
|
|
||||||
@@ -555,21 +593,25 @@ 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/MarkAllAsReadConfirmationDialog.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/MarkAllAsReadConfirmationDialog.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/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Marca com a llegit"
|
msgstr "Marca com a llegit"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.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í"
|
||||||
|
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "Mark entries in this feed as read after this number of days. Leave empty to disable."
|
||||||
|
msgstr "Marca les entrades d'aquest feed com a llegides després d'aquest nombre de dies. Deixeu-ho buit per desactivar-lo."
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Metrics"
|
msgid "Metrics"
|
||||||
msgstr "mètriques"
|
msgstr "mètriques"
|
||||||
@@ -586,15 +628,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/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/components/RelativeDate.tsx
|
#: src/components/RelativeDate.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr "No es coneix"
|
msgstr "No es coneix"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nom"
|
msgstr "Nom"
|
||||||
|
|
||||||
@@ -615,12 +657,17 @@ msgstr "Mai"
|
|||||||
msgid "New password"
|
msgid "New password"
|
||||||
msgstr "Contrasenya nova"
|
msgstr "Contrasenya nova"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "New Password"
|
||||||
|
msgstr "Contrasenya nova"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "El més nou primer"
|
msgstr "El més nou primer"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Següent"
|
msgstr "Següent"
|
||||||
|
|
||||||
@@ -650,7 +697,7 @@ msgstr "el més vell primer"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "On desktop"
|
msgid "On desktop"
|
||||||
msgstr "A l'scriptori"
|
msgstr "A l'escriptori"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "On mobile"
|
msgid "On mobile"
|
||||||
@@ -742,19 +789,25 @@ 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/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.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"
|
||||||
|
|
||||||
|
#: src/hooks/useValidationRules.ts
|
||||||
|
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||||
|
msgstr "La contrasenya ha de tenir almenys {minimumPasswordLength} caràcters"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "Password Recovery"
|
msgid "Password Recovery"
|
||||||
msgstr "Recuperació de contrasenya"
|
msgstr "Recuperació de contrasenya"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/hooks/useValidationRules.ts
|
||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Les contrasenyes no coincideixen"
|
msgstr "Les contrasenyes no coincideixen"
|
||||||
|
|
||||||
@@ -762,8 +815,8 @@ msgstr "Les contrasenyes no coincideixen"
|
|||||||
msgid "Pink"
|
msgid "Pink"
|
||||||
msgstr "Rosa"
|
msgstr "Rosa"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Posició"
|
msgstr "Posició"
|
||||||
|
|
||||||
@@ -779,6 +832,31 @@ msgstr "Color primari"
|
|||||||
msgid "Profile"
|
msgid "Profile"
|
||||||
msgstr "Perfil"
|
msgstr "Perfil"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Push notification service"
|
||||||
|
msgstr "Servei de notificacions push"
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Push notifications"
|
||||||
|
msgstr "Notificacions push"
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
msgid "Push notifications are not configured in your user settings."
|
||||||
|
msgstr "Les notificacions push no estan configurades a la vostra configuració d'usuari."
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Push notifications are not enabled on this CommaFeed instance."
|
||||||
|
msgstr "Les notificacions push no estan activades en aquesta instància de CommaFeed."
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
msgid "Receive push notifications"
|
||||||
|
msgstr "Rep notificacions push"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Receive push notifications when new feed entries are discovered. Enable \"Receive push notifications\" in the settings of each feed for which you want to receive notifications."
|
||||||
|
msgstr "Rebre notificacions push quan es descobreixin noves entrades de feed. Activeu \"Rep notificacions push\" a la configuració de cada feed per al qual vulgueu rebre notificacions."
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Recuperar la contrasenya"
|
msgstr "Recuperar la contrasenya"
|
||||||
@@ -787,8 +865,8 @@ msgstr "Recuperar la contrasenya"
|
|||||||
msgid "Red"
|
msgid "Red"
|
||||||
msgstr "Vermell"
|
msgstr "Vermell"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Actualitzar"
|
msgstr "Actualitzar"
|
||||||
|
|
||||||
@@ -796,6 +874,11 @@ msgstr "Actualitzar"
|
|||||||
msgid "Registrations are closed on this CommaFeed instance"
|
msgid "Registrations are closed on this CommaFeed instance"
|
||||||
msgstr "Els registres estan tancats en aquesta instància de CommaFeed"
|
msgstr "Els registres estan tancats en aquesta instància de CommaFeed"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Reset Password"
|
||||||
|
msgstr "Restableix la contrasenya"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "REST API"
|
msgid "REST API"
|
||||||
msgstr "API REST"
|
msgstr "API REST"
|
||||||
@@ -805,11 +888,12 @@ msgstr "API REST"
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr "Clic dret"
|
msgstr "Clic dret"
|
||||||
|
|
||||||
#: 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
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Desa"
|
msgstr "Desa"
|
||||||
|
|
||||||
@@ -825,17 +909,13 @@ msgstr "Desplaceu-vos suaument quan navegueu entre entrades"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr "Desplaçament"
|
msgstr "Desplaçament"
|
||||||
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Cerca"
|
msgstr "Cerca"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
msgid "Search requires at least 3 characters"
|
|
||||||
msgstr "La cerca requereix almenys 3 caràcters"
|
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Select next unread feed/category"
|
msgid "Select next unread feed/category"
|
||||||
msgstr "Selecciona el següent canal/categoria no llegit"
|
msgstr "Selecciona el següent canal/categoria no llegit"
|
||||||
@@ -844,6 +924,11 @@ msgstr "Selecciona el següent canal/categoria no llegit"
|
|||||||
msgid "Select previous unread feed/category"
|
msgid "Select previous unread feed/category"
|
||||||
msgstr "Selecciona el canal/categoria anterior sense llegir"
|
msgstr "Selecciona el canal/categoria anterior sense llegir"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Server URL"
|
||||||
|
msgstr "URL del servidor"
|
||||||
|
|
||||||
#: 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"
|
||||||
@@ -918,9 +1003,9 @@ msgstr "Mostra el recompte de no llegits a la icona de favorits de la pestanya"
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr "Mostra el recompte de no llegits al títol de la pestanya"
|
msgstr "Mostra el recompte de no llegits al títol de la pestanya"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
#: src/pages/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"
|
||||||
|
|
||||||
@@ -933,21 +1018,21 @@ msgstr "Acaba de passar una cosa dolenta..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Espai"
|
msgstr "Espai"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "Estrella"
|
msgstr "Estrella"
|
||||||
|
|
||||||
#: src/pages/app/FeedEntriesPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedEntriesPage.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"
|
||||||
|
|
||||||
@@ -988,6 +1073,14 @@ msgstr "Etiquetes"
|
|||||||
msgid "Teal"
|
msgid "Teal"
|
||||||
msgstr "Blau verdós"
|
msgstr "Blau verdós"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Test"
|
||||||
|
msgstr "Prova"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Test notification sent successfully."
|
||||||
|
msgstr "La notificació de prova s'ha enviat correctament."
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed will try to find the feed in the page."
|
msgid "The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed will try to find the feed in the page."
|
||||||
msgstr "l'URL del canal al qual us voleu subscriure. "
|
msgstr "l'URL del canal al qual us voleu subscriure. "
|
||||||
@@ -996,10 +1089,19 @@ msgstr "l'URL del canal al qual us voleu subscriure. "
|
|||||||
msgid "Theme"
|
msgid "Theme"
|
||||||
msgstr "Tema"
|
msgstr "Tema"
|
||||||
|
|
||||||
|
#. placeholder {0}: feed.filterLegacy
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "This feed has a legacy filter that cannot be edited and is not applied. Please recreate the filter using the new expression editor. The legacy filter expression was: <0>{0}</0>"
|
||||||
|
msgstr "Aquest feed té un filtre heretat que no es pot editar i no s'aplica. Torneu a crear el filtre amb el nou editor d'expressions. L'expressió del filtre heretat era: <0>{0}</0>"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||||
msgstr "Aquesta és la vostra clau de l'API. Es pot utilitzar per a algunes operacions de l'API de només lectura i permet accedir a l'API Fever. Utilitzeu el formulari de la part inferior de la pàgina per generar una nova clau d'API."
|
msgstr "Aquesta és la vostra clau de l'API. Es pot utilitzar per a algunes operacions de l'API de només lectura i permet accedir a l'API Fever. Utilitzeu el formulari de la part inferior de la pàgina per generar una nova clau d'API."
|
||||||
|
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||||
|
msgstr "Aquesta configuració pot causar problemes de desplaçament en alguns navegadors (per exemple, Safari)"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Canvia l'estat de lectura de l'entrada actual"
|
msgstr "Canvia l'estat de lectura de l'entrada actual"
|
||||||
@@ -1012,6 +1114,10 @@ msgstr "Canvia la barra lateral"
|
|||||||
msgid "Toggle starred status of current entry"
|
msgid "Toggle starred status of current entry"
|
||||||
msgstr "Commuta l'estat destacat de l'entrada actual"
|
msgstr "Commuta l'estat destacat de l'entrada actual"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Topic"
|
||||||
|
msgstr "Tema"
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Proveu CommaFeed amb el compte de demostració: demo/demo"
|
msgstr "Proveu CommaFeed amb el compte de demostració: demo/demo"
|
||||||
@@ -1024,8 +1130,8 @@ msgstr "Prova la demostració!"
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Sense llegir"
|
msgstr "Sense llegir"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "Desestrellar"
|
msgstr "Desestrellar"
|
||||||
@@ -1035,6 +1141,10 @@ msgstr "Desestrellar"
|
|||||||
msgid "Unsubscribe"
|
msgid "Unsubscribe"
|
||||||
msgstr "Donar-se de baixa"
|
msgstr "Donar-se de baixa"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "User key"
|
||||||
|
msgstr "Clau d'usuari"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "User name"
|
msgid "User name"
|
||||||
msgstr "Nom d'usuari"
|
msgstr "Nom d'usuari"
|
||||||
@@ -1056,6 +1166,10 @@ msgstr "Avís"
|
|||||||
msgid "Website"
|
msgid "Website"
|
||||||
msgstr "Lloc web"
|
msgstr "Lloc web"
|
||||||
|
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||||
|
msgstr "Benvingut! Sembla que aquesta és la primera vegada que executeu CommaFeed. Creeu un compte d'administrador per començar."
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Yellow"
|
msgid "Yellow"
|
||||||
msgstr "Groc"
|
msgstr "Groc"
|
||||||
@@ -1067,3 +1181,7 @@ msgstr "Encara no teniu cap subscripció. "
|
|||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Your feeds have been queued for refresh."
|
msgid "Your feeds have been queued for refresh."
|
||||||
msgstr "Els vostres feeds s'han posat a la cua per actualitzar-los."
|
msgstr "Els vostres feeds s'han posat a la cua per actualitzar-los."
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Your password has been changed. You can now log in with your new password."
|
||||||
|
msgstr "La vostra contrasenya s'ha canviat. Ara podeu iniciar la sessió amb la vostra nova contrasenya."
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -17,10 +17,6 @@ msgstr ""
|
|||||||
msgid "<0>CommaFeed is an open-source project. Sources are hosted on </0><1>GitHub</1>."
|
msgid "<0>CommaFeed is an open-source project. Sources are hosted on </0><1>GitHub</1>."
|
||||||
msgstr "<0>CommaFeed ist ein Open Source Projekt. Der Quellcode wird auf auf </0><1>GitHub</1> gehostet."
|
msgstr "<0>CommaFeed ist ein Open Source Projekt. Der Quellcode wird auf auf </0><1>GitHub</1> gehostet."
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "<0>Complete syntax is available </0><1>here</1><2>.</2>"
|
|
||||||
msgstr "<0>Die vollständige Syntax ist </0><1>hier</1> verfügbar<2>.</2>"
|
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "<0>Have an account?</0><1>Log in!</1>"
|
msgid "<0>Have an account?</0><1>Log in!</1>"
|
||||||
msgstr "<0>Haben Sie ein Konto?</0><1>Melden Sie sich an!</1>"
|
msgstr "<0>Haben Sie ein Konto?</0><1>Melden Sie sich an!</1>"
|
||||||
@@ -33,11 +29,15 @@ 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/pages/app/AboutPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Über"
|
msgstr "Über"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Access token"
|
||||||
|
msgstr "Zugriffstoken"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Actions"
|
msgid "Actions"
|
||||||
msgstr "Aktionen"
|
msgstr "Aktionen"
|
||||||
@@ -54,17 +54,22 @@ msgstr "Kategorie hinzufügen"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Benutzer hinzufügen"
|
msgstr "Benutzer hinzufügen"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Verwaltung"
|
msgstr "Verwaltung"
|
||||||
|
|
||||||
#: src/pages/app/FeedEntriesPage.tsx
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
msgid "Admin user name"
|
||||||
#: src/components/header/Header.tsx
|
msgstr "Administrator-Benutzername"
|
||||||
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedEntriesPage.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Alle"
|
msgstr "Alle"
|
||||||
|
|
||||||
@@ -93,6 +98,14 @@ msgstr "Ankündigung"
|
|||||||
msgid "API key"
|
msgid "API key"
|
||||||
msgstr "API-Schlüssel"
|
msgstr "API-Schlüssel"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "API token"
|
||||||
|
msgstr "API-Token"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "App token"
|
||||||
|
msgstr "App-Token"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Are you sure you want to delete category <0>{categoryName}</0>?"
|
msgid "Are you sure you want to delete category <0>{categoryName}</0>?"
|
||||||
msgstr "Sind Sie sicher, dass Sie die Kategorie <0>{categoryName}</0> löschen möchten?"
|
msgstr "Sind Sie sicher, dass Sie die Kategorie <0>{categoryName}</0> löschen möchten?"
|
||||||
@@ -122,54 +135,60 @@ msgid "Asc"
|
|||||||
msgstr "Aufsteigend"
|
msgstr "Aufsteigend"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Available variables are 'title', 'content', 'url' 'author' and 'categories' and their content is converted to lower case to ease string comparison."
|
msgid "Auto-mark as read"
|
||||||
msgstr "Verfügbare Variablen sind „Titel“, „Inhalt“, „URL“, „Autor“ und „Kategorien“, und ihr Inhalt wird in Kleinbuchstaben umgewandelt, um den String-Vergleich zu erleichtern."
|
msgstr "Automatisch als gelesen markieren"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Back"
|
msgid "Back"
|
||||||
msgstr "Zurück"
|
msgstr "Zurück"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Zurück zum Login"
|
msgstr "Zurück zum Login"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Blue"
|
msgid "Blue"
|
||||||
msgstr ""
|
msgstr "Blau"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "Browser extension"
|
||||||
|
msgstr "Browser-Erweiterung"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Browser extension required for Chrome"
|
msgid "Browser extension required for Chrome"
|
||||||
msgstr "Browser-Erweiterung für Chrome benötigt"
|
msgstr "Browser-Erweiterung für Chrome benötigt"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
msgid "Browser extention"
|
|
||||||
msgstr "Browser-Erweiterung"
|
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr "Browsertab"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
msgid "Build a filter expression to indicate what you want to read. Entries that don't match will be marked as read automatically."
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
msgstr "Erstellen Sie einen Filterausdruck, um anzugeben, was Sie lesen möchten. Einträge, die nicht übereinstimmen, werden automatisch als gelesen markiert."
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.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
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Abbrechen"
|
msgstr "Abbrechen"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Kategorie"
|
msgstr "Kategorie"
|
||||||
|
|
||||||
@@ -187,7 +206,7 @@ msgstr "Menü schließen"
|
|||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Cmd"
|
msgid "Cmd"
|
||||||
msgstr ""
|
msgstr "Befehl"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
@@ -209,11 +228,11 @@ msgstr "CommaFeed version {version} ({revision})."
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Kompakt"
|
msgstr "Kompakt"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Bestätigen"
|
msgstr "Bestätigen"
|
||||||
|
|
||||||
@@ -221,10 +240,19 @@ msgstr "Bestätigen"
|
|||||||
msgid "Confirm password"
|
msgid "Confirm password"
|
||||||
msgstr "Passwort bestätigen"
|
msgstr "Passwort bestätigen"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Confirm Password"
|
||||||
|
msgstr "Passwort bestätigen"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Cozy"
|
msgid "Cozy"
|
||||||
msgstr "Gemütlich"
|
msgstr "Gemütlich"
|
||||||
|
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Create Admin Account"
|
||||||
|
msgstr "Administrator-Konto erstellen"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Ctrl"
|
msgid "Ctrl"
|
||||||
msgstr "Strg"
|
msgstr "Strg"
|
||||||
@@ -247,10 +275,10 @@ msgstr "Einer JS Code der beim Laden der Seite ausgeführt wird"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Cyan"
|
msgid "Cyan"
|
||||||
msgstr ""
|
msgstr "Cyan"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Dark"
|
msgid "Dark"
|
||||||
msgstr "Dunkel"
|
msgstr "Dunkel"
|
||||||
|
|
||||||
@@ -258,6 +286,10 @@ msgstr "Dunkel"
|
|||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Erstellungsdatum"
|
msgstr "Erstellungsdatum"
|
||||||
|
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "days"
|
||||||
|
msgstr "Tage"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Löschen"
|
msgstr "Löschen"
|
||||||
@@ -283,14 +315,18 @@ msgstr "Beschr"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr "Detailliert"
|
msgstr "Detailliert"
|
||||||
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
msgid "Disable \"Pull to refresh\" browser behavior"
|
||||||
|
msgstr "Browser-Verhalten \"Zum Aktualisieren ziehen\" deaktivieren"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Anzeige"
|
msgstr "Anzeige"
|
||||||
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/app/DonatePage.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr "Spenden"
|
msgstr "Spenden"
|
||||||
|
|
||||||
@@ -302,11 +338,13 @@ 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/pages/auth/PasswordRecoveryPage.tsx
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "E-Mail"
|
msgstr "E-Mail"
|
||||||
|
|
||||||
@@ -319,8 +357,8 @@ msgstr "E-Mail-Adresse"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Benutzer bearbeiten"
|
msgstr "Benutzer bearbeiten"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Aktiviert"
|
msgstr "Aktiviert"
|
||||||
|
|
||||||
@@ -334,20 +372,16 @@ msgstr "Geben Sie Ihr aktuelles Passwort ein, um die Profileinstellungen zu änd
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Entries to keep above the selected entry when scrolling"
|
msgid "Entries to keep above the selected entry when scrolling"
|
||||||
msgstr ""
|
msgstr "Anzahl der Einträge, die beim Scrollen über dem ausgewählten Eintrag bleiben sollen"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Entry headers"
|
msgid "Entry headers"
|
||||||
msgstr ""
|
msgstr "Eintragsüberschriften"
|
||||||
|
|
||||||
#: src/components/Alert.tsx
|
#: src/components/Alert.tsx
|
||||||
msgid "Error"
|
msgid "Error"
|
||||||
msgstr "Fehler"
|
msgstr "Fehler"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "Example: {example}."
|
|
||||||
msgstr "Beispiel: {example}."
|
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Expanded"
|
msgid "Expanded"
|
||||||
msgstr "Erweitert"
|
msgstr "Erweitert"
|
||||||
@@ -356,8 +390,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/pages/WelcomePage.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/pages/WelcomePage.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr "Erweiterungsoptionen"
|
msgstr "Erweiterungsoptionen"
|
||||||
|
|
||||||
@@ -365,9 +399,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"
|
||||||
|
|
||||||
@@ -377,11 +411,11 @@ msgstr "Alle Feeds jetzt abrufen"
|
|||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "Fever API"
|
msgid "Fever API"
|
||||||
msgstr ""
|
msgstr "Fever-API"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "Fever API URL"
|
msgid "Fever API URL"
|
||||||
msgstr ""
|
msgstr "Fever-API-URL"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Filtering expression"
|
msgid "Filtering expression"
|
||||||
@@ -389,19 +423,19 @@ msgstr "Filterausdruck"
|
|||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Font size"
|
msgid "Font size"
|
||||||
msgstr ""
|
msgstr "Schriftgröße"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Force fetching feeds is not yet available."
|
msgid "Force fetching feeds is not yet available."
|
||||||
msgstr ""
|
msgstr "Das Erzwingen des Feed-Abrufs ist noch nicht verfügbar."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Passwort vergessen?"
|
msgstr "Passwort vergessen?"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.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."
|
||||||
|
|
||||||
@@ -409,9 +443,9 @@ 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/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "Generierte Feed-URL"
|
msgstr "Generierte Feed-URL"
|
||||||
|
|
||||||
@@ -434,23 +468,19 @@ msgstr "Goodies"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Grape"
|
msgid "Grape"
|
||||||
msgstr ""
|
msgstr "Traube"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Gray"
|
msgid "Gray"
|
||||||
msgstr ""
|
msgstr "Grau"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Green"
|
msgid "Green"
|
||||||
msgstr ""
|
msgstr "Grün"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Id"
|
msgid "Id"
|
||||||
msgstr ""
|
msgstr "ID"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
|
|
||||||
msgstr "Wenn nicht leer, ein Ausdruck, der als „wahr“ oder „falsch“ ausgewertet wird."
|
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "If the entry doesn't entirely fit on the screen"
|
msgid "If the entry doesn't entirely fit on the screen"
|
||||||
@@ -470,15 +500,23 @@ msgstr "In der erweiterten Ansicht werden Einträge beim Scrollen als gelesen ma
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Indigo"
|
msgid "Indigo"
|
||||||
msgstr ""
|
msgstr "Indigo"
|
||||||
|
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Initial Setup"
|
||||||
|
msgstr "Ersteinrichtung"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Invalid password reset link. Please request a new one."
|
||||||
|
msgstr "Ungültiger Link zum Zurücksetzen des Passworts. Bitte fordern Sie einen neuen an."
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Ungelesen lassen"
|
msgstr "Ungelesen lassen"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
#: src/components/content/FeedEntries.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Tastaturkürzel"
|
msgstr "Tastaturkürzel"
|
||||||
|
|
||||||
@@ -504,17 +542,17 @@ msgstr "Hell"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Lime"
|
msgid "Lime"
|
||||||
msgstr ""
|
msgstr "Limette"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "Verbindung"
|
msgstr "Verbindung"
|
||||||
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
msgid "Link to the documentation"
|
msgid "Link to the documentation"
|
||||||
msgstr ""
|
msgstr "Link zur Dokumentation"
|
||||||
|
|
||||||
#: src/hooks/useAppLoading.ts
|
#: src/hooks/useAppLoading.ts
|
||||||
msgid "Loading profile..."
|
msgid "Loading profile..."
|
||||||
@@ -532,9 +570,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"
|
||||||
|
|
||||||
@@ -546,8 +584,8 @@ msgstr "Abmelden"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr "Langer Tastendruck"
|
msgstr "Langer Tastendruck"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Benutzer verwalten"
|
msgstr "Benutzer verwalten"
|
||||||
|
|
||||||
@@ -555,21 +593,25 @@ 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/MarkAllAsReadConfirmationDialog.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/MarkAllAsReadConfirmationDialog.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/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Als gelesen markieren"
|
msgstr "Als gelesen markieren"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.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"
|
||||||
|
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "Mark entries in this feed as read after this number of days. Leave empty to disable."
|
||||||
|
msgstr "Markieren Sie Einträge in diesem Feed nach dieser Anzahl von Tagen als gelesen. Leer lassen zum Deaktivieren."
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Metrics"
|
msgid "Metrics"
|
||||||
msgstr "Metriken"
|
msgstr "Metriken"
|
||||||
@@ -586,17 +628,17 @@ 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/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/components/RelativeDate.tsx
|
#: src/components/RelativeDate.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr "n.v."
|
msgstr "n.v."
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr ""
|
msgstr "Name"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Navigate to a subscription by entering its name"
|
msgid "Navigate to a subscription by entering its name"
|
||||||
@@ -604,7 +646,7 @@ msgstr "Navigieren Sie zu einem Abonnement, indem Sie seinen Namen eingeben"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
|
msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
|
||||||
msgstr ""
|
msgstr "Navigieren Sie zum nächsten Feed/Kategorie mit ungelesenen Einträgen, wenn Sie alle Einträge als gelesen markieren"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
@@ -615,12 +657,17 @@ msgstr "Niemals"
|
|||||||
msgid "New password"
|
msgid "New password"
|
||||||
msgstr "Neues Passwort"
|
msgstr "Neues Passwort"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "New Password"
|
||||||
|
msgstr "Neues Passwort"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Neueste zuerst"
|
msgstr "Neueste zuerst"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Weiter"
|
msgstr "Weiter"
|
||||||
|
|
||||||
@@ -638,7 +685,7 @@ msgstr "Keine weiteren Einträge"
|
|||||||
|
|
||||||
#: src/components/content/ShareButtons.tsx
|
#: src/components/content/ShareButtons.tsx
|
||||||
msgid "No sharing options available."
|
msgid "No sharing options available."
|
||||||
msgstr ""
|
msgstr "Keine Optionen zum Teilen verfügbar."
|
||||||
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
msgid "Nothing found"
|
msgid "Nothing found"
|
||||||
@@ -650,11 +697,11 @@ msgstr "Älteste zuerst"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "On desktop"
|
msgid "On desktop"
|
||||||
msgstr ""
|
msgstr "Auf dem Desktop"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "On mobile"
|
msgid "On mobile"
|
||||||
msgstr ""
|
msgstr "Auf dem Handy"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "On mobile, show action buttons at the bottom of the screen"
|
msgid "On mobile, show action buttons at the bottom of the screen"
|
||||||
@@ -662,7 +709,7 @@ msgstr "Auf mobilen Geräten die Aktion-Buttons am unteren Ende des Bildschirms
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Only applies to compact, cozy and detailed modes"
|
msgid "Only applies to compact, cozy and detailed modes"
|
||||||
msgstr ""
|
msgstr "Gilt nur für die Modi Kompakt, Gemütlich und Detailliert"
|
||||||
|
|
||||||
#: src/pages/ErrorPage.tsx
|
#: src/pages/ErrorPage.tsx
|
||||||
msgid "Oops!"
|
msgid "Oops!"
|
||||||
@@ -711,7 +758,7 @@ msgstr "Aktuellen Eintrag öffnen/schließen"
|
|||||||
|
|
||||||
#: src/pages/app/AddPage.tsx
|
#: src/pages/app/AddPage.tsx
|
||||||
msgid "OPML"
|
msgid "OPML"
|
||||||
msgstr ""
|
msgstr "OPML"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "OPML export"
|
msgid "OPML export"
|
||||||
@@ -724,11 +771,11 @@ msgstr "OPML-Datei"
|
|||||||
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
msgid "OPML file is required"
|
msgid "OPML file is required"
|
||||||
msgstr ""
|
msgstr "OPML-Datei ist erforderlich"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Orange"
|
msgid "Orange"
|
||||||
msgstr ""
|
msgstr "Orange"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Order"
|
msgid "Order"
|
||||||
@@ -742,28 +789,34 @@ 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/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.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"
|
||||||
|
|
||||||
|
#: src/hooks/useValidationRules.ts
|
||||||
|
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||||
|
msgstr "Passwort muss mindestens {minimumPasswordLength} Zeichen lang sein"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "Password Recovery"
|
msgid "Password Recovery"
|
||||||
msgstr "Passwortwiederherstellung"
|
msgstr "Passwortwiederherstellung"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/hooks/useValidationRules.ts
|
||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Passwörter stimmen nicht überein"
|
msgstr "Passwörter stimmen nicht überein"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Pink"
|
msgid "Pink"
|
||||||
msgstr ""
|
msgstr "Rosa"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Position"
|
msgstr "Position"
|
||||||
|
|
||||||
@@ -773,22 +826,47 @@ msgstr "Vorheriges"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Primary color"
|
msgid "Primary color"
|
||||||
msgstr ""
|
msgstr "Primärfarbe"
|
||||||
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
msgid "Profile"
|
msgid "Profile"
|
||||||
msgstr "Profil"
|
msgstr "Profil"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Push notification service"
|
||||||
|
msgstr "Push-Benachrichtigungsdienst"
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Push notifications"
|
||||||
|
msgstr "Push-Benachrichtigungen"
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
msgid "Push notifications are not configured in your user settings."
|
||||||
|
msgstr "Push-Benachrichtigungen sind in Ihren Benutzereinstellungen nicht konfiguriert."
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Push notifications are not enabled on this CommaFeed instance."
|
||||||
|
msgstr "Push-Benachrichtigungen sind auf dieser CommaFeed-Instanz nicht aktiviert."
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
msgid "Receive push notifications"
|
||||||
|
msgstr "Push-Benachrichtigungen erhalten"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Receive push notifications when new feed entries are discovered. Enable \"Receive push notifications\" in the settings of each feed for which you want to receive notifications."
|
||||||
|
msgstr "Erhalten Sie Push-Benachrichtigungen, wenn neue Feed-Einträge entdeckt werden. Aktivieren Sie \"Push-Benachrichtigungen erhalten\" in den Einstellungen jedes Feeds, für den Sie Benachrichtigungen erhalten möchten."
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Kennwort wiederherstellen"
|
msgstr "Kennwort wiederherstellen"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Red"
|
msgid "Red"
|
||||||
msgstr ""
|
msgstr "Rot"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Aktualisieren"
|
msgstr "Aktualisieren"
|
||||||
|
|
||||||
@@ -796,6 +874,11 @@ msgstr "Aktualisieren"
|
|||||||
msgid "Registrations are closed on this CommaFeed instance"
|
msgid "Registrations are closed on this CommaFeed instance"
|
||||||
msgstr "Registrierungen sind für diese CommaFeed-Instanz geschlossen"
|
msgstr "Registrierungen sind für diese CommaFeed-Instanz geschlossen"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Reset Password"
|
||||||
|
msgstr "Passwort zurücksetzen"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "REST API"
|
msgid "REST API"
|
||||||
msgstr "REST-API"
|
msgstr "REST-API"
|
||||||
@@ -805,11 +888,12 @@ msgstr "REST-API"
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr "Rechtsklick"
|
msgstr "Rechtsklick"
|
||||||
|
|
||||||
#: 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
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Speichern"
|
msgstr "Speichern"
|
||||||
|
|
||||||
@@ -825,24 +909,25 @@ msgstr "Schnelles Scrollen beim Navigieren zwischen Einträgen"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr "Scrollen"
|
msgstr "Scrollen"
|
||||||
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Suche"
|
msgstr "Suche"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
msgid "Search requires at least 3 characters"
|
|
||||||
msgstr "Suche erfordert mindestens 3 Zeichen"
|
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Select next unread feed/category"
|
msgid "Select next unread feed/category"
|
||||||
msgstr ""
|
msgstr "Nächsten ungelesenen Feed/Kategorie auswählen"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Select previous unread feed/category"
|
msgid "Select previous unread feed/category"
|
||||||
msgstr ""
|
msgstr "Vorherigen ungelesenen Feed/Kategorie auswählen"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Server URL"
|
||||||
|
msgstr "Server-URL"
|
||||||
|
|
||||||
#: 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"
|
||||||
@@ -892,7 +977,7 @@ msgstr "Eintragsmenü anzeigen (Handy)"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Show external link icon"
|
msgid "Show external link icon"
|
||||||
msgstr ""
|
msgstr "Symbol für externen Link anzeigen"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Show feeds and categories with no unread entries"
|
msgid "Show feeds and categories with no unread entries"
|
||||||
@@ -908,19 +993,19 @@ msgstr "Natives Menü anzeigen (Desktop)"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Show star icon"
|
msgid "Show star icon"
|
||||||
msgstr ""
|
msgstr "Stern-Symbol anzeigen"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Show unread count in tab favicon"
|
msgid "Show unread count in tab favicon"
|
||||||
msgstr ""
|
msgstr "Anzahl ungelesener Nachrichten im Tab-Favicon anzeigen"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr ""
|
msgstr "Anzahl ungelesener Nachrichten im Tab-Titel anzeigen"
|
||||||
|
|
||||||
|
#: 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"
|
||||||
|
|
||||||
@@ -933,21 +1018,21 @@ msgstr "Etwas Schlimmes ist gerade passiert..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Raum"
|
msgstr "Raum"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "Stern"
|
msgstr "Stern"
|
||||||
|
|
||||||
#: src/pages/app/FeedEntriesPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedEntriesPage.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"
|
||||||
|
|
||||||
@@ -977,16 +1062,24 @@ msgstr "Zum Lightmode wechseln"
|
|||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "System"
|
msgid "System"
|
||||||
msgstr ""
|
msgstr "System"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
msgid "Tags"
|
msgid "Tags"
|
||||||
msgstr ""
|
msgstr "Tags"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Teal"
|
msgid "Teal"
|
||||||
msgstr ""
|
msgstr "Blaugrün"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Test"
|
||||||
|
msgstr "Test"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Test notification sent successfully."
|
||||||
|
msgstr "Testbenachrichtigung erfolgreich gesendet."
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed will try to find the feed in the page."
|
msgid "The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed will try to find the feed in the page."
|
||||||
@@ -996,10 +1089,19 @@ msgstr "Die URL für den Feed, den Sie abonnieren möchten. "
|
|||||||
msgid "Theme"
|
msgid "Theme"
|
||||||
msgstr "Thema"
|
msgstr "Thema"
|
||||||
|
|
||||||
|
#. placeholder {0}: feed.filterLegacy
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "This feed has a legacy filter that cannot be edited and is not applied. Please recreate the filter using the new expression editor. The legacy filter expression was: <0>{0}</0>"
|
||||||
|
msgstr "Dieser Feed verfügt über einen veralteten Filter, der nicht bearbeitet werden kann und nicht angewendet wird. Bitte erstellen Sie den Filter mit dem neuen Ausdruckseditor neu. Der veraltete Filterausdruck war: <0>{0}</0>"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||||
msgstr "Dies ist Ihr API-Schlüssel. Er kann für einige schreibgeschützte API-Vorgänge verwendet werden und ermöglicht den Zugriff auf die Fever-API. Verwenden Sie das Formular unten auf der Seite, um einen neuen API-Schlüssel zu generieren"
|
msgstr "Dies ist Ihr API-Schlüssel. Er kann für einige schreibgeschützte API-Vorgänge verwendet werden und ermöglicht den Zugriff auf die Fever-API. Verwenden Sie das Formular unten auf der Seite, um einen neuen API-Schlüssel zu generieren"
|
||||||
|
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||||
|
msgstr "Diese Einstellung kann auf einigen Browsern (z. B. Safari) zu Scrollproblemen führen"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Lesestatus des aktuellen Eintrags umschalten"
|
msgstr "Lesestatus des aktuellen Eintrags umschalten"
|
||||||
@@ -1012,6 +1114,10 @@ msgstr "Sidebar an- und ausschalten"
|
|||||||
msgid "Toggle starred status of current entry"
|
msgid "Toggle starred status of current entry"
|
||||||
msgstr "Markierungsstatus des aktuellen Eintrags ändern"
|
msgstr "Markierungsstatus des aktuellen Eintrags ändern"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Topic"
|
||||||
|
msgstr "Thema"
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Testen Sie CommaFeed mit dem Demokonto: demo/demo"
|
msgstr "Testen Sie CommaFeed mit dem Demokonto: demo/demo"
|
||||||
@@ -1024,8 +1130,8 @@ msgstr "Testen Sie die Demo!"
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Ungelesen"
|
msgstr "Ungelesen"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "Stern entfernen"
|
msgstr "Stern entfernen"
|
||||||
@@ -1035,6 +1141,10 @@ msgstr "Stern entfernen"
|
|||||||
msgid "Unsubscribe"
|
msgid "Unsubscribe"
|
||||||
msgstr "Abbestellen"
|
msgstr "Abbestellen"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "User key"
|
||||||
|
msgstr "Benutzerschlüssel"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "User name"
|
msgid "User name"
|
||||||
msgstr "Benutzername"
|
msgstr "Benutzername"
|
||||||
@@ -1046,7 +1156,7 @@ msgstr "Benutzername oder E-Mail"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Violet"
|
msgid "Violet"
|
||||||
msgstr ""
|
msgstr "Violett"
|
||||||
|
|
||||||
#: src/components/Alert.tsx
|
#: src/components/Alert.tsx
|
||||||
msgid "Warning"
|
msgid "Warning"
|
||||||
@@ -1056,9 +1166,13 @@ msgstr "Warnung"
|
|||||||
msgid "Website"
|
msgid "Website"
|
||||||
msgstr "Webseite"
|
msgstr "Webseite"
|
||||||
|
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||||
|
msgstr "Willkommen! Dies scheint das erste Mal zu sein, dass Sie CommaFeed ausführen. Bitte erstellen Sie ein Administrator-Konto, um zu beginnen."
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Yellow"
|
msgid "Yellow"
|
||||||
msgstr ""
|
msgstr "Gelb"
|
||||||
|
|
||||||
#: src/pages/app/FeedEntriesPage.tsx
|
#: src/pages/app/FeedEntriesPage.tsx
|
||||||
msgid "You don't have any subscriptions yet. Why not try adding one by clicking on the + sign at the top of the page?"
|
msgid "You don't have any subscriptions yet. Why not try adding one by clicking on the + sign at the top of the page?"
|
||||||
@@ -1067,3 +1181,7 @@ msgstr "Sie haben noch keine Abonnements."
|
|||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Your feeds have been queued for refresh."
|
msgid "Your feeds have been queued for refresh."
|
||||||
msgstr "Ihr Feed wurde für die Aktualisierung eingereiht."
|
msgstr "Ihr Feed wurde für die Aktualisierung eingereiht."
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Your password has been changed. You can now log in with your new password."
|
||||||
|
msgstr "Ihr Passwort wurde geändert. Sie können sich nun mit Ihrem neuen Passwort anmelden."
|
||||||
|
|||||||
@@ -17,10 +17,6 @@ msgstr ""
|
|||||||
msgid "<0>CommaFeed is an open-source project. Sources are hosted on </0><1>GitHub</1>."
|
msgid "<0>CommaFeed is an open-source project. Sources are hosted on </0><1>GitHub</1>."
|
||||||
msgstr "<0>CommaFeed is an open-source project. Sources are hosted on </0><1>GitHub</1>."
|
msgstr "<0>CommaFeed is an open-source project. Sources are hosted on </0><1>GitHub</1>."
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "<0>Complete syntax is available </0><1>here</1><2>.</2>"
|
|
||||||
msgstr "<0>Complete syntax is available </0><1>here</1><2>.</2>"
|
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "<0>Have an account?</0><1>Log in!</1>"
|
msgid "<0>Have an account?</0><1>Log in!</1>"
|
||||||
msgstr "<0>Have an account?</0><1>Log in!</1>"
|
msgstr "<0>Have an account?</0><1>Log in!</1>"
|
||||||
@@ -33,11 +29,15 @@ 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/pages/app/AboutPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "About"
|
msgstr "About"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Access token"
|
||||||
|
msgstr "Access token"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Actions"
|
msgid "Actions"
|
||||||
msgstr "Actions"
|
msgstr "Actions"
|
||||||
@@ -54,17 +54,22 @@ msgstr "Add category"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Add user"
|
msgstr "Add user"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Admin"
|
msgstr "Admin"
|
||||||
|
|
||||||
#: src/pages/app/FeedEntriesPage.tsx
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
msgid "Admin user name"
|
||||||
#: src/components/header/Header.tsx
|
msgstr "Admin user name"
|
||||||
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedEntriesPage.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "All"
|
msgstr "All"
|
||||||
|
|
||||||
@@ -93,6 +98,14 @@ msgstr "Announcement"
|
|||||||
msgid "API key"
|
msgid "API key"
|
||||||
msgstr "API key"
|
msgstr "API key"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "API token"
|
||||||
|
msgstr "API token"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "App token"
|
||||||
|
msgstr "App token"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Are you sure you want to delete category <0>{categoryName}</0>?"
|
msgid "Are you sure you want to delete category <0>{categoryName}</0>?"
|
||||||
msgstr "Are you sure you want to delete category <0>{categoryName}</0>?"
|
msgstr "Are you sure you want to delete category <0>{categoryName}</0>?"
|
||||||
@@ -122,14 +135,15 @@ msgid "Asc"
|
|||||||
msgstr "Asc"
|
msgstr "Asc"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Available variables are 'title', 'content', 'url' 'author' and 'categories' and their content is converted to lower case to ease string comparison."
|
msgid "Auto-mark as read"
|
||||||
msgstr "Available variables are 'title', 'content', 'url' 'author' and 'categories' and their content is converted to lower case to ease string comparison."
|
msgstr "Auto-mark as read"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Back"
|
msgid "Back"
|
||||||
msgstr "Back"
|
msgstr "Back"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Back to log in"
|
msgstr "Back to log in"
|
||||||
|
|
||||||
@@ -137,39 +151,44 @@ msgstr "Back to log in"
|
|||||||
msgid "Blue"
|
msgid "Blue"
|
||||||
msgstr "Blue"
|
msgstr "Blue"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "Browser extension"
|
||||||
|
msgstr "Browser extension"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Browser extension required for Chrome"
|
msgid "Browser extension required for Chrome"
|
||||||
msgstr "Browser extension required for Chrome"
|
msgstr "Browser extension required for Chrome"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
msgid "Browser extention"
|
|
||||||
msgstr "Browser extention"
|
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr "Browser tab"
|
msgstr "Browser tab"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
msgid "Build a filter expression to indicate what you want to read. Entries that don't match will be marked as read automatically."
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
msgstr "Build a filter expression to indicate what you want to read. Entries that don't match will be marked as read automatically."
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.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
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Cancel"
|
msgstr "Cancel"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Category"
|
msgstr "Category"
|
||||||
|
|
||||||
@@ -209,11 +228,11 @@ msgstr "CommaFeed version {version} ({revision})."
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Compact"
|
msgstr "Compact"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Confirm"
|
msgstr "Confirm"
|
||||||
|
|
||||||
@@ -221,10 +240,19 @@ msgstr "Confirm"
|
|||||||
msgid "Confirm password"
|
msgid "Confirm password"
|
||||||
msgstr "Confirm password"
|
msgstr "Confirm password"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Confirm Password"
|
||||||
|
msgstr "Confirm Password"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Cozy"
|
msgid "Cozy"
|
||||||
msgstr "Cozy"
|
msgstr "Cozy"
|
||||||
|
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Create Admin Account"
|
||||||
|
msgstr "Create Admin Account"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Ctrl"
|
msgid "Ctrl"
|
||||||
msgstr "Ctrl"
|
msgstr "Ctrl"
|
||||||
@@ -249,8 +277,8 @@ msgstr "Custom JS code that will be executed on page load"
|
|||||||
msgid "Cyan"
|
msgid "Cyan"
|
||||||
msgstr "Cyan"
|
msgstr "Cyan"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Dark"
|
msgid "Dark"
|
||||||
msgstr "Dark"
|
msgstr "Dark"
|
||||||
|
|
||||||
@@ -258,6 +286,10 @@ msgstr "Dark"
|
|||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Date created"
|
msgstr "Date created"
|
||||||
|
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "days"
|
||||||
|
msgstr "days"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Delete"
|
msgstr "Delete"
|
||||||
@@ -283,14 +315,18 @@ msgstr "Desc"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr "Detailed"
|
msgstr "Detailed"
|
||||||
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
msgid "Disable \"Pull to refresh\" browser behavior"
|
||||||
|
msgstr "Disable \"Pull to refresh\" browser behavior"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Display"
|
msgstr "Display"
|
||||||
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/app/DonatePage.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr "Donate"
|
msgstr "Donate"
|
||||||
|
|
||||||
@@ -302,11 +338,13 @@ 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/pages/auth/PasswordRecoveryPage.tsx
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "E-mail"
|
msgstr "E-mail"
|
||||||
|
|
||||||
@@ -319,8 +357,8 @@ msgstr "E-mail address"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Edit user"
|
msgstr "Edit user"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Enabled"
|
msgstr "Enabled"
|
||||||
|
|
||||||
@@ -344,10 +382,6 @@ msgstr "Entry headers"
|
|||||||
msgid "Error"
|
msgid "Error"
|
||||||
msgstr "Error"
|
msgstr "Error"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "Example: {example}."
|
|
||||||
msgstr "Example: {example}."
|
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Expanded"
|
msgid "Expanded"
|
||||||
msgstr "Expanded"
|
msgstr "Expanded"
|
||||||
@@ -356,8 +390,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/pages/WelcomePage.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/pages/WelcomePage.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr "Extension options"
|
msgstr "Extension options"
|
||||||
|
|
||||||
@@ -365,9 +399,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"
|
||||||
|
|
||||||
@@ -399,9 +433,9 @@ msgstr "Force fetching feeds is not yet available."
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Forgot password?"
|
msgstr "Forgot password?"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.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."
|
||||||
|
|
||||||
@@ -409,9 +443,9 @@ 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/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "Generated feed url"
|
msgstr "Generated feed url"
|
||||||
|
|
||||||
@@ -448,10 +482,6 @@ msgstr "Green"
|
|||||||
msgid "Id"
|
msgid "Id"
|
||||||
msgstr "Id"
|
msgstr "Id"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
|
|
||||||
msgstr "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
|
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "If the entry doesn't entirely fit on the screen"
|
msgid "If the entry doesn't entirely fit on the screen"
|
||||||
msgstr "If the entry doesn't entirely fit on the screen"
|
msgstr "If the entry doesn't entirely fit on the screen"
|
||||||
@@ -472,13 +502,21 @@ msgstr "In expanded view, scrolling through entries mark them as read"
|
|||||||
msgid "Indigo"
|
msgid "Indigo"
|
||||||
msgstr "Indigo"
|
msgstr "Indigo"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Initial Setup"
|
||||||
|
msgstr "Initial Setup"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Invalid password reset link. Please request a new one."
|
||||||
|
msgstr "Invalid password reset link. Please request a new one."
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Keep unread"
|
msgstr "Keep unread"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
#: src/components/content/FeedEntries.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Keyboard shortcuts"
|
msgstr "Keyboard shortcuts"
|
||||||
|
|
||||||
@@ -506,9 +544,9 @@ msgstr "Light"
|
|||||||
msgid "Lime"
|
msgid "Lime"
|
||||||
msgstr "Lime"
|
msgstr "Lime"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "Link"
|
msgstr "Link"
|
||||||
|
|
||||||
@@ -532,9 +570,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"
|
||||||
|
|
||||||
@@ -546,8 +584,8 @@ msgstr "Logout"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr "Long press"
|
msgstr "Long press"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Manage users"
|
msgstr "Manage users"
|
||||||
|
|
||||||
@@ -555,21 +593,25 @@ 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/MarkAllAsReadConfirmationDialog.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/MarkAllAsReadConfirmationDialog.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/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Mark as read"
|
msgstr "Mark as read"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.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"
|
||||||
|
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "Mark entries in this feed as read after this number of days. Leave empty to disable."
|
||||||
|
msgstr "Mark entries in this feed as read after this number of days. Leave empty to disable."
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Metrics"
|
msgid "Metrics"
|
||||||
msgstr "Metrics"
|
msgstr "Metrics"
|
||||||
@@ -586,15 +628,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/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/components/RelativeDate.tsx
|
#: src/components/RelativeDate.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr "N/A"
|
msgstr "N/A"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Name"
|
msgstr "Name"
|
||||||
|
|
||||||
@@ -615,12 +657,17 @@ msgstr "Never"
|
|||||||
msgid "New password"
|
msgid "New password"
|
||||||
msgstr "New password"
|
msgstr "New password"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "New Password"
|
||||||
|
msgstr "New Password"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Newest first"
|
msgstr "Newest first"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Next"
|
msgstr "Next"
|
||||||
|
|
||||||
@@ -742,19 +789,25 @@ 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/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.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"
|
||||||
|
|
||||||
|
#: src/hooks/useValidationRules.ts
|
||||||
|
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||||
|
msgstr "Password must be at least {minimumPasswordLength} characters"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "Password Recovery"
|
msgid "Password Recovery"
|
||||||
msgstr "Password Recovery"
|
msgstr "Password Recovery"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/hooks/useValidationRules.ts
|
||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Passwords do not match"
|
msgstr "Passwords do not match"
|
||||||
|
|
||||||
@@ -762,8 +815,8 @@ msgstr "Passwords do not match"
|
|||||||
msgid "Pink"
|
msgid "Pink"
|
||||||
msgstr "Pink"
|
msgstr "Pink"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Position"
|
msgstr "Position"
|
||||||
|
|
||||||
@@ -779,6 +832,31 @@ msgstr "Primary color"
|
|||||||
msgid "Profile"
|
msgid "Profile"
|
||||||
msgstr "Profile"
|
msgstr "Profile"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Push notification service"
|
||||||
|
msgstr "Push notification service"
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Push notifications"
|
||||||
|
msgstr "Push notifications"
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
msgid "Push notifications are not configured in your user settings."
|
||||||
|
msgstr "Push notifications are not configured in your user settings."
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Push notifications are not enabled on this CommaFeed instance."
|
||||||
|
msgstr "Push notifications are not enabled on this CommaFeed instance."
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
msgid "Receive push notifications"
|
||||||
|
msgstr "Receive push notifications"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Receive push notifications when new feed entries are discovered. Enable \"Receive push notifications\" in the settings of each feed for which you want to receive notifications."
|
||||||
|
msgstr "Receive push notifications when new feed entries are discovered. Enable \"Receive push notifications\" in the settings of each feed for which you want to receive notifications."
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Recover password"
|
msgstr "Recover password"
|
||||||
@@ -787,8 +865,8 @@ msgstr "Recover password"
|
|||||||
msgid "Red"
|
msgid "Red"
|
||||||
msgstr "Red"
|
msgstr "Red"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Refresh"
|
msgstr "Refresh"
|
||||||
|
|
||||||
@@ -796,6 +874,11 @@ msgstr "Refresh"
|
|||||||
msgid "Registrations are closed on this CommaFeed instance"
|
msgid "Registrations are closed on this CommaFeed instance"
|
||||||
msgstr "Registrations are closed on this CommaFeed instance"
|
msgstr "Registrations are closed on this CommaFeed instance"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Reset Password"
|
||||||
|
msgstr "Reset Password"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "REST API"
|
msgid "REST API"
|
||||||
msgstr "REST API"
|
msgstr "REST API"
|
||||||
@@ -805,11 +888,12 @@ msgstr "REST API"
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr "Right click"
|
msgstr "Right click"
|
||||||
|
|
||||||
#: 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
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Save"
|
msgstr "Save"
|
||||||
|
|
||||||
@@ -825,17 +909,13 @@ msgstr "Scroll smoothly when navigating between entries"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr "Scrolling"
|
msgstr "Scrolling"
|
||||||
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Search"
|
msgstr "Search"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
msgid "Search requires at least 3 characters"
|
|
||||||
msgstr "Search requires at least 3 characters"
|
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Select next unread feed/category"
|
msgid "Select next unread feed/category"
|
||||||
msgstr "Select next unread feed/category"
|
msgstr "Select next unread feed/category"
|
||||||
@@ -844,6 +924,11 @@ msgstr "Select next unread feed/category"
|
|||||||
msgid "Select previous unread feed/category"
|
msgid "Select previous unread feed/category"
|
||||||
msgstr "Select previous unread feed/category"
|
msgstr "Select previous unread feed/category"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Server URL"
|
||||||
|
msgstr "Server URL"
|
||||||
|
|
||||||
#: 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"
|
||||||
@@ -918,9 +1003,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"
|
||||||
|
|
||||||
@@ -933,21 +1018,21 @@ msgstr "Something bad just happened..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Space"
|
msgstr "Space"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "Star"
|
msgstr "Star"
|
||||||
|
|
||||||
#: src/pages/app/FeedEntriesPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedEntriesPage.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"
|
||||||
|
|
||||||
@@ -988,6 +1073,14 @@ msgstr "Tags"
|
|||||||
msgid "Teal"
|
msgid "Teal"
|
||||||
msgstr "Teal"
|
msgstr "Teal"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Test"
|
||||||
|
msgstr "Test"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Test notification sent successfully."
|
||||||
|
msgstr "Test notification sent successfully."
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed will try to find the feed in the page."
|
msgid "The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed will try to find the feed in the page."
|
||||||
msgstr "The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed will try to find the feed in the page."
|
msgstr "The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed will try to find the feed in the page."
|
||||||
@@ -996,10 +1089,19 @@ msgstr "The URL for the feed you want to subscribe to. You can also use the webs
|
|||||||
msgid "Theme"
|
msgid "Theme"
|
||||||
msgstr "Theme"
|
msgstr "Theme"
|
||||||
|
|
||||||
|
#. placeholder {0}: feed.filterLegacy
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "This feed has a legacy filter that cannot be edited and is not applied. Please recreate the filter using the new expression editor. The legacy filter expression was: <0>{0}</0>"
|
||||||
|
msgstr "This feed has a legacy filter that cannot be edited and is not applied. Please recreate the filter using the new expression editor. The legacy filter expression was: <0>{0}</0>"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||||
msgstr "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
msgstr "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||||
|
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||||
|
msgstr "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Toggle read status of current entry"
|
msgstr "Toggle read status of current entry"
|
||||||
@@ -1012,6 +1114,10 @@ msgstr "Toggle sidebar"
|
|||||||
msgid "Toggle starred status of current entry"
|
msgid "Toggle starred status of current entry"
|
||||||
msgstr "Toggle starred status of current entry"
|
msgstr "Toggle starred status of current entry"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Topic"
|
||||||
|
msgstr "Topic"
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Try out CommaFeed with the demo account: demo/demo"
|
msgstr "Try out CommaFeed with the demo account: demo/demo"
|
||||||
@@ -1024,8 +1130,8 @@ msgstr "Try the demo!"
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Unread"
|
msgstr "Unread"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "Unstar"
|
msgstr "Unstar"
|
||||||
@@ -1035,6 +1141,10 @@ msgstr "Unstar"
|
|||||||
msgid "Unsubscribe"
|
msgid "Unsubscribe"
|
||||||
msgstr "Unsubscribe"
|
msgstr "Unsubscribe"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "User key"
|
||||||
|
msgstr "User key"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "User name"
|
msgid "User name"
|
||||||
msgstr "User name"
|
msgstr "User name"
|
||||||
@@ -1056,6 +1166,10 @@ msgstr "Warning"
|
|||||||
msgid "Website"
|
msgid "Website"
|
||||||
msgstr "Website"
|
msgstr "Website"
|
||||||
|
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||||
|
msgstr "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Yellow"
|
msgid "Yellow"
|
||||||
msgstr "Yellow"
|
msgstr "Yellow"
|
||||||
@@ -1067,3 +1181,7 @@ msgstr "You don't have any subscriptions yet. Why not try adding one by clicking
|
|||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Your feeds have been queued for refresh."
|
msgid "Your feeds have been queued for refresh."
|
||||||
msgstr "Your feeds have been queued for refresh."
|
msgstr "Your feeds have been queued for refresh."
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Your password has been changed. You can now log in with your new password."
|
||||||
|
msgstr "Your password has been changed. You can now log in with your new password."
|
||||||
|
|||||||
@@ -18,10 +18,6 @@ msgstr ""
|
|||||||
msgid "<0>CommaFeed is an open-source project. Sources are hosted on </0><1>GitHub</1>."
|
msgid "<0>CommaFeed is an open-source project. Sources are hosted on </0><1>GitHub</1>."
|
||||||
msgstr "<0>CommaFeed es un proyecto de código abierto. El código fuente está hospedado en </0><1>GitHub</1>."
|
msgstr "<0>CommaFeed es un proyecto de código abierto. El código fuente está hospedado en </0><1>GitHub</1>."
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "<0>Complete syntax is available </0><1>here</1><2>.</2>"
|
|
||||||
msgstr "<0>La sintaxis completa está disponible </0><1>aquí</1><2>.</2>"
|
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "<0>Have an account?</0><1>Log in!</1>"
|
msgid "<0>Have an account?</0><1>Log in!</1>"
|
||||||
msgstr "<0>¿Tienes una cuenta?</0><1>¡Inicia sesión!</1>"
|
msgstr "<0>¿Tienes una cuenta?</0><1>¡Inicia sesión!</1>"
|
||||||
@@ -34,11 +30,15 @@ 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/pages/app/AboutPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Acerca de"
|
msgstr "Acerca de"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Access token"
|
||||||
|
msgstr "Token de acceso"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Actions"
|
msgid "Actions"
|
||||||
msgstr "Acciones"
|
msgstr "Acciones"
|
||||||
@@ -55,17 +55,22 @@ msgstr "Añadir categoría"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Añadir usuario"
|
msgstr "Añadir usuario"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Administrador"
|
msgstr "Administrador"
|
||||||
|
|
||||||
#: src/pages/app/FeedEntriesPage.tsx
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
msgid "Admin user name"
|
||||||
#: src/components/header/Header.tsx
|
msgstr "Nombre de usuario administrador"
|
||||||
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedEntriesPage.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Todo"
|
msgstr "Todo"
|
||||||
|
|
||||||
@@ -94,6 +99,14 @@ msgstr "Anuncio"
|
|||||||
msgid "API key"
|
msgid "API key"
|
||||||
msgstr "Clave API"
|
msgstr "Clave API"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "API token"
|
||||||
|
msgstr "Token de API"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "App token"
|
||||||
|
msgstr "Token de aplicación"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Are you sure you want to delete category <0>{categoryName}</0>?"
|
msgid "Are you sure you want to delete category <0>{categoryName}</0>?"
|
||||||
msgstr "¿Estás seguro de que deseas eliminar la categoría <0>{categoryName}</0>?"
|
msgstr "¿Estás seguro de que deseas eliminar la categoría <0>{categoryName}</0>?"
|
||||||
@@ -123,54 +136,60 @@ msgid "Asc"
|
|||||||
msgstr "Asc"
|
msgstr "Asc"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Available variables are 'title', 'content', 'url' 'author' and 'categories' and their content is converted to lower case to ease string comparison."
|
msgid "Auto-mark as read"
|
||||||
msgstr "Las variables disponibles son 'título', 'contenido', 'url', 'autor' y 'categorías' y su contenido se convierte a minúsculas para facilitar la comparación de cadenas."
|
msgstr "Marcar como leído automáticamente"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Back"
|
msgid "Back"
|
||||||
msgstr "Atrás"
|
msgstr "Atrás"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Volver a iniciar sesión"
|
msgstr "Volver a iniciar sesión"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Blue"
|
msgid "Blue"
|
||||||
msgstr ""
|
msgstr "Azul"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "Browser extension"
|
||||||
|
msgstr "Extensión del navegador"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Browser extension required for Chrome"
|
msgid "Browser extension required for Chrome"
|
||||||
msgstr "Se requiere extensión de navegador para Chrome"
|
msgstr "Se requiere extensión de navegador para Chrome"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
msgid "Browser extention"
|
|
||||||
msgstr "Extensión del navegador"
|
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr "Pestaña del navegador"
|
msgstr "Pestaña del navegador"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
msgid "Build a filter expression to indicate what you want to read. Entries that don't match will be marked as read automatically."
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
msgstr "Crea una expresión de filtrado para indicar lo que quieres leer. Las entradas que no coincidan se marcarán como leídas automáticamente."
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.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
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Cancelar"
|
msgstr "Cancelar"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Categoría"
|
msgstr "Categoría"
|
||||||
|
|
||||||
@@ -210,11 +229,11 @@ msgstr "Versión de CommaFeed {version} ({revision})."
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Compacto"
|
msgstr "Compacto"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Confirmar"
|
msgstr "Confirmar"
|
||||||
|
|
||||||
@@ -222,10 +241,19 @@ msgstr "Confirmar"
|
|||||||
msgid "Confirm password"
|
msgid "Confirm password"
|
||||||
msgstr "Confirmar contraseña"
|
msgstr "Confirmar contraseña"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Confirm Password"
|
||||||
|
msgstr "Confirmar contraseña"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Cozy"
|
msgid "Cozy"
|
||||||
msgstr "Acogedor"
|
msgstr "Acogedor"
|
||||||
|
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Create Admin Account"
|
||||||
|
msgstr "Crear cuenta de administrador"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Ctrl"
|
msgid "Ctrl"
|
||||||
msgstr "Ctrl"
|
msgstr "Ctrl"
|
||||||
@@ -248,10 +276,10 @@ msgstr "Código JS personalizado que se ejecutará al cargar la página"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Cyan"
|
msgid "Cyan"
|
||||||
msgstr ""
|
msgstr "Cian"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Dark"
|
msgid "Dark"
|
||||||
msgstr "Oscuro"
|
msgstr "Oscuro"
|
||||||
|
|
||||||
@@ -259,6 +287,10 @@ msgstr "Oscuro"
|
|||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Fecha de creación"
|
msgstr "Fecha de creación"
|
||||||
|
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "days"
|
||||||
|
msgstr "días"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Borrar"
|
msgstr "Borrar"
|
||||||
@@ -284,14 +316,18 @@ msgstr "Desc"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr "Detallado"
|
msgstr "Detallado"
|
||||||
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
msgid "Disable \"Pull to refresh\" browser behavior"
|
||||||
|
msgstr "Desactivar el comportamiento \"Arrastrar para actualizar\" del navegador"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Mostrar"
|
msgstr "Mostrar"
|
||||||
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/app/DonatePage.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr "Donar"
|
msgstr "Donar"
|
||||||
|
|
||||||
@@ -303,11 +339,13 @@ 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/pages/auth/PasswordRecoveryPage.tsx
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "Correo electrónico"
|
msgstr "Correo electrónico"
|
||||||
|
|
||||||
@@ -320,8 +358,8 @@ msgstr "Dirección de correo electrónico"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Editar usuario"
|
msgstr "Editar usuario"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Habilitado"
|
msgstr "Habilitado"
|
||||||
|
|
||||||
@@ -345,10 +383,6 @@ msgstr "Encabezados de las entradas"
|
|||||||
msgid "Error"
|
msgid "Error"
|
||||||
msgstr "Error"
|
msgstr "Error"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "Example: {example}."
|
|
||||||
msgstr "Ejemplo: {ejemplo}."
|
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Expanded"
|
msgid "Expanded"
|
||||||
msgstr "Expandido"
|
msgstr "Expandido"
|
||||||
@@ -357,8 +391,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/pages/WelcomePage.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/pages/WelcomePage.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr "Opciones de la extensión"
|
msgstr "Opciones de la extensión"
|
||||||
|
|
||||||
@@ -366,9 +400,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"
|
||||||
|
|
||||||
@@ -390,19 +424,19 @@ msgstr "Expresión de filtrado"
|
|||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Font size"
|
msgid "Font size"
|
||||||
msgstr ""
|
msgstr "Tamaño de fuente"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Force fetching feeds is not yet available."
|
msgid "Force fetching feeds is not yet available."
|
||||||
msgstr ""
|
msgstr "Forzar la actualización de los feeds aún no está disponible."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "¿Olvidaste la contraseña?"
|
msgstr "¿Olvidaste la contraseña?"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.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."
|
||||||
|
|
||||||
@@ -410,9 +444,9 @@ 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/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "URL del feed generado"
|
msgstr "URL del feed generado"
|
||||||
|
|
||||||
@@ -435,24 +469,20 @@ msgstr "Golosinas"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Grape"
|
msgid "Grape"
|
||||||
msgstr ""
|
msgstr "Uva"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Gray"
|
msgid "Gray"
|
||||||
msgstr ""
|
msgstr "Gris"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Green"
|
msgid "Green"
|
||||||
msgstr ""
|
msgstr "Verde"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Id"
|
msgid "Id"
|
||||||
msgstr "Identificación"
|
msgstr "Identificación"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
|
|
||||||
msgstr "Si no está vacía, una expresión que se evalúa como \"verdadera\" o \"falso\". Si es falso, las nuevas entradas de este feed se marcarán como leídas automáticamente."
|
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "If the entry doesn't entirely fit on the screen"
|
msgid "If the entry doesn't entirely fit on the screen"
|
||||||
msgstr "Si la entrada no cabe completamente en la pantalla"
|
msgstr "Si la entrada no cabe completamente en la pantalla"
|
||||||
@@ -471,15 +501,23 @@ msgstr "En la vista ampliada, al desplazarse por las entradas marcarlas como le
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Indigo"
|
msgid "Indigo"
|
||||||
msgstr ""
|
msgstr "Índigo"
|
||||||
|
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Initial Setup"
|
||||||
|
msgstr "Configuración inicial"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Invalid password reset link. Please request a new one."
|
||||||
|
msgstr "Enlace de restablecimiento de contraseña no válido. Por favor, solicita uno nuevo."
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Mantener sin leer"
|
msgstr "Mantener sin leer"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
#: src/components/content/FeedEntries.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Atajos de teclado"
|
msgstr "Atajos de teclado"
|
||||||
|
|
||||||
@@ -505,17 +543,17 @@ msgstr "Claro"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Lime"
|
msgid "Lime"
|
||||||
msgstr ""
|
msgstr "Lima"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "Enlace"
|
msgstr "Enlace"
|
||||||
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
msgid "Link to the documentation"
|
msgid "Link to the documentation"
|
||||||
msgstr ""
|
msgstr "Enlace a la documentación"
|
||||||
|
|
||||||
#: src/hooks/useAppLoading.ts
|
#: src/hooks/useAppLoading.ts
|
||||||
msgid "Loading profile..."
|
msgid "Loading profile..."
|
||||||
@@ -533,9 +571,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"
|
||||||
|
|
||||||
@@ -547,8 +585,8 @@ msgstr "Cerrar sesión"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr "Pulsación larga"
|
msgstr "Pulsación larga"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Administrar usuarios"
|
msgstr "Administrar usuarios"
|
||||||
|
|
||||||
@@ -556,21 +594,25 @@ 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/MarkAllAsReadConfirmationDialog.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/MarkAllAsReadConfirmationDialog.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/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Marcar como leído"
|
msgstr "Marcar como leído"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.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í"
|
||||||
|
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "Mark entries in this feed as read after this number of days. Leave empty to disable."
|
||||||
|
msgstr "Marcar las entradas de este feed como leídas después de este número de días. Dejar vacío para desactivar."
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Metrics"
|
msgid "Metrics"
|
||||||
msgstr "Métricas"
|
msgstr "Métricas"
|
||||||
@@ -587,15 +629,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/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/components/RelativeDate.tsx
|
#: src/components/RelativeDate.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr "N/D"
|
msgstr "N/D"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nombre"
|
msgstr "Nombre"
|
||||||
|
|
||||||
@@ -605,7 +647,7 @@ msgstr "Navegar a una suscripción introduciendo su nombre"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
|
msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
|
||||||
msgstr ""
|
msgstr "Navegar a la siguiente categoría/feed con entradas no leídas al marcar todas como leídas"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
@@ -616,12 +658,17 @@ msgstr "Nunca"
|
|||||||
msgid "New password"
|
msgid "New password"
|
||||||
msgstr "Nueva contraseña"
|
msgstr "Nueva contraseña"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "New Password"
|
||||||
|
msgstr "Nueva contraseña"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Las más recientes primero"
|
msgstr "Las más recientes primero"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Siguiente"
|
msgstr "Siguiente"
|
||||||
|
|
||||||
@@ -729,7 +776,7 @@ msgstr "Es necesario un archivo OPML"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Orange"
|
msgid "Orange"
|
||||||
msgstr ""
|
msgstr "Naranja"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Order"
|
msgid "Order"
|
||||||
@@ -743,28 +790,34 @@ 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/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.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"
|
||||||
|
|
||||||
|
#: src/hooks/useValidationRules.ts
|
||||||
|
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||||
|
msgstr "La contraseña debe tener al menos {minimumPasswordLength} caracteres"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "Password Recovery"
|
msgid "Password Recovery"
|
||||||
msgstr "Recuperación de contraseña"
|
msgstr "Recuperación de contraseña"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/hooks/useValidationRules.ts
|
||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Las contraseñas no coinciden"
|
msgstr "Las contraseñas no coinciden"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Pink"
|
msgid "Pink"
|
||||||
msgstr ""
|
msgstr "Rosa"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Posición"
|
msgstr "Posición"
|
||||||
|
|
||||||
@@ -774,22 +827,47 @@ msgstr "Previo"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Primary color"
|
msgid "Primary color"
|
||||||
msgstr ""
|
msgstr "Color primario"
|
||||||
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
msgid "Profile"
|
msgid "Profile"
|
||||||
msgstr "Perfil"
|
msgstr "Perfil"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Push notification service"
|
||||||
|
msgstr "Servicio de notificaciones push"
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Push notifications"
|
||||||
|
msgstr "Notificaciones push"
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
msgid "Push notifications are not configured in your user settings."
|
||||||
|
msgstr "Las notificaciones push no están configuradas en tus ajustes de usuario."
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Push notifications are not enabled on this CommaFeed instance."
|
||||||
|
msgstr "Las notificaciones push no están habilitadas en esta instancia de CommaFeed."
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
msgid "Receive push notifications"
|
||||||
|
msgstr "Recibir notificaciones push"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Receive push notifications when new feed entries are discovered. Enable \"Receive push notifications\" in the settings of each feed for which you want to receive notifications."
|
||||||
|
msgstr "Recibir notificaciones push cuando se descubran nuevas entradas. Activa \"Recibir notificaciones push\" en los ajustes de cada feed del que quieras recibir notificaciones."
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Recuperar contraseña"
|
msgstr "Recuperar contraseña"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Red"
|
msgid "Red"
|
||||||
msgstr ""
|
msgstr "Rojo"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Actualizar"
|
msgstr "Actualizar"
|
||||||
|
|
||||||
@@ -797,6 +875,11 @@ msgstr "Actualizar"
|
|||||||
msgid "Registrations are closed on this CommaFeed instance"
|
msgid "Registrations are closed on this CommaFeed instance"
|
||||||
msgstr "Los registros están cerrados en esta instancia de CommaFeed"
|
msgstr "Los registros están cerrados en esta instancia de CommaFeed"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Reset Password"
|
||||||
|
msgstr "Restablecer contraseña"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "REST API"
|
msgid "REST API"
|
||||||
msgstr "API REST"
|
msgstr "API REST"
|
||||||
@@ -806,11 +889,12 @@ msgstr "API REST"
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr "Clic derecho"
|
msgstr "Clic derecho"
|
||||||
|
|
||||||
#: 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
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Guardar"
|
msgstr "Guardar"
|
||||||
|
|
||||||
@@ -826,24 +910,25 @@ msgstr "Desplazarse suavemente al navegar entre entradas"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr "Desplazarse"
|
msgstr "Desplazarse"
|
||||||
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Buscar"
|
msgstr "Buscar"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
msgid "Search requires at least 3 characters"
|
|
||||||
msgstr "La búsqueda requiere al menos 3 caracteres"
|
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Select next unread feed/category"
|
msgid "Select next unread feed/category"
|
||||||
msgstr ""
|
msgstr "Seleccionar el siguiente feed/categoría no leído"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Select previous unread feed/category"
|
msgid "Select previous unread feed/category"
|
||||||
msgstr ""
|
msgstr "Seleccionar el anterior feed/categoría no leído"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Server URL"
|
||||||
|
msgstr "URL del servidor"
|
||||||
|
|
||||||
#: 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"
|
||||||
@@ -919,9 +1004,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"
|
||||||
|
|
||||||
@@ -934,21 +1019,21 @@ msgstr "Algo malo acaba de pasar..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Espacio"
|
msgstr "Espacio"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "Estrella"
|
msgstr "Estrella"
|
||||||
|
|
||||||
#: src/pages/app/FeedEntriesPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedEntriesPage.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"
|
||||||
|
|
||||||
@@ -987,7 +1072,15 @@ msgstr "Etiquetas"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Teal"
|
msgid "Teal"
|
||||||
msgstr ""
|
msgstr "Verde azulado"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Test"
|
||||||
|
msgstr "Probar"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Test notification sent successfully."
|
||||||
|
msgstr "Notificación de prueba enviada con éxito."
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed will try to find the feed in the page."
|
msgid "The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed will try to find the feed in the page."
|
||||||
@@ -997,10 +1090,19 @@ msgstr "La URL del feed al que desea suscribirse. También puede utilizar la URL
|
|||||||
msgid "Theme"
|
msgid "Theme"
|
||||||
msgstr "Tema"
|
msgstr "Tema"
|
||||||
|
|
||||||
|
#. placeholder {0}: feed.filterLegacy
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "This feed has a legacy filter that cannot be edited and is not applied. Please recreate the filter using the new expression editor. The legacy filter expression was: <0>{0}</0>"
|
||||||
|
msgstr "Este feed tiene un filtro heredado que no se puede editar y no se aplica. Por favor, vuelve a crear el filtro usando el nuevo editor de expresiones. La expresión del filtro heredado era: <0>{0}</0>"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||||
msgstr "Esta es su clave API. Se puede utilizar para algunas operaciones API de solo lectura y otorga acceso a Fever API. Utilice el formulario en la parte inferior de la página para generar una nueva clave API"
|
msgstr "Esta es su clave API. Se puede utilizar para algunas operaciones API de solo lectura y otorga acceso a Fever API. Utilice el formulario en la parte inferior de la página para generar una nueva clave API"
|
||||||
|
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||||
|
msgstr "Este ajuste puede causar problemas de desplazamiento en algunos navegadores (por ejemplo, Safari)"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Alternar estado de lectura de la entrada actual"
|
msgstr "Alternar estado de lectura de la entrada actual"
|
||||||
@@ -1013,6 +1115,10 @@ msgstr "Alternar barra lateral"
|
|||||||
msgid "Toggle starred status of current entry"
|
msgid "Toggle starred status of current entry"
|
||||||
msgstr "Alternar estado destacado de la entrada actual"
|
msgstr "Alternar estado destacado de la entrada actual"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Topic"
|
||||||
|
msgstr "Tema"
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Prueba CommaFeed con la cuenta de demostración: demo/demo"
|
msgstr "Prueba CommaFeed con la cuenta de demostración: demo/demo"
|
||||||
@@ -1025,8 +1131,8 @@ msgstr "¡Prueba la demostración!"
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "No leído"
|
msgstr "No leído"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "Desmarcar"
|
msgstr "Desmarcar"
|
||||||
@@ -1036,6 +1142,10 @@ msgstr "Desmarcar"
|
|||||||
msgid "Unsubscribe"
|
msgid "Unsubscribe"
|
||||||
msgstr "Cancelar suscripción"
|
msgstr "Cancelar suscripción"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "User key"
|
||||||
|
msgstr "Clave de usuario"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "User name"
|
msgid "User name"
|
||||||
msgstr "Nombre de usuario"
|
msgstr "Nombre de usuario"
|
||||||
@@ -1047,7 +1157,7 @@ msgstr "Nombre de usuario o correo electrónico"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Violet"
|
msgid "Violet"
|
||||||
msgstr ""
|
msgstr "Violeta"
|
||||||
|
|
||||||
#: src/components/Alert.tsx
|
#: src/components/Alert.tsx
|
||||||
msgid "Warning"
|
msgid "Warning"
|
||||||
@@ -1057,9 +1167,13 @@ msgstr "Advertencia"
|
|||||||
msgid "Website"
|
msgid "Website"
|
||||||
msgstr "Sitio web"
|
msgstr "Sitio web"
|
||||||
|
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||||
|
msgstr "¡Bienvenido! Parece que esta es la primera vez que ejecutas CommaFeed. Por favor, crea una cuenta de administrador para empezar."
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Yellow"
|
msgid "Yellow"
|
||||||
msgstr ""
|
msgstr "Amarillo"
|
||||||
|
|
||||||
#: src/pages/app/FeedEntriesPage.tsx
|
#: src/pages/app/FeedEntriesPage.tsx
|
||||||
msgid "You don't have any subscriptions yet. Why not try adding one by clicking on the + sign at the top of the page?"
|
msgid "You don't have any subscriptions yet. Why not try adding one by clicking on the + sign at the top of the page?"
|
||||||
@@ -1068,3 +1182,7 @@ msgstr "Aún no tienes ninguna suscripción. ¿Por qué no intentas agregar una
|
|||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Your feeds have been queued for refresh."
|
msgid "Your feeds have been queued for refresh."
|
||||||
msgstr "Tus feeds se han puesto en cola para actualizarse."
|
msgstr "Tus feeds se han puesto en cola para actualizarse."
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Your password has been changed. You can now log in with your new password."
|
||||||
|
msgstr "Tu contraseña ha sido cambiada. Ahora puedes iniciar sesión con tu nueva contraseña."
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -17,10 +17,6 @@ msgstr ""
|
|||||||
msgid "<0>CommaFeed is an open-source project. Sources are hosted on </0><1>GitHub</1>."
|
msgid "<0>CommaFeed is an open-source project. Sources are hosted on </0><1>GitHub</1>."
|
||||||
msgstr "<0>CommaFeed est un projet open-source. Les sources sont hébergées sur </0><1>GitHub</1>."
|
msgstr "<0>CommaFeed est un projet open-source. Les sources sont hébergées sur </0><1>GitHub</1>."
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "<0>Complete syntax is available </0><1>here</1><2>.</2>"
|
|
||||||
msgstr "<0>La syntaxe complète est disponible </0><1>ici</1><2>.</2>"
|
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "<0>Have an account?</0><1>Log in!</1>"
|
msgid "<0>Have an account?</0><1>Log in!</1>"
|
||||||
msgstr "<0>Déjà un compte ?</0><1>Connectez-vous !</1>"
|
msgstr "<0>Déjà un compte ?</0><1>Connectez-vous !</1>"
|
||||||
@@ -33,11 +29,15 @@ 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/pages/app/AboutPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "À propos"
|
msgstr "À propos"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Access token"
|
||||||
|
msgstr "Jeton d'accès"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Actions"
|
msgid "Actions"
|
||||||
msgstr "Actions"
|
msgstr "Actions"
|
||||||
@@ -54,17 +54,22 @@ msgstr "Ajouter une catégorie"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Ajouter un utilisateur"
|
msgstr "Ajouter un utilisateur"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Administrateur"
|
msgstr "Administrateur"
|
||||||
|
|
||||||
#: src/pages/app/FeedEntriesPage.tsx
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
msgid "Admin user name"
|
||||||
#: src/components/header/Header.tsx
|
msgstr "Nom de l'administrateur"
|
||||||
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedEntriesPage.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Tout"
|
msgstr "Tout"
|
||||||
|
|
||||||
@@ -93,6 +98,14 @@ msgstr "Annonces"
|
|||||||
msgid "API key"
|
msgid "API key"
|
||||||
msgstr "Clé API"
|
msgstr "Clé API"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "API token"
|
||||||
|
msgstr "Jeton API"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "App token"
|
||||||
|
msgstr "Jeton Appli"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Are you sure you want to delete category <0>{categoryName}</0>?"
|
msgid "Are you sure you want to delete category <0>{categoryName}</0>?"
|
||||||
msgstr "Êtes-vous sûr de vouloir supprimer la catégorie <0>{categoryName}</0> ?"
|
msgstr "Êtes-vous sûr de vouloir supprimer la catégorie <0>{categoryName}</0> ?"
|
||||||
@@ -122,14 +135,15 @@ msgid "Asc"
|
|||||||
msgstr "Ascendant"
|
msgstr "Ascendant"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Available variables are 'title', 'content', 'url' 'author' and 'categories' and their content is converted to lower case to ease string comparison."
|
msgid "Auto-mark as read"
|
||||||
msgstr "Les variables disponibles sont 'title', 'content', 'url' 'author' et 'categories' et leur contenu est converti en minuscules pour faciliter la comparaison de chaînes."
|
msgstr "Marquer automatiquement comme lu"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Back"
|
msgid "Back"
|
||||||
msgstr "Retour"
|
msgstr "Retour"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Retour à la connexion"
|
msgstr "Retour à la connexion"
|
||||||
|
|
||||||
@@ -137,39 +151,44 @@ msgstr "Retour à la connexion"
|
|||||||
msgid "Blue"
|
msgid "Blue"
|
||||||
msgstr "Bleu"
|
msgstr "Bleu"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "Browser extension"
|
||||||
|
msgstr "Extension navigateur"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Browser extension required for Chrome"
|
msgid "Browser extension required for Chrome"
|
||||||
msgstr "L'extension navigateur est nécessaire sur Chrome"
|
msgstr "L'extension navigateur est nécessaire sur Chrome"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
msgid "Browser extention"
|
|
||||||
msgstr "Extension navigateur"
|
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr "Onglet navigateur"
|
msgstr "Onglet navigateur"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
msgid "Build a filter expression to indicate what you want to read. Entries that don't match will be marked as read automatically."
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
msgstr "Créez une expression régulière pour filtrer ce que vous voulez lire. Les entrées qui ne correspondent pas seront automatiquement marquées comme lues."
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.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
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Annuler"
|
msgstr "Annuler"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Catégorie"
|
msgstr "Catégorie"
|
||||||
|
|
||||||
@@ -209,11 +228,11 @@ msgstr "CommaFeed version {version} ({revision})."
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Compact"
|
msgstr "Compact"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Confirmer"
|
msgstr "Confirmer"
|
||||||
|
|
||||||
@@ -221,10 +240,19 @@ msgstr "Confirmer"
|
|||||||
msgid "Confirm password"
|
msgid "Confirm password"
|
||||||
msgstr "Confirmer le mot de passe"
|
msgstr "Confirmer le mot de passe"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Confirm Password"
|
||||||
|
msgstr "Confirmer le mot de passe"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Cozy"
|
msgid "Cozy"
|
||||||
msgstr "Cozy"
|
msgstr "Cozy"
|
||||||
|
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Create Admin Account"
|
||||||
|
msgstr "Créer un compte adminstrateur"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Ctrl"
|
msgid "Ctrl"
|
||||||
msgstr "Ctrl"
|
msgstr "Ctrl"
|
||||||
@@ -249,8 +277,8 @@ msgstr "Code JS personnalisé qui sera appliqué au chargement des pages"
|
|||||||
msgid "Cyan"
|
msgid "Cyan"
|
||||||
msgstr "Cyan"
|
msgstr "Cyan"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Dark"
|
msgid "Dark"
|
||||||
msgstr "Foncé"
|
msgstr "Foncé"
|
||||||
|
|
||||||
@@ -258,6 +286,10 @@ msgstr "Foncé"
|
|||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Date de création"
|
msgstr "Date de création"
|
||||||
|
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "days"
|
||||||
|
msgstr "jours"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Effacer"
|
msgstr "Effacer"
|
||||||
@@ -283,14 +315,18 @@ msgstr "Descendant"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr "Vue détaillée"
|
msgstr "Vue détaillée"
|
||||||
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
msgid "Disable \"Pull to refresh\" browser behavior"
|
||||||
|
msgstr "Désactiver la fonction \"tirer pour rafraîchir\" du navigateur"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Affichage"
|
msgstr "Affichage"
|
||||||
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/app/DonatePage.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr "Faire un don"
|
msgstr "Faire un don"
|
||||||
|
|
||||||
@@ -302,11 +338,13 @@ 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/pages/auth/PasswordRecoveryPage.tsx
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "E-mail"
|
msgstr "E-mail"
|
||||||
|
|
||||||
@@ -319,8 +357,8 @@ msgstr "Adresse e-mail"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Modifier un utilisateur"
|
msgstr "Modifier un utilisateur"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Actif"
|
msgstr "Actif"
|
||||||
|
|
||||||
@@ -344,10 +382,6 @@ msgstr "En-têtes de l'entrée"
|
|||||||
msgid "Error"
|
msgid "Error"
|
||||||
msgstr "Erreur"
|
msgstr "Erreur"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "Example: {example}."
|
|
||||||
msgstr "Exemple : {example}."
|
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Expanded"
|
msgid "Expanded"
|
||||||
msgstr "Vue étendue"
|
msgstr "Vue étendue"
|
||||||
@@ -356,8 +390,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/pages/WelcomePage.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/pages/WelcomePage.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr "Options de l'extension"
|
msgstr "Options de l'extension"
|
||||||
|
|
||||||
@@ -365,9 +399,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"
|
||||||
|
|
||||||
@@ -399,9 +433,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/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.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."
|
||||||
|
|
||||||
@@ -409,9 +443,9 @@ 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/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "URL du flux généré"
|
msgstr "URL du flux généré"
|
||||||
|
|
||||||
@@ -448,10 +482,6 @@ msgstr "Vert"
|
|||||||
msgid "Id"
|
msgid "Id"
|
||||||
msgstr "Identifiant"
|
msgstr "Identifiant"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
|
|
||||||
msgstr "Si non vide, une expression évaluant à 'vrai' ou 'faux'. Si faux, les nouvelles entrées de ce flux seront marquées comme lues automatiquement."
|
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "If the entry doesn't entirely fit on the screen"
|
msgid "If the entry doesn't entirely fit on the screen"
|
||||||
msgstr "Si l'entrée ne tient pas entièrement sur l'écran"
|
msgstr "Si l'entrée ne tient pas entièrement sur l'écran"
|
||||||
@@ -472,13 +502,21 @@ msgstr "En mode de lecture étendu, marquer les éléments comme lus lorsque la
|
|||||||
msgid "Indigo"
|
msgid "Indigo"
|
||||||
msgstr "Indigo"
|
msgstr "Indigo"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Initial Setup"
|
||||||
|
msgstr "Configuration initiale"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Invalid password reset link. Please request a new one."
|
||||||
|
msgstr "Lien de réinitialisation de mot de passse invalide. Recommencez la procédure."
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Garder non lu"
|
msgstr "Garder non lu"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
#: src/components/content/FeedEntries.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Raccourcis clavier"
|
msgstr "Raccourcis clavier"
|
||||||
|
|
||||||
@@ -506,9 +544,9 @@ msgstr "Clair"
|
|||||||
msgid "Lime"
|
msgid "Lime"
|
||||||
msgstr "Jaune-vert"
|
msgstr "Jaune-vert"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "Lien"
|
msgstr "Lien"
|
||||||
|
|
||||||
@@ -532,9 +570,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"
|
||||||
|
|
||||||
@@ -546,8 +584,8 @@ msgstr "Déconnexion"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr "Appui long"
|
msgstr "Appui long"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Gestion des utilisateurs"
|
msgstr "Gestion des utilisateurs"
|
||||||
|
|
||||||
@@ -555,21 +593,25 @@ 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/MarkAllAsReadConfirmationDialog.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/MarkAllAsReadConfirmationDialog.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/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Marquer comme lu"
|
msgstr "Marquer comme lu"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.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"
|
||||||
|
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "Mark entries in this feed as read after this number of days. Leave empty to disable."
|
||||||
|
msgstr "Marquer les entrées de ce flux comme lues après ce nombre de jours. Laissez vide pour désactiver."
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Metrics"
|
msgid "Metrics"
|
||||||
msgstr "Métriques"
|
msgstr "Métriques"
|
||||||
@@ -586,15 +628,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/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/components/RelativeDate.tsx
|
#: src/components/RelativeDate.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr "N/A"
|
msgstr "N/A"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nom"
|
msgstr "Nom"
|
||||||
|
|
||||||
@@ -615,12 +657,17 @@ msgstr "Jamais"
|
|||||||
msgid "New password"
|
msgid "New password"
|
||||||
msgstr "Nouveau mot de passe"
|
msgstr "Nouveau mot de passe"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "New Password"
|
||||||
|
msgstr "Nouveau mot de passe"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Plus récent en premier"
|
msgstr "Plus récent en premier"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Suivant"
|
msgstr "Suivant"
|
||||||
|
|
||||||
@@ -742,19 +789,25 @@ 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/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.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"
|
||||||
|
|
||||||
|
#: src/hooks/useValidationRules.ts
|
||||||
|
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||||
|
msgstr "Le mot de passe doit mesurer au moins {minimumPasswordLength} caractères"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "Password Recovery"
|
msgid "Password Recovery"
|
||||||
msgstr "Récupération de mot de passe"
|
msgstr "Récupération de mot de passe"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/hooks/useValidationRules.ts
|
||||||
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"
|
||||||
|
|
||||||
@@ -762,8 +815,8 @@ msgstr "Les mots de passe ne correspondent pas"
|
|||||||
msgid "Pink"
|
msgid "Pink"
|
||||||
msgstr "Rose"
|
msgstr "Rose"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Position"
|
msgstr "Position"
|
||||||
|
|
||||||
@@ -779,6 +832,31 @@ msgstr "Couleur d'ambiance"
|
|||||||
msgid "Profile"
|
msgid "Profile"
|
||||||
msgstr "Profil"
|
msgstr "Profil"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Push notification service"
|
||||||
|
msgstr "Service de notifications Push"
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Push notifications"
|
||||||
|
msgstr "Notifications Push"
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
msgid "Push notifications are not configured in your user settings."
|
||||||
|
msgstr "Les notifications Push ne sont pas configurées dans vos préférences."
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Push notifications are not enabled on this CommaFeed instance."
|
||||||
|
msgstr "Les notifications Push ne sont pas disponibles dans cette instance CommaFeed."
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
msgid "Receive push notifications"
|
||||||
|
msgstr "Envoyer des notifications Push"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Receive push notifications when new feed entries are discovered. Enable \"Receive push notifications\" in the settings of each feed for which you want to receive notifications."
|
||||||
|
msgstr "Permet de recevoir des notifications Push quand des nouvelles entrées sont découvertes pour un flux. Activez \"Envoyer des notifications Push\" dans les paramètres des flux pour lesquels vous souhaitez être notifié."
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Récupérer le mot de passe"
|
msgstr "Récupérer le mot de passe"
|
||||||
@@ -787,8 +865,8 @@ msgstr "Récupérer le mot de passe"
|
|||||||
msgid "Red"
|
msgid "Red"
|
||||||
msgstr "Rouge"
|
msgstr "Rouge"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Rafraîchir"
|
msgstr "Rafraîchir"
|
||||||
|
|
||||||
@@ -796,6 +874,11 @@ msgstr "Rafraîchir"
|
|||||||
msgid "Registrations are closed on this CommaFeed instance"
|
msgid "Registrations are closed on this CommaFeed instance"
|
||||||
msgstr "Les inscriptions sont fermées sur cette instance de CommaFeed"
|
msgstr "Les inscriptions sont fermées sur cette instance de CommaFeed"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Reset Password"
|
||||||
|
msgstr "Réinitialiser le mot de passe"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "REST API"
|
msgid "REST API"
|
||||||
msgstr "API REST"
|
msgstr "API REST"
|
||||||
@@ -805,11 +888,12 @@ msgstr "API REST"
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr "Clic droit"
|
msgstr "Clic droit"
|
||||||
|
|
||||||
#: 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
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Enregistrer"
|
msgstr "Enregistrer"
|
||||||
|
|
||||||
@@ -825,17 +909,13 @@ msgstr "Défilement animé lors de la navigation entre les entrées"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr "Défilement"
|
msgstr "Défilement"
|
||||||
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Rechercher"
|
msgstr "Rechercher"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
msgid "Search requires at least 3 characters"
|
|
||||||
msgstr "La recherche requiert au moins 3 caractères"
|
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Select next unread feed/category"
|
msgid "Select next unread feed/category"
|
||||||
msgstr "Sélectionner l'article non lu suivant/la catégorie non lue suivante"
|
msgstr "Sélectionner l'article non lu suivant/la catégorie non lue suivante"
|
||||||
@@ -844,6 +924,11 @@ msgstr "Sélectionner l'article non lu suivant/la catégorie non lue suivante"
|
|||||||
msgid "Select previous unread feed/category"
|
msgid "Select previous unread feed/category"
|
||||||
msgstr "Sélectionner l'article non lu précédent/la catégorie non lue précédente"
|
msgstr "Sélectionner l'article non lu précédent/la catégorie non lue précédente"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Server URL"
|
||||||
|
msgstr "URL du serveur"
|
||||||
|
|
||||||
#: 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"
|
||||||
@@ -918,9 +1003,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"
|
||||||
|
|
||||||
@@ -933,21 +1018,21 @@ msgstr "Quelque chose s'est mal passé..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Espace"
|
msgstr "Espace"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.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/pages/app/FeedEntriesPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedEntriesPage.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"
|
||||||
|
|
||||||
@@ -988,6 +1073,14 @@ msgstr "Marqueurs"
|
|||||||
msgid "Teal"
|
msgid "Teal"
|
||||||
msgstr "Bleu-vert"
|
msgstr "Bleu-vert"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Test"
|
||||||
|
msgstr "Test"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Test notification sent successfully."
|
||||||
|
msgstr "Notification de test envoyée avec succès."
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed will try to find the feed in the page."
|
msgid "The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed will try to find the feed in the page."
|
||||||
msgstr "L'URL du flux auquel vous souhaitez vous abonner. Vous pouvez aussi utiliser l'URL du site directement et CommaFeed va essayer de trouver le flux dans la page."
|
msgstr "L'URL du flux auquel vous souhaitez vous abonner. Vous pouvez aussi utiliser l'URL du site directement et CommaFeed va essayer de trouver le flux dans la page."
|
||||||
@@ -996,10 +1089,19 @@ msgstr "L'URL du flux auquel vous souhaitez vous abonner. Vous pouvez aussi util
|
|||||||
msgid "Theme"
|
msgid "Theme"
|
||||||
msgstr "Thème"
|
msgstr "Thème"
|
||||||
|
|
||||||
|
#. placeholder {0}: feed.filterLegacy
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "This feed has a legacy filter that cannot be edited and is not applied. Please recreate the filter using the new expression editor. The legacy filter expression was: <0>{0}</0>"
|
||||||
|
msgstr "Ce flux est configuré avec un filtre obsolète, qui ne peut être ni modifié ni appliqué. Vous devez recréer ce filtre à l'aide du nouvel éditeur d'expressions régulières. Le filtre configuré était : <0>{0}</0>"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||||
msgstr "Ceci est votre clef API. Elle peut être utilisée pour certaines opérations en lecture seule et donne accès à l'API Fever. Utilisez le formulaire en bas de la page pour générer une nouvelle clef API"
|
msgstr "Ceci est votre clef API. Elle peut être utilisée pour certaines opérations en lecture seule et donne accès à l'API Fever. Utilisez le formulaire en bas de la page pour générer une nouvelle clef API"
|
||||||
|
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||||
|
msgstr "Cette fonctinnalité peut causer des problèmes de défilement sur certains navigateurs (Safari, par exemple)"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Marquer l'entrée actuelle comme lue/non lue"
|
msgstr "Marquer l'entrée actuelle comme lue/non lue"
|
||||||
@@ -1012,6 +1114,10 @@ msgstr "Montrer/cacher la barre latérale"
|
|||||||
msgid "Toggle starred status of current entry"
|
msgid "Toggle starred status of current entry"
|
||||||
msgstr "Montrer/cacher le statut favori de l'entrée"
|
msgstr "Montrer/cacher le statut favori de l'entrée"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Topic"
|
||||||
|
msgstr "Sujet"
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Essayez CommaFeed avec le compte de démonstration : demo/demo"
|
msgstr "Essayez CommaFeed avec le compte de démonstration : demo/demo"
|
||||||
@@ -1024,8 +1130,8 @@ msgstr "Essayez la version de démonstration !"
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Non lu"
|
msgstr "Non lu"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.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"
|
||||||
@@ -1035,6 +1141,10 @@ msgstr "Retirer des favoris"
|
|||||||
msgid "Unsubscribe"
|
msgid "Unsubscribe"
|
||||||
msgstr "Se désabonner"
|
msgstr "Se désabonner"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "User key"
|
||||||
|
msgstr "Clé utilisateur"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "User name"
|
msgid "User name"
|
||||||
msgstr "Nom"
|
msgstr "Nom"
|
||||||
@@ -1056,6 +1166,10 @@ msgstr "Attention"
|
|||||||
msgid "Website"
|
msgid "Website"
|
||||||
msgstr "Site web"
|
msgstr "Site web"
|
||||||
|
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||||
|
msgstr "Bienvenue ! Il semble que ce soit le premier démarrage de Commafeed. Avant tout, vous devez créer un compte administrateur."
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Yellow"
|
msgid "Yellow"
|
||||||
msgstr "Jaune"
|
msgstr "Jaune"
|
||||||
@@ -1067,3 +1181,7 @@ msgstr "Vous n'avez pas encore d'abonnements. Pourquoi ne pas essayer d'en ajout
|
|||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Your feeds have been queued for refresh."
|
msgid "Your feeds have been queued for refresh."
|
||||||
msgstr "Vos flux sont en cours de rafraîchissement"
|
msgstr "Vos flux sont en cours de rafraîchissement"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Your password has been changed. You can now log in with your new password."
|
||||||
|
msgstr "Votre mot de passe a été modifié. Vous pouvez vous connecter avec votre nouveau mot de passe."
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -17,10 +17,6 @@ msgstr ""
|
|||||||
msgid "<0>CommaFeed is an open-source project. Sources are hosted on </0><1>GitHub</1>."
|
msgid "<0>CommaFeed is an open-source project. Sources are hosted on </0><1>GitHub</1>."
|
||||||
msgstr "<0>CommaFeed はオープンソースのプロジェクトです。 ソースは以下でホストされています </0><1>GitHub</1>。"
|
msgstr "<0>CommaFeed はオープンソースのプロジェクトです。 ソースは以下でホストされています </0><1>GitHub</1>。"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "<0>Complete syntax is available </0><1>here</1><2>.</2>"
|
|
||||||
msgstr "<0>完全な syntax </0><1>こちら</1>で利用可能です<2>。</2>"
|
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "<0>Have an account?</0><1>Log in!</1>"
|
msgid "<0>Have an account?</0><1>Log in!</1>"
|
||||||
msgstr "<0>アカウントをお持ちですか?</0><1>ログインしてください!</1>"
|
msgstr "<0>アカウントをお持ちですか?</0><1>ログインしてください!</1>"
|
||||||
@@ -33,11 +29,15 @@ 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/pages/app/AboutPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "About"
|
msgstr "About"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Access token"
|
||||||
|
msgstr "アクセストークン"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Actions"
|
msgid "Actions"
|
||||||
msgstr "アクション"
|
msgstr "アクション"
|
||||||
@@ -54,17 +54,22 @@ msgstr "カテゴリを追加"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "ユーザー追加"
|
msgstr "ユーザー追加"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "管理者"
|
msgstr "管理者"
|
||||||
|
|
||||||
#: src/pages/app/FeedEntriesPage.tsx
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
msgid "Admin user name"
|
||||||
#: src/components/header/Header.tsx
|
msgstr "管理者ユーザー名"
|
||||||
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedEntriesPage.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "すべて"
|
msgstr "すべて"
|
||||||
|
|
||||||
@@ -93,6 +98,14 @@ msgstr "お知らせ"
|
|||||||
msgid "API key"
|
msgid "API key"
|
||||||
msgstr "APIキー"
|
msgstr "APIキー"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "API token"
|
||||||
|
msgstr "APIトークン"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "App token"
|
||||||
|
msgstr "アプリトークン"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Are you sure you want to delete category <0>{categoryName}</0>?"
|
msgid "Are you sure you want to delete category <0>{categoryName}</0>?"
|
||||||
msgstr "カテゴリ <0>{categoryName}</0> を削除してもよろしいですか?"
|
msgstr "カテゴリ <0>{categoryName}</0> を削除してもよろしいですか?"
|
||||||
@@ -122,54 +135,60 @@ msgid "Asc"
|
|||||||
msgstr "昇順"
|
msgstr "昇順"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Available variables are 'title', 'content', 'url' 'author' and 'categories' and their content is converted to lower case to ease string comparison."
|
msgid "Auto-mark as read"
|
||||||
msgstr "使用可能な変数は「title」、「content」、「url」、「author」、および「categories」であり、それらのコンテンツは文字列の比較を容易にするために小文字に変換されます。"
|
msgstr "自動的に既読にする"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Back"
|
msgid "Back"
|
||||||
msgstr "戻る"
|
msgstr "戻る"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "ログインに戻る"
|
msgstr "ログインに戻る"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Blue"
|
msgid "Blue"
|
||||||
msgstr ""
|
msgstr "ブルー"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "Browser extension"
|
||||||
|
msgstr "ブラウザー拡張"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Browser extension required for Chrome"
|
msgid "Browser extension required for Chrome"
|
||||||
msgstr "Chromeのブラウザー拡張が必要です"
|
msgstr "Chromeのブラウザー拡張が必要です"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
msgid "Browser extention"
|
|
||||||
msgstr "ブラウザー拡張"
|
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr "ブラウザータブ"
|
msgstr "ブラウザータブ"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
msgid "Build a filter expression to indicate what you want to read. Entries that don't match will be marked as read automatically."
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
msgstr "読みたい内容を指定するためのフィルタ式を作成します。一致しないエントリは自動的に既読としてマークされます。"
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.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
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "キャンセル"
|
msgstr "キャンセル"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "カテゴリー"
|
msgstr "カテゴリー"
|
||||||
|
|
||||||
@@ -209,11 +228,11 @@ msgstr "CommaFeed バージョン {version} ({revision})。"
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "コンパクト"
|
msgstr "コンパクト"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "確認"
|
msgstr "確認"
|
||||||
|
|
||||||
@@ -221,10 +240,19 @@ msgstr "確認"
|
|||||||
msgid "Confirm password"
|
msgid "Confirm password"
|
||||||
msgstr "パスワード確認"
|
msgstr "パスワード確認"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Confirm Password"
|
||||||
|
msgstr "パスワードの確認"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Cozy"
|
msgid "Cozy"
|
||||||
msgstr "Cozy"
|
msgstr "Cozy"
|
||||||
|
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Create Admin Account"
|
||||||
|
msgstr "管理者アカウントの作成"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Ctrl"
|
msgid "Ctrl"
|
||||||
msgstr "Ctrl"
|
msgstr "Ctrl"
|
||||||
@@ -247,10 +275,10 @@ msgstr "ページ読み込み時に実行されるカスタムJSコード"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Cyan"
|
msgid "Cyan"
|
||||||
msgstr ""
|
msgstr "シアン"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Dark"
|
msgid "Dark"
|
||||||
msgstr "ダーク"
|
msgstr "ダーク"
|
||||||
|
|
||||||
@@ -258,6 +286,10 @@ msgstr "ダーク"
|
|||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "作成日"
|
msgstr "作成日"
|
||||||
|
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "days"
|
||||||
|
msgstr "日"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "削除"
|
msgstr "削除"
|
||||||
@@ -283,14 +315,18 @@ msgstr "説明"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr "詳細"
|
msgstr "詳細"
|
||||||
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
msgid "Disable \"Pull to refresh\" browser behavior"
|
||||||
|
msgstr "ブラウザの「プルして更新」動作を無効にする"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "ディスプレイ"
|
msgstr "ディスプレイ"
|
||||||
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/app/DonatePage.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr "寄付"
|
msgstr "寄付"
|
||||||
|
|
||||||
@@ -302,11 +338,13 @@ msgstr "ダウンロード"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "リンクをブックマークバーにドラッグ"
|
msgstr "リンクをブックマークバーにドラッグ"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "メール"
|
msgstr "メール"
|
||||||
|
|
||||||
@@ -319,8 +357,8 @@ msgstr "メールアドレス"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "ユーザーの編集"
|
msgstr "ユーザーの編集"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "有効"
|
msgstr "有効"
|
||||||
|
|
||||||
@@ -344,10 +382,6 @@ msgstr "エントリーヘッダー"
|
|||||||
msgid "Error"
|
msgid "Error"
|
||||||
msgstr "エラー"
|
msgstr "エラー"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "Example: {example}."
|
|
||||||
msgstr "例: {example}."
|
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Expanded"
|
msgid "Expanded"
|
||||||
msgstr "拡張"
|
msgstr "拡張"
|
||||||
@@ -356,8 +390,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/pages/WelcomePage.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/pages/WelcomePage.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr "拡張機能オプション"
|
msgstr "拡張機能オプション"
|
||||||
|
|
||||||
@@ -365,9 +399,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"
|
||||||
|
|
||||||
@@ -389,7 +423,7 @@ msgstr "フィルタリング式"
|
|||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Font size"
|
msgid "Font size"
|
||||||
msgstr ""
|
msgstr "フォントサイズ"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Force fetching feeds is not yet available."
|
msgid "Force fetching feeds is not yet available."
|
||||||
@@ -399,9 +433,9 @@ msgstr "フィードの強制フェッチはまだ利用できません。"
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "パスワードをお忘れですか?"
|
msgstr "パスワードをお忘れですか?"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "最初にプロファイルでAPIキーを生成します。"
|
msgstr "最初にプロファイルでAPIキーを生成します。"
|
||||||
|
|
||||||
@@ -409,9 +443,9 @@ msgstr "最初にプロファイルでAPIキーを生成します。"
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "新しいAPIキーを生成する"
|
msgstr "新しいAPIキーを生成する"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "生成されたフィードURL"
|
msgstr "生成されたフィードURL"
|
||||||
|
|
||||||
@@ -434,24 +468,20 @@ msgstr "グッズ"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Grape"
|
msgid "Grape"
|
||||||
msgstr ""
|
msgstr "グレープ"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Gray"
|
msgid "Gray"
|
||||||
msgstr ""
|
msgstr "グレー"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Green"
|
msgid "Green"
|
||||||
msgstr ""
|
msgstr "グリーン"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Id"
|
msgid "Id"
|
||||||
msgstr "ID"
|
msgstr "ID"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
|
|
||||||
msgstr "空でない場合は、'true' または 'false' に評価される式。 'false' の場合、このフィードの新しいエントリーは自動的に既読としてマークされます。"
|
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "If the entry doesn't entirely fit on the screen"
|
msgid "If the entry doesn't entirely fit on the screen"
|
||||||
msgstr "エントリーが画面に完全に収まらない場合"
|
msgstr "エントリーが画面に完全に収まらない場合"
|
||||||
@@ -470,15 +500,23 @@ msgstr "展開ビューでエントリーをスクロールすると、それら
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Indigo"
|
msgid "Indigo"
|
||||||
msgstr ""
|
msgstr "インディゴ"
|
||||||
|
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Initial Setup"
|
||||||
|
msgstr "初期設定"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Invalid password reset link. Please request a new one."
|
||||||
|
msgstr "無効なパスワードリセットリンクです。新しいリンクをリクエストしてください。"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "未読のままにする"
|
msgstr "未読のままにする"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
#: src/components/content/FeedEntries.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "キーボードショートカット"
|
msgstr "キーボードショートカット"
|
||||||
|
|
||||||
@@ -504,17 +542,17 @@ msgstr "ライト"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Lime"
|
msgid "Lime"
|
||||||
msgstr ""
|
msgstr "ライム"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "リンク"
|
msgstr "リンク"
|
||||||
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
msgid "Link to the documentation"
|
msgid "Link to the documentation"
|
||||||
msgstr ""
|
msgstr "ドキュメントへのリンク"
|
||||||
|
|
||||||
#: src/hooks/useAppLoading.ts
|
#: src/hooks/useAppLoading.ts
|
||||||
msgid "Loading profile..."
|
msgid "Loading profile..."
|
||||||
@@ -532,9 +570,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 "ログイン"
|
||||||
|
|
||||||
@@ -546,8 +584,8 @@ msgstr "ログアウト"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr "長押し"
|
msgstr "長押し"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "ユーザーの管理"
|
msgstr "ユーザーの管理"
|
||||||
|
|
||||||
@@ -555,21 +593,25 @@ msgstr "ユーザーの管理"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "すべて既読にする"
|
msgstr "すべて既読にする"
|
||||||
|
|
||||||
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "すべてのエントリーを既読にする"
|
msgstr "すべてのエントリーを既読にする"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "既読にする"
|
msgstr "既読にする"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "ここまで既読にする"
|
msgstr "ここまで既読にする"
|
||||||
|
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "Mark entries in this feed as read after this number of days. Leave empty to disable."
|
||||||
|
msgstr "この日数経過後に、このフィードのエントリを既読としてマークします。無効にするには空のままにしてください。"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Metrics"
|
msgid "Metrics"
|
||||||
msgstr "メトリックス"
|
msgstr "メトリックス"
|
||||||
@@ -586,15 +628,15 @@ msgstr "ページを下に移動"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "ページを上に移動"
|
msgstr "ページを上に移動"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/components/RelativeDate.tsx
|
#: src/components/RelativeDate.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr "該当なし"
|
msgstr "該当なし"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "名前"
|
msgstr "名前"
|
||||||
|
|
||||||
@@ -604,7 +646,7 @@ msgstr "名前を入力してサブスクリプションに移動します"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
|
msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
|
||||||
msgstr ""
|
msgstr "すべてのエントリーを既読にするとき、未読エントリーのある次のカテゴリ/フィードに移動する"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
@@ -615,12 +657,17 @@ msgstr "しない"
|
|||||||
msgid "New password"
|
msgid "New password"
|
||||||
msgstr "新しいパスワード"
|
msgstr "新しいパスワード"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "New Password"
|
||||||
|
msgstr "新しいパスワード"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "最新順"
|
msgstr "最新順"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "次へ"
|
msgstr "次へ"
|
||||||
|
|
||||||
@@ -728,7 +775,7 @@ msgstr "OPMLファイルは必要です"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Orange"
|
msgid "Orange"
|
||||||
msgstr ""
|
msgstr "オレンジ"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Order"
|
msgid "Order"
|
||||||
@@ -742,28 +789,34 @@ 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/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.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 "パスワード"
|
||||||
|
|
||||||
|
#: src/hooks/useValidationRules.ts
|
||||||
|
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||||
|
msgstr "パスワードは {minimumPasswordLength} 文字以上である必要があります"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "Password Recovery"
|
msgid "Password Recovery"
|
||||||
msgstr "パスワード回復"
|
msgstr "パスワード回復"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/hooks/useValidationRules.ts
|
||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "パスワードが一致しません"
|
msgstr "パスワードが一致しません"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Pink"
|
msgid "Pink"
|
||||||
msgstr ""
|
msgstr "ピンク"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "位置"
|
msgstr "位置"
|
||||||
|
|
||||||
@@ -773,22 +826,47 @@ msgstr "前へ"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Primary color"
|
msgid "Primary color"
|
||||||
msgstr ""
|
msgstr "プライマリカラー"
|
||||||
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
msgid "Profile"
|
msgid "Profile"
|
||||||
msgstr "プロフィール"
|
msgstr "プロフィール"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Push notification service"
|
||||||
|
msgstr "プッシュ通知サービス"
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Push notifications"
|
||||||
|
msgstr "プッシュ通知"
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
msgid "Push notifications are not configured in your user settings."
|
||||||
|
msgstr "ユーザー設定でプッシュ通知が設定されていません。"
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Push notifications are not enabled on this CommaFeed instance."
|
||||||
|
msgstr "この CommaFeed インスタンスではプッシュ通知が有効になっていません。"
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
msgid "Receive push notifications"
|
||||||
|
msgstr "プッシュ通知を受け取る"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Receive push notifications when new feed entries are discovered. Enable \"Receive push notifications\" in the settings of each feed for which you want to receive notifications."
|
||||||
|
msgstr "新しいフィードエントリが発見されたときにプッシュ通知を受け取ります。通知を受け取りたい各フィードの設定で「プッシュ通知を受け取る」を有効にしてください。"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "パスワードの回復"
|
msgstr "パスワードの回復"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Red"
|
msgid "Red"
|
||||||
msgstr ""
|
msgstr "レッド"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "リフレッシュ"
|
msgstr "リフレッシュ"
|
||||||
|
|
||||||
@@ -796,6 +874,11 @@ msgstr "リフレッシュ"
|
|||||||
msgid "Registrations are closed on this CommaFeed instance"
|
msgid "Registrations are closed on this CommaFeed instance"
|
||||||
msgstr "このCommaFeedインスタンスの登録は終了しています"
|
msgstr "このCommaFeedインスタンスの登録は終了しています"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Reset Password"
|
||||||
|
msgstr "パスワードをリセット"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "REST API"
|
msgid "REST API"
|
||||||
msgstr "REST API"
|
msgstr "REST API"
|
||||||
@@ -805,11 +888,12 @@ msgstr "REST API"
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr "右クリック"
|
msgstr "右クリック"
|
||||||
|
|
||||||
#: 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
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "保存"
|
msgstr "保存"
|
||||||
|
|
||||||
@@ -825,24 +909,25 @@ msgstr "エントリー間を移動するときにスムーズにスクロール
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr "スクロール"
|
msgstr "スクロール"
|
||||||
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "検索"
|
msgstr "検索"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
msgid "Search requires at least 3 characters"
|
|
||||||
msgstr "検索には少なくとも3文字が必要です"
|
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Select next unread feed/category"
|
msgid "Select next unread feed/category"
|
||||||
msgstr ""
|
msgstr "次の未読フィード/カテゴリを選択"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Select previous unread feed/category"
|
msgid "Select previous unread feed/category"
|
||||||
msgstr ""
|
msgstr "前の未読フィード/カテゴリを選択"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Server URL"
|
||||||
|
msgstr "サーバーURL"
|
||||||
|
|
||||||
#: 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"
|
||||||
@@ -918,9 +1003,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 "サインアップ"
|
||||||
|
|
||||||
@@ -933,21 +1018,21 @@ msgstr "何か悪いことが起きました..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Space"
|
msgstr "Space"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "スター"
|
msgstr "スター"
|
||||||
|
|
||||||
#: src/pages/app/FeedEntriesPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedEntriesPage.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 "購読する"
|
||||||
|
|
||||||
@@ -986,7 +1071,15 @@ msgstr "タグ"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Teal"
|
msgid "Teal"
|
||||||
msgstr ""
|
msgstr "ティール"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Test"
|
||||||
|
msgstr "テスト"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Test notification sent successfully."
|
||||||
|
msgstr "テスト通知が正常に送信されました。"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed will try to find the feed in the page."
|
msgid "The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed will try to find the feed in the page."
|
||||||
@@ -996,10 +1089,19 @@ msgstr "購読したいフィードのURL。ウェブサイトのURLを直接使
|
|||||||
msgid "Theme"
|
msgid "Theme"
|
||||||
msgstr "テーマ"
|
msgstr "テーマ"
|
||||||
|
|
||||||
|
#. placeholder {0}: feed.filterLegacy
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "This feed has a legacy filter that cannot be edited and is not applied. Please recreate the filter using the new expression editor. The legacy filter expression was: <0>{0}</0>"
|
||||||
|
msgstr "このフィードには、編集できず適用もされない古い形式のフィルタがあります。新しい式エディタを使用してフィルタを再作成してください。古いフィルタ式は次のとおりでした: <0>{0}</0>"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||||
msgstr "これはあなたのAPIキーです。いくつかの読み取り専用API操作に使用できます。これにより、Fever APIへのアクセスが可能になります。ページの下部のフォームを使用して新しいAPIキーを生成します。"
|
msgstr "これはあなたのAPIキーです。いくつかの読み取り専用API操作に使用できます。これにより、Fever APIへのアクセスが可能になります。ページの下部のフォームを使用して新しいAPIキーを生成します。"
|
||||||
|
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||||
|
msgstr "この設定により、一部のブラウザ(Safari など)でスクロールの問題が発生する可能性があります。"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "現在のエントリーの読み取りステータスを切り替えます"
|
msgstr "現在のエントリーの読み取りステータスを切り替えます"
|
||||||
@@ -1012,6 +1114,10 @@ msgstr "サイドバーを切り替える"
|
|||||||
msgid "Toggle starred status of current entry"
|
msgid "Toggle starred status of current entry"
|
||||||
msgstr "現在のエントリーのスターステータスを切り替える"
|
msgstr "現在のエントリーのスターステータスを切り替える"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Topic"
|
||||||
|
msgstr "トピック"
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "デモアカウントでCommaFeedを試す: demo/demo"
|
msgstr "デモアカウントでCommaFeedを試す: demo/demo"
|
||||||
@@ -1024,8 +1130,8 @@ msgstr "デモを試す!"
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "未読"
|
msgstr "未読"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "スターを外す"
|
msgstr "スターを外す"
|
||||||
@@ -1035,6 +1141,10 @@ msgstr "スターを外す"
|
|||||||
msgid "Unsubscribe"
|
msgid "Unsubscribe"
|
||||||
msgstr "退会"
|
msgstr "退会"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "User key"
|
||||||
|
msgstr "ユーザーキー"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "User name"
|
msgid "User name"
|
||||||
msgstr "ユーザー名"
|
msgstr "ユーザー名"
|
||||||
@@ -1046,7 +1156,7 @@ msgstr "ユーザー名またはメールアドレス"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Violet"
|
msgid "Violet"
|
||||||
msgstr ""
|
msgstr "バイオレット"
|
||||||
|
|
||||||
#: src/components/Alert.tsx
|
#: src/components/Alert.tsx
|
||||||
msgid "Warning"
|
msgid "Warning"
|
||||||
@@ -1056,9 +1166,13 @@ msgstr "警告"
|
|||||||
msgid "Website"
|
msgid "Website"
|
||||||
msgstr "ウェブサイト"
|
msgstr "ウェブサイト"
|
||||||
|
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||||
|
msgstr "ようこそ!CommaFeedを初めて実行するようです。開始するには管理者アカウントを作成してください。"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Yellow"
|
msgid "Yellow"
|
||||||
msgstr ""
|
msgstr "イエロー"
|
||||||
|
|
||||||
#: src/pages/app/FeedEntriesPage.tsx
|
#: src/pages/app/FeedEntriesPage.tsx
|
||||||
msgid "You don't have any subscriptions yet. Why not try adding one by clicking on the + sign at the top of the page?"
|
msgid "You don't have any subscriptions yet. Why not try adding one by clicking on the + sign at the top of the page?"
|
||||||
@@ -1067,3 +1181,7 @@ msgstr "まだサブスクリプションがありません。上部の + 記号
|
|||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Your feeds have been queued for refresh."
|
msgid "Your feeds have been queued for refresh."
|
||||||
msgstr "フィードの更新がキューに登録されました。"
|
msgstr "フィードの更新がキューに登録されました。"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Your password has been changed. You can now log in with your new password."
|
||||||
|
msgstr "パスワードが変更されました。新しいパスワードでログインできます。"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -17,10 +17,6 @@ msgstr ""
|
|||||||
msgid "<0>CommaFeed is an open-source project. Sources are hosted on </0><1>GitHub</1>."
|
msgid "<0>CommaFeed is an open-source project. Sources are hosted on </0><1>GitHub</1>."
|
||||||
msgstr "<0>CommaFeed é um projeto de código abrto. O código está hospedado no </0><1>GitHub</1>."
|
msgstr "<0>CommaFeed é um projeto de código abrto. O código está hospedado no </0><1>GitHub</1>."
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "<0>Complete syntax is available </0><1>here</1><2>.</2>"
|
|
||||||
msgstr "<0>Sintaxe completa disponível </0><1>aqui</1><2>.</2>"
|
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "<0>Have an account?</0><1>Log in!</1>"
|
msgid "<0>Have an account?</0><1>Log in!</1>"
|
||||||
msgstr "<0>Tem uma conta?</0><1>Faça login!</1>"
|
msgstr "<0>Tem uma conta?</0><1>Faça login!</1>"
|
||||||
@@ -33,11 +29,15 @@ msgstr "<0>Olá,</0><1>eu sou Jérémie da Bélgica e venho trabalhando no Comma
|
|||||||
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/pages/app/AboutPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Sobre"
|
msgstr "Sobre"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Access token"
|
||||||
|
msgstr "Token de acesso"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Actions"
|
msgid "Actions"
|
||||||
msgstr "Ações"
|
msgstr "Ações"
|
||||||
@@ -54,17 +54,22 @@ msgstr "Adicionar categoria"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Adicionar usuário"
|
msgstr "Adicionar usuário"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Administrador"
|
msgstr "Administrador"
|
||||||
|
|
||||||
#: src/pages/app/FeedEntriesPage.tsx
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
msgid "Admin user name"
|
||||||
#: src/components/header/Header.tsx
|
msgstr "Nome de usuário do administrador"
|
||||||
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedEntriesPage.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Todos"
|
msgstr "Todos"
|
||||||
|
|
||||||
@@ -93,6 +98,14 @@ msgstr "Aviso"
|
|||||||
msgid "API key"
|
msgid "API key"
|
||||||
msgstr "chave de API"
|
msgstr "chave de API"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "API token"
|
||||||
|
msgstr "Token de API"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "App token"
|
||||||
|
msgstr "Token do aplicativo"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Are you sure you want to delete category <0>{categoryName}</0>?"
|
msgid "Are you sure you want to delete category <0>{categoryName}</0>?"
|
||||||
msgstr "Tem certeza de que deseja excluir a categoria <0>{categoryName}</0>?"
|
msgstr "Tem certeza de que deseja excluir a categoria <0>{categoryName}</0>?"
|
||||||
@@ -122,14 +135,15 @@ msgid "Asc"
|
|||||||
msgstr "Asc"
|
msgstr "Asc"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Available variables are 'title', 'content', 'url' 'author' and 'categories' and their content is converted to lower case to ease string comparison."
|
msgid "Auto-mark as read"
|
||||||
msgstr "As variáveis disponíveis são 'título', 'conteúdo', 'url' 'autor' e 'categorias' e seu conteúdo é convertido em letras minúsculas para facilitar a comparação de strings."
|
msgstr "Marcar automaticamente como lido"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Back"
|
msgid "Back"
|
||||||
msgstr "Voltar"
|
msgstr "Voltar"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Voltar para logar"
|
msgstr "Voltar para logar"
|
||||||
|
|
||||||
@@ -137,39 +151,44 @@ msgstr "Voltar para logar"
|
|||||||
msgid "Blue"
|
msgid "Blue"
|
||||||
msgstr "Azul"
|
msgstr "Azul"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "Browser extension"
|
||||||
|
msgstr "Extensão do navegador"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Browser extension required for Chrome"
|
msgid "Browser extension required for Chrome"
|
||||||
msgstr "Extensão para o Chrome necessária"
|
msgstr "Extensão para o Chrome necessária"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
msgid "Browser extention"
|
|
||||||
msgstr "Extensão do navegador"
|
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr "Aba do navegador"
|
msgstr "Aba do navegador"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
msgid "Build a filter expression to indicate what you want to read. Entries that don't match will be marked as read automatically."
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
msgstr "Crie uma expressão de filtro para indicar o que você deseja ler. As entradas que não corresponderem serão marcadas como lidas automaticamente."
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.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
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Cancelar"
|
msgstr "Cancelar"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Categoria"
|
msgstr "Categoria"
|
||||||
|
|
||||||
@@ -209,11 +228,11 @@ msgstr "CommaFeed versão {version} ({revision})."
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Compacto"
|
msgstr "Compacto"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Confirmar"
|
msgstr "Confirmar"
|
||||||
|
|
||||||
@@ -221,10 +240,19 @@ msgstr "Confirmar"
|
|||||||
msgid "Confirm password"
|
msgid "Confirm password"
|
||||||
msgstr "Confirmar senha"
|
msgstr "Confirmar senha"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Confirm Password"
|
||||||
|
msgstr "Confirmar senha"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Cozy"
|
msgid "Cozy"
|
||||||
msgstr "Aconchegante"
|
msgstr "Aconchegante"
|
||||||
|
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Create Admin Account"
|
||||||
|
msgstr "Criar conta de administrador"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Ctrl"
|
msgid "Ctrl"
|
||||||
msgstr "Ctrl"
|
msgstr "Ctrl"
|
||||||
@@ -249,8 +277,8 @@ msgstr "Código JS personalizado que será executado ao carregar a página"
|
|||||||
msgid "Cyan"
|
msgid "Cyan"
|
||||||
msgstr "Ciano"
|
msgstr "Ciano"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Dark"
|
msgid "Dark"
|
||||||
msgstr "Escuro"
|
msgstr "Escuro"
|
||||||
|
|
||||||
@@ -258,6 +286,10 @@ msgstr "Escuro"
|
|||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Data de criação"
|
msgstr "Data de criação"
|
||||||
|
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "days"
|
||||||
|
msgstr "dias"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Excluir"
|
msgstr "Excluir"
|
||||||
@@ -283,14 +315,18 @@ msgstr "Desc"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr "Detalhado"
|
msgstr "Detalhado"
|
||||||
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
msgid "Disable \"Pull to refresh\" browser behavior"
|
||||||
|
msgstr "Desativar o comportamento do navegador \"Puxar para atualizar\""
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Exibir"
|
msgstr "Exibir"
|
||||||
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/app/DonatePage.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr "Doar"
|
msgstr "Doar"
|
||||||
|
|
||||||
@@ -302,11 +338,13 @@ 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/pages/auth/PasswordRecoveryPage.tsx
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "E-mail"
|
msgstr "E-mail"
|
||||||
|
|
||||||
@@ -319,8 +357,8 @@ msgstr "Endereço de e-mail"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Editar usuário"
|
msgstr "Editar usuário"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Ativado"
|
msgstr "Ativado"
|
||||||
|
|
||||||
@@ -344,10 +382,6 @@ msgstr "Cabeçalho das entredas"
|
|||||||
msgid "Error"
|
msgid "Error"
|
||||||
msgstr "Erro"
|
msgstr "Erro"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "Example: {example}."
|
|
||||||
msgstr "Exemplo: {exemplo}."
|
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Expanded"
|
msgid "Expanded"
|
||||||
msgstr "Expandido"
|
msgstr "Expandido"
|
||||||
@@ -356,8 +390,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/pages/WelcomePage.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/pages/WelcomePage.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr "Opções da extensão"
|
msgstr "Opções da extensão"
|
||||||
|
|
||||||
@@ -365,9 +399,9 @@ msgstr "Opções da extensão"
|
|||||||
msgid "Feed name"
|
msgid "Feed name"
|
||||||
msgstr "Nome do feed"
|
msgstr "Nome do feed"
|
||||||
|
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/content/add/Subscribe.tsx
|
||||||
#: src/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"
|
||||||
|
|
||||||
@@ -399,9 +433,9 @@ msgstr "Forçar a atualização de feeds não está disponível."
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Esqueceu a senha?"
|
msgstr "Esqueceu a senha?"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.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."
|
||||||
|
|
||||||
@@ -409,9 +443,9 @@ 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/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "URL do feed gerado"
|
msgstr "URL do feed gerado"
|
||||||
|
|
||||||
@@ -448,10 +482,6 @@ msgstr "Verde"
|
|||||||
msgid "Id"
|
msgid "Id"
|
||||||
msgstr "ID"
|
msgstr "ID"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
|
|
||||||
msgstr "Se não estiver vazio, uma expressão avaliada como 'true' ou 'false'. "
|
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "If the entry doesn't entirely fit on the screen"
|
msgid "If the entry doesn't entirely fit on the screen"
|
||||||
msgstr "Se a entrafa não couber por completo na tela"
|
msgstr "Se a entrafa não couber por completo na tela"
|
||||||
@@ -472,13 +502,21 @@ msgstr "Na visualização expandida, rolar pelas entradas marca-as como lidas"
|
|||||||
msgid "Indigo"
|
msgid "Indigo"
|
||||||
msgstr "Índigo"
|
msgstr "Índigo"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Initial Setup"
|
||||||
|
msgstr "Configuração inicial"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Invalid password reset link. Please request a new one."
|
||||||
|
msgstr "Link de redefinição de senha inválido. Solicite um novo."
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Manter não lido"
|
msgstr "Manter não lido"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
#: src/components/content/FeedEntries.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Atalhos de teclado"
|
msgstr "Atalhos de teclado"
|
||||||
|
|
||||||
@@ -506,9 +544,9 @@ msgstr "Claro"
|
|||||||
msgid "Lime"
|
msgid "Lime"
|
||||||
msgstr "Lima"
|
msgstr "Lima"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "Link"
|
msgstr "Link"
|
||||||
|
|
||||||
@@ -532,9 +570,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"
|
||||||
|
|
||||||
@@ -546,8 +584,8 @@ msgstr "Sair"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr "Pressione e segure"
|
msgstr "Pressione e segure"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Gerenciar usuários"
|
msgstr "Gerenciar usuários"
|
||||||
|
|
||||||
@@ -555,21 +593,25 @@ 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/MarkAllAsReadConfirmationDialog.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/MarkAllAsReadConfirmationDialog.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/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Marcar como lido"
|
msgstr "Marcar como lido"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.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"
|
||||||
|
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "Mark entries in this feed as read after this number of days. Leave empty to disable."
|
||||||
|
msgstr "Marcar as entradas neste feed como lidas após este número de dias. Deixe vazio para desativar."
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Metrics"
|
msgid "Metrics"
|
||||||
msgstr "Métricas"
|
msgstr "Métricas"
|
||||||
@@ -586,15 +628,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/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/components/RelativeDate.tsx
|
#: src/components/RelativeDate.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr "N/D"
|
msgstr "N/D"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Nome"
|
msgstr "Nome"
|
||||||
|
|
||||||
@@ -615,12 +657,17 @@ msgstr "Nunca"
|
|||||||
msgid "New password"
|
msgid "New password"
|
||||||
msgstr "Nova senha"
|
msgstr "Nova senha"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "New Password"
|
||||||
|
msgstr "Nova senha"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Mais novo primeiro"
|
msgstr "Mais novo primeiro"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Próximo"
|
msgstr "Próximo"
|
||||||
|
|
||||||
@@ -742,19 +789,25 @@ 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/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.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"
|
||||||
|
|
||||||
|
#: src/hooks/useValidationRules.ts
|
||||||
|
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||||
|
msgstr "A senha deve ter pelo menos {minimumPasswordLength} caracteres"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "Password Recovery"
|
msgid "Password Recovery"
|
||||||
msgstr "Recuperação de Senha"
|
msgstr "Recuperação de Senha"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/hooks/useValidationRules.ts
|
||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Senhas não coincidem"
|
msgstr "Senhas não coincidem"
|
||||||
|
|
||||||
@@ -762,8 +815,8 @@ msgstr "Senhas não coincidem"
|
|||||||
msgid "Pink"
|
msgid "Pink"
|
||||||
msgstr "Rosa"
|
msgstr "Rosa"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Posição"
|
msgstr "Posição"
|
||||||
|
|
||||||
@@ -779,6 +832,31 @@ msgstr "Cor primária"
|
|||||||
msgid "Profile"
|
msgid "Profile"
|
||||||
msgstr "Perfil"
|
msgstr "Perfil"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Push notification service"
|
||||||
|
msgstr "Serviço de notificação push"
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Push notifications"
|
||||||
|
msgstr "Notificações push"
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
msgid "Push notifications are not configured in your user settings."
|
||||||
|
msgstr "As notificações push não estão configuradas nas suas configurações de usuário."
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Push notifications are not enabled on this CommaFeed instance."
|
||||||
|
msgstr "As notificações push não estão ativadas nesta instância do CommaFeed."
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
msgid "Receive push notifications"
|
||||||
|
msgstr "Receber notificações push"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Receive push notifications when new feed entries are discovered. Enable \"Receive push notifications\" in the settings of each feed for which you want to receive notifications."
|
||||||
|
msgstr "Receba notificações push quando novas entradas de feed forem descobertas. Ative \"Receber notificações push\" nas configurações de cada feed para o qual deseja receber notificações."
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Recuperar senha"
|
msgstr "Recuperar senha"
|
||||||
@@ -787,8 +865,8 @@ msgstr "Recuperar senha"
|
|||||||
msgid "Red"
|
msgid "Red"
|
||||||
msgstr "Vermelho"
|
msgstr "Vermelho"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Atualizar"
|
msgstr "Atualizar"
|
||||||
|
|
||||||
@@ -796,6 +874,11 @@ msgstr "Atualizar"
|
|||||||
msgid "Registrations are closed on this CommaFeed instance"
|
msgid "Registrations are closed on this CommaFeed instance"
|
||||||
msgstr "Os registros estão fechados nesta instância do CommaFeed"
|
msgstr "Os registros estão fechados nesta instância do CommaFeed"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Reset Password"
|
||||||
|
msgstr "Redefinir senha"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "REST API"
|
msgid "REST API"
|
||||||
msgstr "API REST"
|
msgstr "API REST"
|
||||||
@@ -805,11 +888,12 @@ msgstr "API REST"
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr "Clique com o botão direito"
|
msgstr "Clique com o botão direito"
|
||||||
|
|
||||||
#: 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
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Salvar"
|
msgstr "Salvar"
|
||||||
|
|
||||||
@@ -825,17 +909,13 @@ msgstr "Rolar suavemente ao navegar entre as entradas"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr "Deslizar"
|
msgstr "Deslizar"
|
||||||
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Pesquisar"
|
msgstr "Pesquisar"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
msgid "Search requires at least 3 characters"
|
|
||||||
msgstr "Pesquisa requer pelo menos 3 caracteres"
|
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Select next unread feed/category"
|
msgid "Select next unread feed/category"
|
||||||
msgstr "Selecionar próximo feed/categoria não lido"
|
msgstr "Selecionar próximo feed/categoria não lido"
|
||||||
@@ -844,6 +924,11 @@ msgstr "Selecionar próximo feed/categoria não lido"
|
|||||||
msgid "Select previous unread feed/category"
|
msgid "Select previous unread feed/category"
|
||||||
msgstr "Selecionar feed/categoria não lido anterior"
|
msgstr "Selecionar feed/categoria não lido anterior"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Server URL"
|
||||||
|
msgstr "URL do servidor"
|
||||||
|
|
||||||
#: 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"
|
||||||
@@ -918,9 +1003,9 @@ msgstr "Mostrar contagem de não lidos no favion da aba"
|
|||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr "Mostrar contagem de não lidos no título da aba"
|
msgstr "Mostrar contagem de não lidos no título da aba"
|
||||||
|
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
#: src/pages/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"
|
||||||
|
|
||||||
@@ -933,21 +1018,21 @@ msgstr "Algo ruim acabou de acontecer..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Espaço"
|
msgstr "Espaço"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "Estrela"
|
msgstr "Estrela"
|
||||||
|
|
||||||
#: src/pages/app/FeedEntriesPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedEntriesPage.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"
|
||||||
|
|
||||||
@@ -988,6 +1073,14 @@ msgstr "Etiquetas"
|
|||||||
msgid "Teal"
|
msgid "Teal"
|
||||||
msgstr "Azul petróleo"
|
msgstr "Azul petróleo"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Test"
|
||||||
|
msgstr "Teste"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Test notification sent successfully."
|
||||||
|
msgstr "Notificação de teste enviada com sucesso."
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed will try to find the feed in the page."
|
msgid "The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed will try to find the feed in the page."
|
||||||
msgstr "A URL do feed que você deseja assinar. "
|
msgstr "A URL do feed que você deseja assinar. "
|
||||||
@@ -996,10 +1089,19 @@ msgstr "A URL do feed que você deseja assinar. "
|
|||||||
msgid "Theme"
|
msgid "Theme"
|
||||||
msgstr "Tema"
|
msgstr "Tema"
|
||||||
|
|
||||||
|
#. placeholder {0}: feed.filterLegacy
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "This feed has a legacy filter that cannot be edited and is not applied. Please recreate the filter using the new expression editor. The legacy filter expression was: <0>{0}</0>"
|
||||||
|
msgstr "Este feed tem um filtro legado que não pode ser editado e não é aplicado. Recrie o filtro usando o novo editor de expressões. A expressão do filtro legado era: <0>{0}</0>"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||||
msgstr "Esta é sua chave de API. Ela pode ser usada para algumas operações somente leitura da API e concede acesso à API do Fever. Use o formulário abaixo para gerar uma nova chave de API"
|
msgstr "Esta é sua chave de API. Ela pode ser usada para algumas operações somente leitura da API e concede acesso à API do Fever. Use o formulário abaixo para gerar uma nova chave de API"
|
||||||
|
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||||
|
msgstr "Esta configuração pode causar problemas de rolagem em alguns navegadores (ex: Safari)"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Alternar o status de leitura da entrada atual"
|
msgstr "Alternar o status de leitura da entrada atual"
|
||||||
@@ -1012,6 +1114,10 @@ msgstr "Alternar barra lateral"
|
|||||||
msgid "Toggle starred status of current entry"
|
msgid "Toggle starred status of current entry"
|
||||||
msgstr "Alternar estrela da entrada atual"
|
msgstr "Alternar estrela da entrada atual"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Topic"
|
||||||
|
msgstr "Tópico"
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Experimente o CommaFeed com a conta demo: demo/demo"
|
msgstr "Experimente o CommaFeed com a conta demo: demo/demo"
|
||||||
@@ -1024,8 +1130,8 @@ msgstr "Teste o demo!"
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Não lido"
|
msgstr "Não lido"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "Desestrelar"
|
msgstr "Desestrelar"
|
||||||
@@ -1035,6 +1141,10 @@ msgstr "Desestrelar"
|
|||||||
msgid "Unsubscribe"
|
msgid "Unsubscribe"
|
||||||
msgstr "Cancelar inscrição"
|
msgstr "Cancelar inscrição"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "User key"
|
||||||
|
msgstr "Chave do usuário"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "User name"
|
msgid "User name"
|
||||||
msgstr "Nome de usuário"
|
msgstr "Nome de usuário"
|
||||||
@@ -1056,6 +1166,10 @@ msgstr "Aviso"
|
|||||||
msgid "Website"
|
msgid "Website"
|
||||||
msgstr "Site"
|
msgstr "Site"
|
||||||
|
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||||
|
msgstr "Bem-vindo! Esta parece ser a primeira vez que você está executando o CommaFeed. Crie uma conta de administrador para começar."
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Yellow"
|
msgid "Yellow"
|
||||||
msgstr "Amarelo"
|
msgstr "Amarelo"
|
||||||
@@ -1067,3 +1181,7 @@ msgstr "Você ainda não tem nenhuma assinatura. "
|
|||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Your feeds have been queued for refresh."
|
msgid "Your feeds have been queued for refresh."
|
||||||
msgstr "Seus feed foram enfileirados para atualização"
|
msgstr "Seus feed foram enfileirados para atualização"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Your password has been changed. You can now log in with your new password."
|
||||||
|
msgstr "Sua senha foi alterada. Agora você pode fazer login com sua nova senha."
|
||||||
|
|||||||
@@ -17,10 +17,6 @@ msgstr ""
|
|||||||
msgid "<0>CommaFeed is an open-source project. Sources are hosted on </0><1>GitHub</1>."
|
msgid "<0>CommaFeed is an open-source project. Sources are hosted on </0><1>GitHub</1>."
|
||||||
msgstr "<0>CommaFeed - это проект с открытым исходным кодом. Исходный код доступен по адресу </0><1>GitHub</1>."
|
msgstr "<0>CommaFeed - это проект с открытым исходным кодом. Исходный код доступен по адресу </0><1>GitHub</1>."
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "<0>Complete syntax is available </0><1>here</1><2>.</2>"
|
|
||||||
msgstr "<0>Полный синтаксис доступен </0><1>здесь</1><2>.</2>"
|
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "<0>Have an account?</0><1>Log in!</1>"
|
msgid "<0>Have an account?</0><1>Log in!</1>"
|
||||||
msgstr "<0>Есть аккаунт?</0><1>Войти!</1>"
|
msgstr "<0>Есть аккаунт?</0><1>Войти!</1>"
|
||||||
@@ -33,11 +29,15 @@ 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/pages/app/AboutPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "О CommaFeed"
|
msgstr "О CommaFeed"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Access token"
|
||||||
|
msgstr "Токен доступа"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Actions"
|
msgid "Actions"
|
||||||
msgstr "Действия"
|
msgstr "Действия"
|
||||||
@@ -54,17 +54,22 @@ msgstr "Добавить категорию"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Добавить пользователя"
|
msgstr "Добавить пользователя"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Админ"
|
msgstr "Админ"
|
||||||
|
|
||||||
#: src/pages/app/FeedEntriesPage.tsx
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
msgid "Admin user name"
|
||||||
#: src/components/header/Header.tsx
|
msgstr "Имя администратора"
|
||||||
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedEntriesPage.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Все"
|
msgstr "Все"
|
||||||
|
|
||||||
@@ -93,6 +98,14 @@ msgstr "Объявление"
|
|||||||
msgid "API key"
|
msgid "API key"
|
||||||
msgstr "Ключ API"
|
msgstr "Ключ API"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "API token"
|
||||||
|
msgstr "API токен"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "App token"
|
||||||
|
msgstr "Токен приложения"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Are you sure you want to delete category <0>{categoryName}</0>?"
|
msgid "Are you sure you want to delete category <0>{categoryName}</0>?"
|
||||||
msgstr "Вы уверены, что хотите удалить категорию <0>{categoryName}</0>?"
|
msgstr "Вы уверены, что хотите удалить категорию <0>{categoryName}</0>?"
|
||||||
@@ -122,54 +135,60 @@ msgid "Asc"
|
|||||||
msgstr "По возрастанию"
|
msgstr "По возрастанию"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Available variables are 'title', 'content', 'url' 'author' and 'categories' and their content is converted to lower case to ease string comparison."
|
msgid "Auto-mark as read"
|
||||||
msgstr "Доступными переменными являются «заголовок», «контент», «url», «автор» и «категории», и их содержимое преобразуется в нижний регистр для облегчения сравнения строк."
|
msgstr "Автоматически помечать как прочитанное"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Back"
|
msgid "Back"
|
||||||
msgstr "Назад"
|
msgstr "Назад"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Вернуться к входу"
|
msgstr "Вернуться к входу"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Blue"
|
msgid "Blue"
|
||||||
msgstr ""
|
msgstr "Синий"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "Browser extension"
|
||||||
|
msgstr "Расширение для браузера"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Browser extension required for Chrome"
|
msgid "Browser extension required for Chrome"
|
||||||
msgstr "Для браузера Chrome требуется расширение"
|
msgstr "Для браузера Chrome требуется расширение"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
msgid "Browser extention"
|
|
||||||
msgstr "Расширение для браузера"
|
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr "Вкладка браузера"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
msgid "Build a filter expression to indicate what you want to read. Entries that don't match will be marked as read automatically."
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
msgstr "Создайте выражение фильтра, чтобы указать, что вы хотите читать. Записи, которые не соответствуют выражению, будут автоматически помечены как прочитанные."
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.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
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Отмена"
|
msgstr "Отмена"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Категория"
|
msgstr "Категория"
|
||||||
|
|
||||||
@@ -187,7 +206,7 @@ msgstr "Закрыть меню"
|
|||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Cmd"
|
msgid "Cmd"
|
||||||
msgstr ""
|
msgstr "Cmd"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
@@ -209,11 +228,11 @@ msgstr "CommaFeed версии {version} ({revision})."
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Компактный"
|
msgstr "Компактный"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Подтвердить"
|
msgstr "Подтвердить"
|
||||||
|
|
||||||
@@ -221,10 +240,19 @@ msgstr "Подтвердить"
|
|||||||
msgid "Confirm password"
|
msgid "Confirm password"
|
||||||
msgstr "Подтвердить пароль"
|
msgstr "Подтвердить пароль"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Confirm Password"
|
||||||
|
msgstr "Подтвердите пароль"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Cozy"
|
msgid "Cozy"
|
||||||
msgstr "Уютно"
|
msgstr "Уютно"
|
||||||
|
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Create Admin Account"
|
||||||
|
msgstr "Создать учетную запись администратора"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Ctrl"
|
msgid "Ctrl"
|
||||||
msgstr "Ctrl"
|
msgstr "Ctrl"
|
||||||
@@ -247,10 +275,10 @@ msgstr "Пользовательский JS-код, который будет в
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Cyan"
|
msgid "Cyan"
|
||||||
msgstr ""
|
msgstr "Голубой"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Dark"
|
msgid "Dark"
|
||||||
msgstr "Темная"
|
msgstr "Темная"
|
||||||
|
|
||||||
@@ -258,6 +286,10 @@ msgstr "Темная"
|
|||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Дата создания"
|
msgstr "Дата создания"
|
||||||
|
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "days"
|
||||||
|
msgstr "дней"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Удалить"
|
msgstr "Удалить"
|
||||||
@@ -283,14 +315,18 @@ msgstr "По убыванию"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr "Подробно"
|
msgstr "Подробно"
|
||||||
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
msgid "Disable \"Pull to refresh\" browser behavior"
|
||||||
|
msgstr "Отключить поведение браузера «Потяните для обновления»"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Отображение"
|
msgstr "Отображение"
|
||||||
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/app/DonatePage.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr "Пожертвование"
|
msgstr "Пожертвование"
|
||||||
|
|
||||||
@@ -302,11 +338,13 @@ msgstr "Скачать"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "Перетащите ссылку на панель закладок"
|
msgstr "Перетащите ссылку на панель закладок"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "Электронная почта"
|
msgstr "Электронная почта"
|
||||||
|
|
||||||
@@ -319,8 +357,8 @@ msgstr "Адрес электронной почты"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Редактировать пользователя"
|
msgstr "Редактировать пользователя"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Включено"
|
msgstr "Включено"
|
||||||
|
|
||||||
@@ -334,20 +372,16 @@ msgstr "Введите текущий пароль, чтобы изменить
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Entries to keep above the selected entry when scrolling"
|
msgid "Entries to keep above the selected entry when scrolling"
|
||||||
msgstr ""
|
msgstr "Количество записей, которые должны оставаться над выбранной записью при прокрутке"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Entry headers"
|
msgid "Entry headers"
|
||||||
msgstr ""
|
msgstr "Заголовки записей"
|
||||||
|
|
||||||
#: src/components/Alert.tsx
|
#: src/components/Alert.tsx
|
||||||
msgid "Error"
|
msgid "Error"
|
||||||
msgstr "Ошибка"
|
msgstr "Ошибка"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "Example: {example}."
|
|
||||||
msgstr "Пример: {пример}."
|
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Expanded"
|
msgid "Expanded"
|
||||||
msgstr "Расширенный"
|
msgstr "Расширенный"
|
||||||
@@ -356,8 +390,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/pages/WelcomePage.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/pages/WelcomePage.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr "Параметры расширения"
|
msgstr "Параметры расширения"
|
||||||
|
|
||||||
@@ -365,9 +399,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-адрес фида"
|
||||||
|
|
||||||
@@ -389,19 +423,19 @@ msgstr "Выражение фильтрации"
|
|||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Font size"
|
msgid "Font size"
|
||||||
msgstr ""
|
msgstr "Размер шрифта"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Force fetching feeds is not yet available."
|
msgid "Force fetching feeds is not yet available."
|
||||||
msgstr ""
|
msgstr "Принудительное получение фидов пока недоступно."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Забыли пароль?"
|
msgstr "Забыли пароль?"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "Сначала сгенерируйте ключ API в своем профиле."
|
msgstr "Сначала сгенерируйте ключ API в своем профиле."
|
||||||
|
|
||||||
@@ -409,9 +443,9 @@ msgstr "Сначала сгенерируйте ключ API в своем пр
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "Создать новый ключ API"
|
msgstr "Создать новый ключ API"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "Сгенерированный URL фида"
|
msgstr "Сгенерированный URL фида"
|
||||||
|
|
||||||
@@ -434,24 +468,20 @@ msgstr "Сладости"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Grape"
|
msgid "Grape"
|
||||||
msgstr ""
|
msgstr "Виноградный"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Gray"
|
msgid "Gray"
|
||||||
msgstr ""
|
msgstr "Серый"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Green"
|
msgid "Green"
|
||||||
msgstr ""
|
msgstr "Зеленый"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Id"
|
msgid "Id"
|
||||||
msgstr "Идентификатор"
|
msgstr "Идентификатор"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
|
|
||||||
msgstr "Если не пусто, то выражение, оценивающееся как 'true' или 'false'. Если false, то новые записи для этой ленты будут автоматически помечаться как прочитанные."
|
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "If the entry doesn't entirely fit on the screen"
|
msgid "If the entry doesn't entirely fit on the screen"
|
||||||
msgstr "Если запись не помещается на экране полностью"
|
msgstr "Если запись не помещается на экране полностью"
|
||||||
@@ -470,15 +500,23 @@ msgstr "В развернутом виде прокрутка записей п
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Indigo"
|
msgid "Indigo"
|
||||||
msgstr ""
|
msgstr "Индиго"
|
||||||
|
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Initial Setup"
|
||||||
|
msgstr "Начальная настройка"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Invalid password reset link. Please request a new one."
|
||||||
|
msgstr "Неверная ссылка для сброса пароля. Пожалуйста, запросите новую."
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Оставить непрочитанным"
|
msgstr "Оставить непрочитанным"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
#: src/components/content/FeedEntries.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Сочетания клавиш"
|
msgstr "Сочетания клавиш"
|
||||||
|
|
||||||
@@ -504,17 +542,17 @@ msgstr "Светлая"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Lime"
|
msgid "Lime"
|
||||||
msgstr ""
|
msgstr "Лаймовый"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "Ссылка"
|
msgstr "Ссылка"
|
||||||
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
msgid "Link to the documentation"
|
msgid "Link to the documentation"
|
||||||
msgstr ""
|
msgstr "Ссылка на документацию"
|
||||||
|
|
||||||
#: src/hooks/useAppLoading.ts
|
#: src/hooks/useAppLoading.ts
|
||||||
msgid "Loading profile..."
|
msgid "Loading profile..."
|
||||||
@@ -532,9 +570,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 "Войти"
|
||||||
|
|
||||||
@@ -546,8 +584,8 @@ msgstr "Выйти"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr "Долгое нажатие"
|
msgstr "Долгое нажатие"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Управление пользователями"
|
msgstr "Управление пользователями"
|
||||||
|
|
||||||
@@ -555,21 +593,25 @@ msgstr "Управление пользователями"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "Отметить все как прочитанное"
|
msgstr "Отметить все как прочитанное"
|
||||||
|
|
||||||
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "Отметить все записи как прочитанные"
|
msgstr "Отметить все записи как прочитанные"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Отметить как прочитанное"
|
msgstr "Отметить как прочитанное"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "Отметить как прочитанное до этого места"
|
msgstr "Отметить как прочитанное до этого места"
|
||||||
|
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "Mark entries in this feed as read after this number of days. Leave empty to disable."
|
||||||
|
msgstr "Помечать записи в этом фиде как прочитанные через указанное количество дней. Оставьте пустым, чтобы отключить."
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Metrics"
|
msgid "Metrics"
|
||||||
msgstr "Метрики"
|
msgstr "Метрики"
|
||||||
@@ -586,15 +628,15 @@ msgstr "Переместить страницу вниз"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "Переместить страницу вверх"
|
msgstr "Переместить страницу вверх"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/components/RelativeDate.tsx
|
#: src/components/RelativeDate.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr "Н/Д"
|
msgstr "Н/Д"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Имя"
|
msgstr "Имя"
|
||||||
|
|
||||||
@@ -604,7 +646,7 @@ msgstr "Перейдите к подписке, введя ее имя."
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
|
msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
|
||||||
msgstr ""
|
msgstr "Переходить к следующей категории/фиду с непрочитанными записями при пометке всех записей как прочитанных"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
@@ -615,12 +657,17 @@ msgstr "Никогда"
|
|||||||
msgid "New password"
|
msgid "New password"
|
||||||
msgstr "Новый пароль"
|
msgstr "Новый пароль"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "New Password"
|
||||||
|
msgstr "Новый пароль"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Сначала новые"
|
msgstr "Сначала новые"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Следующий"
|
msgstr "Следующий"
|
||||||
|
|
||||||
@@ -638,7 +685,7 @@ msgstr "Записей больше нет"
|
|||||||
|
|
||||||
#: src/components/content/ShareButtons.tsx
|
#: src/components/content/ShareButtons.tsx
|
||||||
msgid "No sharing options available."
|
msgid "No sharing options available."
|
||||||
msgstr ""
|
msgstr "Нет доступных вариантов для обмена."
|
||||||
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
msgid "Nothing found"
|
msgid "Nothing found"
|
||||||
@@ -650,11 +697,11 @@ msgstr "Сначала самые старые"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "On desktop"
|
msgid "On desktop"
|
||||||
msgstr ""
|
msgstr "На ПК"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "On mobile"
|
msgid "On mobile"
|
||||||
msgstr ""
|
msgstr "На телефоне"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "On mobile, show action buttons at the bottom of the screen"
|
msgid "On mobile, show action buttons at the bottom of the screen"
|
||||||
@@ -662,7 +709,7 @@ msgstr "На мобильных устройствах отображать кн
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Only applies to compact, cozy and detailed modes"
|
msgid "Only applies to compact, cozy and detailed modes"
|
||||||
msgstr ""
|
msgstr "Применяется только к компактному, уютному и подробному режимам"
|
||||||
|
|
||||||
#: src/pages/ErrorPage.tsx
|
#: src/pages/ErrorPage.tsx
|
||||||
msgid "Oops!"
|
msgid "Oops!"
|
||||||
@@ -728,7 +775,7 @@ msgstr "Необходим файл OPML"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Orange"
|
msgid "Orange"
|
||||||
msgstr ""
|
msgstr "Оранжевый"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Order"
|
msgid "Order"
|
||||||
@@ -742,28 +789,34 @@ 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/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.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 "Пароль"
|
||||||
|
|
||||||
|
#: src/hooks/useValidationRules.ts
|
||||||
|
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||||
|
msgstr "Пароль должен содержать не менее {minimumPasswordLength} символов"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "Password Recovery"
|
msgid "Password Recovery"
|
||||||
msgstr "Восстановление пароля"
|
msgstr "Восстановление пароля"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/hooks/useValidationRules.ts
|
||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Пароли не совпадают"
|
msgstr "Пароли не совпадают"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Pink"
|
msgid "Pink"
|
||||||
msgstr ""
|
msgstr "Розовый"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Позиция"
|
msgstr "Позиция"
|
||||||
|
|
||||||
@@ -773,22 +826,47 @@ msgstr "Предыдущий"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Primary color"
|
msgid "Primary color"
|
||||||
msgstr ""
|
msgstr "Основной цвет"
|
||||||
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
msgid "Profile"
|
msgid "Profile"
|
||||||
msgstr "Профиль"
|
msgstr "Профиль"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Push notification service"
|
||||||
|
msgstr "Служба пуш-уведомлений"
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Push notifications"
|
||||||
|
msgstr "Пуш-уведомления"
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
msgid "Push notifications are not configured in your user settings."
|
||||||
|
msgstr "Пуш-уведомления не настроены в ваших пользовательских настройках."
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Push notifications are not enabled on this CommaFeed instance."
|
||||||
|
msgstr "Пуш-уведомления не включены в этом экземпляре CommaFeed."
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
msgid "Receive push notifications"
|
||||||
|
msgstr "Получать пуш-уведомления"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Receive push notifications when new feed entries are discovered. Enable \"Receive push notifications\" in the settings of each feed for which you want to receive notifications."
|
||||||
|
msgstr "Получайте пуш-уведомления при обнаружении новых записей в фиде. Включите «Получать пуш-уведомления» в настройках каждого фида, для которого вы хотите получать уведомления."
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Восстановить пароль"
|
msgstr "Восстановить пароль"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Red"
|
msgid "Red"
|
||||||
msgstr ""
|
msgstr "Красный"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Обновить"
|
msgstr "Обновить"
|
||||||
|
|
||||||
@@ -796,6 +874,11 @@ msgstr "Обновить"
|
|||||||
msgid "Registrations are closed on this CommaFeed instance"
|
msgid "Registrations are closed on this CommaFeed instance"
|
||||||
msgstr "Регистрация закрыта для этого экземпляра CommaFeed."
|
msgstr "Регистрация закрыта для этого экземпляра CommaFeed."
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Reset Password"
|
||||||
|
msgstr "Сброс пароля"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "REST API"
|
msgid "REST API"
|
||||||
msgstr "REST API"
|
msgstr "REST API"
|
||||||
@@ -805,11 +888,12 @@ msgstr "REST API"
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr "Правый клик"
|
msgstr "Правый клик"
|
||||||
|
|
||||||
#: 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
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Сохранить"
|
msgstr "Сохранить"
|
||||||
|
|
||||||
@@ -825,24 +909,25 @@ msgstr "Плавная прокрутка при переходе между з
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr "Прокрутка"
|
msgstr "Прокрутка"
|
||||||
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Поиск"
|
msgstr "Поиск"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
msgid "Search requires at least 3 characters"
|
|
||||||
msgstr "Для поиска требуется не менее 3 символов"
|
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Select next unread feed/category"
|
msgid "Select next unread feed/category"
|
||||||
msgstr ""
|
msgstr "Выбрать следующий непрочитанный фид/категорию"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Select previous unread feed/category"
|
msgid "Select previous unread feed/category"
|
||||||
msgstr ""
|
msgstr "Выбрать предыдущий непрочитанный фид/категорию"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Server URL"
|
||||||
|
msgstr "URL сервера"
|
||||||
|
|
||||||
#: 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"
|
||||||
@@ -892,7 +977,7 @@ msgstr "Показать меню входа (телефон)"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Show external link icon"
|
msgid "Show external link icon"
|
||||||
msgstr ""
|
msgstr "Показывать значок внешней ссылки"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Show feeds and categories with no unread entries"
|
msgid "Show feeds and categories with no unread entries"
|
||||||
@@ -908,19 +993,19 @@ msgstr "Показать родное меню (ПК)"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Show star icon"
|
msgid "Show star icon"
|
||||||
msgstr ""
|
msgstr "Показывать значок звезды"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Show unread count in tab favicon"
|
msgid "Show unread count in tab favicon"
|
||||||
msgstr ""
|
msgstr "Показывать количество непрочитанных во вкладке favicon"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
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 "Зарегистрироваться"
|
||||||
|
|
||||||
@@ -933,21 +1018,21 @@ msgstr "Только что случилось что-то плохое..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Пробел"
|
msgstr "Пробел"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "В избранное"
|
msgstr "В избранное"
|
||||||
|
|
||||||
#: src/pages/app/FeedEntriesPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedEntriesPage.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 "Подписаться"
|
||||||
|
|
||||||
@@ -986,7 +1071,15 @@ msgstr "Теги"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Teal"
|
msgid "Teal"
|
||||||
msgstr ""
|
msgstr "Бирюзовый"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Test"
|
||||||
|
msgstr "Тест"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Test notification sent successfully."
|
||||||
|
msgstr "Тестовое уведомление успешно отправлено."
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed will try to find the feed in the page."
|
msgid "The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed will try to find the feed in the page."
|
||||||
@@ -996,10 +1089,19 @@ msgstr "URL канала, на который вы хотите подписат
|
|||||||
msgid "Theme"
|
msgid "Theme"
|
||||||
msgstr "Тема"
|
msgstr "Тема"
|
||||||
|
|
||||||
|
#. placeholder {0}: feed.filterLegacy
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "This feed has a legacy filter that cannot be edited and is not applied. Please recreate the filter using the new expression editor. The legacy filter expression was: <0>{0}</0>"
|
||||||
|
msgstr "Этот фид имеет устаревший фильтр, который нельзя редактировать и который не применяется. Пожалуйста, создайте фильтр заново, используя новый редактор выражений. Устаревшее выражение фильтра было: <0>{0}</0>"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||||
msgstr "Это ваш ключ API. Он может использоваться для некоторых операций API только для чтения и предоставляет доступ к API Fever. Чтобы сгенерировать новый ключ API, воспользуйтесь формой в нижней части страницы"
|
msgstr "Это ваш ключ API. Он может использоваться для некоторых операций API только для чтения и предоставляет доступ к API Fever. Чтобы сгенерировать новый ключ API, воспользуйтесь формой в нижней части страницы"
|
||||||
|
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||||
|
msgstr "Этот параметр может вызвать проблемы с прокруткой в некоторых браузерах (например, Safari)"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "Переключить статус чтения текущей записи"
|
msgstr "Переключить статус чтения текущей записи"
|
||||||
@@ -1012,6 +1114,10 @@ msgstr "Переключить боковую панель"
|
|||||||
msgid "Toggle starred status of current entry"
|
msgid "Toggle starred status of current entry"
|
||||||
msgstr "Переключение статуса избранное для текущей записи"
|
msgstr "Переключение статуса избранное для текущей записи"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Topic"
|
||||||
|
msgstr "Тема"
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "Попробуйте CommaFeed на демо аккаунте: demo/demo"
|
msgstr "Попробуйте CommaFeed на демо аккаунте: demo/demo"
|
||||||
@@ -1024,8 +1130,8 @@ msgstr "Попробуйте демо-версию!"
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Не прочитано"
|
msgstr "Не прочитано"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "Удалить из избранного"
|
msgstr "Удалить из избранного"
|
||||||
@@ -1035,6 +1141,10 @@ msgstr "Удалить из избранного"
|
|||||||
msgid "Unsubscribe"
|
msgid "Unsubscribe"
|
||||||
msgstr "Отписаться"
|
msgstr "Отписаться"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "User key"
|
||||||
|
msgstr "Ключ пользователя"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "User name"
|
msgid "User name"
|
||||||
msgstr "Имя пользователя"
|
msgstr "Имя пользователя"
|
||||||
@@ -1046,7 +1156,7 @@ msgstr "Имя пользователя или адрес электронной
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Violet"
|
msgid "Violet"
|
||||||
msgstr ""
|
msgstr "Фиолетовый"
|
||||||
|
|
||||||
#: src/components/Alert.tsx
|
#: src/components/Alert.tsx
|
||||||
msgid "Warning"
|
msgid "Warning"
|
||||||
@@ -1056,9 +1166,13 @@ msgstr "Предупреждение"
|
|||||||
msgid "Website"
|
msgid "Website"
|
||||||
msgstr "Веб-сайт"
|
msgstr "Веб-сайт"
|
||||||
|
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||||
|
msgstr "Добро пожаловать! Похоже, вы запускаете CommaFeed в первый раз. Пожалуйста, создайте учетную запись администратора, чтобы начать работу."
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Yellow"
|
msgid "Yellow"
|
||||||
msgstr ""
|
msgstr "Желтый"
|
||||||
|
|
||||||
#: src/pages/app/FeedEntriesPage.tsx
|
#: src/pages/app/FeedEntriesPage.tsx
|
||||||
msgid "You don't have any subscriptions yet. Why not try adding one by clicking on the + sign at the top of the page?"
|
msgid "You don't have any subscriptions yet. Why not try adding one by clicking on the + sign at the top of the page?"
|
||||||
@@ -1067,3 +1181,7 @@ msgstr "У вас еще нет подписок. Почему бы не поп
|
|||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Your feeds have been queued for refresh."
|
msgid "Your feeds have been queued for refresh."
|
||||||
msgstr "Ваши каналы были поставлены в очередь на обновление."
|
msgstr "Ваши каналы были поставлены в очередь на обновление."
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Your password has been changed. You can now log in with your new password."
|
||||||
|
msgstr "Ваш пароль был изменен. Теперь вы можете войти с новым паролем."
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -17,10 +17,6 @@ msgstr ""
|
|||||||
msgid "<0>CommaFeed is an open-source project. Sources are hosted on </0><1>GitHub</1>."
|
msgid "<0>CommaFeed is an open-source project. Sources are hosted on </0><1>GitHub</1>."
|
||||||
msgstr "<0>CommaFeed açık kaynak kodlu bir proje. Kaynak kodları </0><1>GitHub</1>'da."
|
msgstr "<0>CommaFeed açık kaynak kodlu bir proje. Kaynak kodları </0><1>GitHub</1>'da."
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "<0>Complete syntax is available </0><1>here</1><2>.</2>"
|
|
||||||
msgstr "<0>Tüm sözdizimi </0><1>burada</1><2>.</2>"
|
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "<0>Have an account?</0><1>Log in!</1>"
|
msgid "<0>Have an account?</0><1>Log in!</1>"
|
||||||
msgstr "<0>Hesabınız var mı?</0><1>Giriş yapın!</1>"
|
msgstr "<0>Hesabınız var mı?</0><1>Giriş yapın!</1>"
|
||||||
@@ -33,11 +29,15 @@ 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/pages/app/AboutPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Hakkında"
|
msgstr "Hakkında"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Access token"
|
||||||
|
msgstr "Erişim jetonu"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Actions"
|
msgid "Actions"
|
||||||
msgstr "Eylemler"
|
msgstr "Eylemler"
|
||||||
@@ -54,24 +54,29 @@ msgstr "Kategori ekle"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "Kullanıcı ekle"
|
msgstr "Kullanıcı ekle"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "Yönetici"
|
msgstr "Yönetici"
|
||||||
|
|
||||||
#: src/pages/app/FeedEntriesPage.tsx
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
msgid "Admin user name"
|
||||||
#: src/components/header/Header.tsx
|
msgstr "Yönetici kullanıcı adı"
|
||||||
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedEntriesPage.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Tümü"
|
msgstr "Tümü"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Always"
|
msgid "Always"
|
||||||
msgstr ""
|
msgstr "Her zaman"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "An email has been sent if this address was registered. Check your inbox."
|
msgid "An email has been sent if this address was registered. Check your inbox."
|
||||||
@@ -93,6 +98,14 @@ msgstr "Duyuru"
|
|||||||
msgid "API key"
|
msgid "API key"
|
||||||
msgstr "API anahtarı"
|
msgstr "API anahtarı"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "API token"
|
||||||
|
msgstr "API jetonu"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "App token"
|
||||||
|
msgstr "Uygulama jetonu"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Are you sure you want to delete category <0>{categoryName}</0>?"
|
msgid "Are you sure you want to delete category <0>{categoryName}</0>?"
|
||||||
msgstr "<0>{categoryName}</0> kategorisini silmek istediğinizden emin misiniz?"
|
msgstr "<0>{categoryName}</0> kategorisini silmek istediğinizden emin misiniz?"
|
||||||
@@ -122,54 +135,60 @@ msgid "Asc"
|
|||||||
msgstr "Artan"
|
msgstr "Artan"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Available variables are 'title', 'content', 'url' 'author' and 'categories' and their content is converted to lower case to ease string comparison."
|
msgid "Auto-mark as read"
|
||||||
msgstr "Mevcut değişkenler 'title', 'content', 'url' 'yazar' ve 'kategoriler'dir ve dize karşılaştırmasını kolaylaştırmak için içerikleri küçük harfe dönüştürülür."
|
msgstr "Otomatik olarak okundu olarak işaretle"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Back"
|
msgid "Back"
|
||||||
msgstr "Geri"
|
msgstr "Geri"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "Giriş yapmak için geri dön"
|
msgstr "Giriş yapmak için geri dön"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Blue"
|
msgid "Blue"
|
||||||
msgstr ""
|
msgstr "Mavi"
|
||||||
|
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
|
msgid "Browser extension"
|
||||||
|
msgstr "Tarayıcı eklentisi"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Browser extension required for Chrome"
|
msgid "Browser extension required for Chrome"
|
||||||
msgstr ""
|
msgstr "Chrome için tarayıcı eklentisi gereklidir"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
msgid "Browser extention"
|
|
||||||
msgstr "Tarayıcı eklentisi"
|
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr ""
|
msgstr "Tarayıcı sekmesi"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
msgid "Build a filter expression to indicate what you want to read. Entries that don't match will be marked as read automatically."
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
msgstr "Ne okumak istediğinizi belirtmek için bir filtre ifadesi oluşturun. Eşleşmeyen girişler otomatik olarak okundu olarak işaretlenecektir."
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.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
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "İptal"
|
msgstr "İptal"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "Kategori"
|
msgstr "Kategori"
|
||||||
|
|
||||||
@@ -183,11 +202,11 @@ msgstr "Feed'in çalışıp çalışmadığını kontrol edin"
|
|||||||
|
|
||||||
#: src/pages/app/Layout.tsx
|
#: src/pages/app/Layout.tsx
|
||||||
msgid "Close menu"
|
msgid "Close menu"
|
||||||
msgstr ""
|
msgstr "Menüyü kapat"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Cmd"
|
msgid "Cmd"
|
||||||
msgstr ""
|
msgstr "Cmd"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
msgid "CommaFeed browser extension version {browserExtensionVersion}."
|
||||||
@@ -195,7 +214,7 @@ msgstr "CommaFeed tarayıcı eklentisi sürüm {browserExtensionVersion}."
|
|||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
|
msgid "CommaFeed is compatible with the Fever API. Use the following URL in your Fever-compatible mobile client. Login with your username and your <0>API key</0>."
|
||||||
msgstr ""
|
msgstr "CommaFeed, Fever API ile uyumludur. Fever uyumlu mobil istemcinizde aşağıdaki URL'yi kullanın. Kullanıcı adınız ve <0>API anahtarınız</0> ile giriş yapın."
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "CommaFeed next unread item"
|
msgid "CommaFeed next unread item"
|
||||||
@@ -209,11 +228,11 @@ msgstr "CommaFeed sürüm {version} ({revision})."
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "Kompakt"
|
msgstr "Kompakt"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "Onayla"
|
msgstr "Onayla"
|
||||||
|
|
||||||
@@ -221,10 +240,19 @@ msgstr "Onayla"
|
|||||||
msgid "Confirm password"
|
msgid "Confirm password"
|
||||||
msgstr "Şifreyi onayla"
|
msgstr "Şifreyi onayla"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Confirm Password"
|
||||||
|
msgstr "Şifreyi Onayla"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Cozy"
|
msgid "Cozy"
|
||||||
msgstr "Rahat"
|
msgstr "Rahat"
|
||||||
|
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Create Admin Account"
|
||||||
|
msgstr "Yönetici Hesabı Oluştur"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Ctrl"
|
msgid "Ctrl"
|
||||||
msgstr "Ctrl"
|
msgstr "Ctrl"
|
||||||
@@ -247,17 +275,21 @@ msgstr "Sayfa yüklendiğinde çalıştırılacak özel JS kodu"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Cyan"
|
msgid "Cyan"
|
||||||
msgstr ""
|
msgstr "Macenta"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Dark"
|
msgid "Dark"
|
||||||
msgstr ""
|
msgstr "Koyu"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "Oluşturulma tarihi"
|
msgstr "Oluşturulma tarihi"
|
||||||
|
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "days"
|
||||||
|
msgstr "gün"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Sil"
|
msgstr "Sil"
|
||||||
@@ -281,18 +313,22 @@ msgstr "Açılış"
|
|||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr ""
|
msgstr "Detaylı"
|
||||||
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
msgid "Disable \"Pull to refresh\" browser behavior"
|
||||||
|
msgstr "Tarayıcının \"Yenilemek için çek\" davranışını devre dışı bırak"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "Ekran"
|
msgstr "Ekran"
|
||||||
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/app/DonatePage.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr ""
|
msgstr "Bağış Yap"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "Download"
|
msgid "Download"
|
||||||
@@ -302,11 +338,13 @@ 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/pages/auth/PasswordRecoveryPage.tsx
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "E-posta"
|
msgstr "E-posta"
|
||||||
|
|
||||||
@@ -319,8 +357,8 @@ msgstr "E-posta adresi"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "Kullanıcıyı düzenle"
|
msgstr "Kullanıcıyı düzenle"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "Etkin"
|
msgstr "Etkin"
|
||||||
|
|
||||||
@@ -334,20 +372,16 @@ msgstr "Profil ayarlarını değiştirmek için mevcut şifrenizi girin"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Entries to keep above the selected entry when scrolling"
|
msgid "Entries to keep above the selected entry when scrolling"
|
||||||
msgstr ""
|
msgstr "Kaydırma sırasında seçilen girişin üzerinde tutulacak giriş sayısı"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Entry headers"
|
msgid "Entry headers"
|
||||||
msgstr ""
|
msgstr "Giriş başlıkları"
|
||||||
|
|
||||||
#: src/components/Alert.tsx
|
#: src/components/Alert.tsx
|
||||||
msgid "Error"
|
msgid "Error"
|
||||||
msgstr "Hata"
|
msgstr "Hata"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "Example: {example}."
|
|
||||||
msgstr "Örnek: {örnek}."
|
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Expanded"
|
msgid "Expanded"
|
||||||
msgstr "Genişletilmiş"
|
msgstr "Genişletilmiş"
|
||||||
@@ -356,8 +390,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/pages/WelcomePage.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/pages/WelcomePage.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr "Eklenti ayarları"
|
msgstr "Eklenti ayarları"
|
||||||
|
|
||||||
@@ -365,9 +399,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"
|
||||||
|
|
||||||
@@ -377,11 +411,11 @@ msgstr "Tüm feed'lerimi şimdi çek"
|
|||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "Fever API"
|
msgid "Fever API"
|
||||||
msgstr ""
|
msgstr "Fever API"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "Fever API URL"
|
msgid "Fever API URL"
|
||||||
msgstr ""
|
msgstr "Fever API URL'si"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Filtering expression"
|
msgid "Filtering expression"
|
||||||
@@ -389,19 +423,19 @@ msgstr "Filtreleme ifadesi"
|
|||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Font size"
|
msgid "Font size"
|
||||||
msgstr ""
|
msgstr "Yazı boyutu"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Force fetching feeds is not yet available."
|
msgid "Force fetching feeds is not yet available."
|
||||||
msgstr ""
|
msgstr "Beslemeleri zorla çekme özelliği henüz mevcut değil."
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "Parolanızı mı unuttunuz?"
|
msgstr "Parolanızı mı unuttunuz?"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.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."
|
||||||
|
|
||||||
@@ -409,9 +443,9 @@ 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/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "Oluşturulan besleme url'si"
|
msgstr "Oluşturulan besleme url'si"
|
||||||
|
|
||||||
@@ -434,27 +468,23 @@ msgstr "İyilikler"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Grape"
|
msgid "Grape"
|
||||||
msgstr ""
|
msgstr "Üzüm"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Gray"
|
msgid "Gray"
|
||||||
msgstr ""
|
msgstr "Gri"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Green"
|
msgid "Green"
|
||||||
msgstr ""
|
msgstr "Yeşil"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Id"
|
msgid "Id"
|
||||||
msgstr "Kimlik"
|
msgstr "Kimlik"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
|
|
||||||
msgstr "Boş değilse, 'doğru' veya 'yanlış' olarak değerlendirilen bir ifade. "
|
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "If the entry doesn't entirely fit on the screen"
|
msgid "If the entry doesn't entirely fit on the screen"
|
||||||
msgstr ""
|
msgstr "Eğer giriş ekrana tamamen sığmıyorsa"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
|
msgid "If you encounter an issue, please report it on the issues page of the GitHub project."
|
||||||
@@ -470,15 +500,23 @@ msgstr "Genişletilmiş görünümde, girişler arasında gezinmek onları okund
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Indigo"
|
msgid "Indigo"
|
||||||
msgstr ""
|
msgstr "İndigo"
|
||||||
|
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Initial Setup"
|
||||||
|
msgstr "Başlangıç Kurulumu"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Invalid password reset link. Please request a new one."
|
||||||
|
msgstr "Geçersiz şifre sıfırlama bağlantısı. Lütfen yeni bir tane isteyin."
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "Okunmadan sakla"
|
msgstr "Okunmadan sakla"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
#: src/components/content/FeedEntries.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "Klavye kısayolları"
|
msgstr "Klavye kısayolları"
|
||||||
|
|
||||||
@@ -500,21 +538,21 @@ msgstr "Son yenileme mesajı"
|
|||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Light"
|
msgid "Light"
|
||||||
msgstr ""
|
msgstr "Açık"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Lime"
|
msgid "Lime"
|
||||||
msgstr ""
|
msgstr "Limon"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "Bağlantı"
|
msgstr "Bağlantı"
|
||||||
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
msgid "Link to the documentation"
|
msgid "Link to the documentation"
|
||||||
msgstr ""
|
msgstr "Belgelere bağlantı"
|
||||||
|
|
||||||
#: src/hooks/useAppLoading.ts
|
#: src/hooks/useAppLoading.ts
|
||||||
msgid "Loading profile..."
|
msgid "Loading profile..."
|
||||||
@@ -532,9 +570,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ş"
|
||||||
|
|
||||||
@@ -546,8 +584,8 @@ msgstr "Çıkış"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr "Uzun bas"
|
msgstr "Uzun bas"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "Kullanıcıları yönet"
|
msgstr "Kullanıcıları yönet"
|
||||||
|
|
||||||
@@ -555,21 +593,25 @@ 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/MarkAllAsReadConfirmationDialog.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/MarkAllAsReadConfirmationDialog.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/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "Okundu olarak işaretle"
|
msgstr "Okundu olarak işaretle"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.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"
|
||||||
|
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "Mark entries in this feed as read after this number of days. Leave empty to disable."
|
||||||
|
msgstr "Bu beslemedeki girişleri şu kadar gün sonra okundu olarak işaretle. Devre dışı bırakmak için boş bırakın."
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Metrics"
|
msgid "Metrics"
|
||||||
msgstr "Metrikler"
|
msgstr "Metrikler"
|
||||||
@@ -586,15 +628,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/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/components/RelativeDate.tsx
|
#: src/components/RelativeDate.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr "Yok"
|
msgstr "Yok"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "İsim"
|
msgstr "İsim"
|
||||||
|
|
||||||
@@ -604,23 +646,28 @@ msgstr "Adını girerek bir aboneliğe gidin"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
|
msgid "Navigate to the next category/feed with unread entries when marking all entries as read"
|
||||||
msgstr ""
|
msgstr "Tüm girişleri okundu olarak işaretlerken okunmamış girişleri olan bir sonraki kategoriye/beslemeye git"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Never"
|
msgid "Never"
|
||||||
msgstr ""
|
msgstr "Asla"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "New password"
|
msgid "New password"
|
||||||
msgstr "Yeni şifre"
|
msgstr "Yeni şifre"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "New Password"
|
||||||
|
msgstr "Yeni Şifre"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "Önce en yenisi"
|
msgstr "Önce en yenisi"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "Sonraki"
|
msgstr "Sonraki"
|
||||||
|
|
||||||
@@ -638,7 +685,7 @@ msgstr "Başka giriş yok"
|
|||||||
|
|
||||||
#: src/components/content/ShareButtons.tsx
|
#: src/components/content/ShareButtons.tsx
|
||||||
msgid "No sharing options available."
|
msgid "No sharing options available."
|
||||||
msgstr ""
|
msgstr "Paylaşım seçeneği mevcut değil."
|
||||||
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
msgid "Nothing found"
|
msgid "Nothing found"
|
||||||
@@ -650,19 +697,19 @@ msgstr "Önce en eski"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "On desktop"
|
msgid "On desktop"
|
||||||
msgstr ""
|
msgstr "Masaüstünde"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "On mobile"
|
msgid "On mobile"
|
||||||
msgstr ""
|
msgstr "Mobilde"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "On mobile, show action buttons at the bottom of the screen"
|
msgid "On mobile, show action buttons at the bottom of the screen"
|
||||||
msgstr ""
|
msgstr "Mobilde, eylem düğmelerini ekranın altında göster"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Only applies to compact, cozy and detailed modes"
|
msgid "Only applies to compact, cozy and detailed modes"
|
||||||
msgstr ""
|
msgstr "Yalnızca kompakt, rahat ve detaylı modlar için geçerlidir"
|
||||||
|
|
||||||
#: src/pages/ErrorPage.tsx
|
#: src/pages/ErrorPage.tsx
|
||||||
msgid "Oops!"
|
msgid "Oops!"
|
||||||
@@ -695,7 +742,7 @@ msgstr "Bağlantıyı yeni sekmede aç"
|
|||||||
|
|
||||||
#: src/pages/app/Layout.tsx
|
#: src/pages/app/Layout.tsx
|
||||||
msgid "Open menu"
|
msgid "Open menu"
|
||||||
msgstr ""
|
msgstr "Menüyü aç"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Open next entry"
|
msgid "Open next entry"
|
||||||
@@ -724,11 +771,11 @@ msgstr "OPML dosyası"
|
|||||||
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
msgid "OPML file is required"
|
msgid "OPML file is required"
|
||||||
msgstr ""
|
msgstr "OPML dosyası gereklidir"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Orange"
|
msgid "Orange"
|
||||||
msgstr ""
|
msgstr "Turuncu"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Order"
|
msgid "Order"
|
||||||
@@ -742,28 +789,34 @@ 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/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.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"
|
||||||
|
|
||||||
|
#: src/hooks/useValidationRules.ts
|
||||||
|
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||||
|
msgstr "Şifre en az {minimumPasswordLength} karakter olmalıdır"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "Password Recovery"
|
msgid "Password Recovery"
|
||||||
msgstr "Parola Kurtarma"
|
msgstr "Parola Kurtarma"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/hooks/useValidationRules.ts
|
||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "Parolalar eşleşmiyor"
|
msgstr "Parolalar eşleşmiyor"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Pink"
|
msgid "Pink"
|
||||||
msgstr ""
|
msgstr "Pembe"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "Konum"
|
msgstr "Konum"
|
||||||
|
|
||||||
@@ -773,22 +826,47 @@ msgstr "Önceki"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Primary color"
|
msgid "Primary color"
|
||||||
msgstr ""
|
msgstr "Birincil renk"
|
||||||
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
#: src/pages/app/SettingsPage.tsx
|
||||||
msgid "Profile"
|
msgid "Profile"
|
||||||
msgstr "Profil"
|
msgstr "Profil"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Push notification service"
|
||||||
|
msgstr "Push bildirim servisi"
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Push notifications"
|
||||||
|
msgstr "Push bildirimleri"
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
msgid "Push notifications are not configured in your user settings."
|
||||||
|
msgstr "Push bildirimleri kullanıcı ayarlarınızda yapılandırılmamış."
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Push notifications are not enabled on this CommaFeed instance."
|
||||||
|
msgstr "Bu CommaFeed örneğinde push bildirimleri etkin değil."
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
msgid "Receive push notifications"
|
||||||
|
msgstr "Push bildirimlerini al"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Receive push notifications when new feed entries are discovered. Enable \"Receive push notifications\" in the settings of each feed for which you want to receive notifications."
|
||||||
|
msgstr "Yeni besleme girişleri keşfedildiğinde push bildirimleri alın. Bildirim almak istediğiniz her beslemenin ayarlarında \"Push bildirimlerini al\" seçeneğini etkinleştirin."
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "Şifreyi kurtar"
|
msgstr "Şifreyi kurtar"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Red"
|
msgid "Red"
|
||||||
msgstr ""
|
msgstr "Kırmızı"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Yenile"
|
msgstr "Yenile"
|
||||||
|
|
||||||
@@ -796,6 +874,11 @@ msgstr "Yenile"
|
|||||||
msgid "Registrations are closed on this CommaFeed instance"
|
msgid "Registrations are closed on this CommaFeed instance"
|
||||||
msgstr "Bu CommaFeed örneğinde kayıtlar kapalı"
|
msgstr "Bu CommaFeed örneğinde kayıtlar kapalı"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Reset Password"
|
||||||
|
msgstr "Şifreyi Sıfırla"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "REST API"
|
msgid "REST API"
|
||||||
msgstr "REST API"
|
msgstr "REST API"
|
||||||
@@ -805,17 +888,18 @@ msgstr "REST API"
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr "Sağ tık"
|
msgstr "Sağ tık"
|
||||||
|
|
||||||
#: 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
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Kaydet"
|
msgstr "Kaydet"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Scroll selected entry to the top of the page"
|
msgid "Scroll selected entry to the top of the page"
|
||||||
msgstr ""
|
msgstr "Seçilen girişi sayfanın üstüne kaydır"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Scroll smoothly when navigating between entries"
|
msgid "Scroll smoothly when navigating between entries"
|
||||||
@@ -823,26 +907,27 @@ msgstr "Girişler arasında gezinirken sorunsuz ilerleyin"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr ""
|
msgstr "Kaydırma"
|
||||||
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Ara"
|
msgstr "Ara"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
msgid "Search requires at least 3 characters"
|
|
||||||
msgstr "Arama için en az 3 karakter gerekiyor"
|
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Select next unread feed/category"
|
msgid "Select next unread feed/category"
|
||||||
msgstr ""
|
msgstr "Sonraki okunmamış beslemeyi/kategoriyi seç"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Select previous unread feed/category"
|
msgid "Select previous unread feed/category"
|
||||||
msgstr ""
|
msgstr "Önceki okunmamış beslemeyi/kategoriyi seç"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Server URL"
|
||||||
|
msgstr "Sunucu URL'si"
|
||||||
|
|
||||||
#: 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"
|
||||||
@@ -892,7 +977,7 @@ msgstr "Giriş menüsünü göster (mobil)"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Show external link icon"
|
msgid "Show external link icon"
|
||||||
msgstr ""
|
msgstr "Harici bağlantı simgesini göster"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Show feeds and categories with no unread entries"
|
msgid "Show feeds and categories with no unread entries"
|
||||||
@@ -908,19 +993,19 @@ msgstr "Orijinal tarayıcı menüsünü göster (masaüstü)"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Show star icon"
|
msgid "Show star icon"
|
||||||
msgstr ""
|
msgstr "Yıldız simgesini göster"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Show unread count in tab favicon"
|
msgid "Show unread count in tab favicon"
|
||||||
msgstr ""
|
msgstr "Sekme simgesinde okunmamış sayısını göster"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Show unread count in tab title"
|
msgid "Show unread count in tab title"
|
||||||
msgstr ""
|
msgstr "Sekme başlığında okunmamış sayısını göster"
|
||||||
|
|
||||||
|
#: 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"
|
||||||
|
|
||||||
@@ -933,21 +1018,21 @@ msgstr "Az önce kötü bir şey oldu..."
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "Uzay"
|
msgstr "Uzay"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.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/pages/app/FeedEntriesPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedEntriesPage.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"
|
||||||
|
|
||||||
@@ -965,7 +1050,7 @@ msgstr "Başarı"
|
|||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Swipe header to the left"
|
msgid "Swipe header to the left"
|
||||||
msgstr ""
|
msgstr "Başlığı sola kaydır"
|
||||||
|
|
||||||
#: src/pages/WelcomePage.tsx
|
#: src/pages/WelcomePage.tsx
|
||||||
msgid "Switch to dark theme"
|
msgid "Switch to dark theme"
|
||||||
@@ -977,7 +1062,7 @@ msgstr "Aydınlık temaya geç"
|
|||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "System"
|
msgid "System"
|
||||||
msgstr ""
|
msgstr "Sistem"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
@@ -986,7 +1071,15 @@ msgstr "Etiketler"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Teal"
|
msgid "Teal"
|
||||||
msgstr ""
|
msgstr "Camgöbeği"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Test"
|
||||||
|
msgstr "Test"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Test notification sent successfully."
|
||||||
|
msgstr "Test bildirimi başarıyla gönderildi."
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed will try to find the feed in the page."
|
msgid "The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed will try to find the feed in the page."
|
||||||
@@ -996,9 +1089,18 @@ msgstr "Abone olmak istediğiniz beslemenin URL'si. "
|
|||||||
msgid "Theme"
|
msgid "Theme"
|
||||||
msgstr "Tema"
|
msgstr "Tema"
|
||||||
|
|
||||||
|
#. placeholder {0}: feed.filterLegacy
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "This feed has a legacy filter that cannot be edited and is not applied. Please recreate the filter using the new expression editor. The legacy filter expression was: <0>{0}</0>"
|
||||||
|
msgstr "Bu beslemenin düzenlenemeyen ve uygulanmayan eski bir filtresi var. Lütfen yeni ifade düzenleyiciyi kullanarak filtreyi yeniden oluşturun. Eski filtre ifadesi şuydu: <0>{0}</0>"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||||
msgstr ""
|
msgstr "Bu sizin API anahtarınızdır. Bazı salt okunur API işlemleri için kullanılabilir ve Fever API'sine erişim sağlar. Yeni bir API anahtarı oluşturmak için sayfanın altındaki formu kullanın"
|
||||||
|
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||||
|
msgstr "Bu ayar bazı tarayıcılarda (örneğin Safari) kaydırma sorunlarına neden olabilir"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
@@ -1010,7 +1112,11 @@ msgstr "Kenar çubuğunu göster/gizle"
|
|||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Toggle starred status of current entry"
|
msgid "Toggle starred status of current entry"
|
||||||
msgstr ""
|
msgstr "Geçerli girişin yıldızlı durumunu değiştir"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Topic"
|
||||||
|
msgstr "Konu"
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
@@ -1024,8 +1130,8 @@ msgstr "Demo'yu deneyin!"
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "Okunmamış"
|
msgstr "Okunmamış"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.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"
|
||||||
@@ -1035,6 +1141,10 @@ msgstr "Yıldızı kaldır"
|
|||||||
msgid "Unsubscribe"
|
msgid "Unsubscribe"
|
||||||
msgstr "Aboneliği iptal et"
|
msgstr "Aboneliği iptal et"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "User key"
|
||||||
|
msgstr "Kullanıcı anahtarı"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "User name"
|
msgid "User name"
|
||||||
msgstr "Kullanıcı adı"
|
msgstr "Kullanıcı adı"
|
||||||
@@ -1046,7 +1156,7 @@ msgstr "Kullanıcı Adı veya E-posta"
|
|||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Violet"
|
msgid "Violet"
|
||||||
msgstr ""
|
msgstr "Menekşe"
|
||||||
|
|
||||||
#: src/components/Alert.tsx
|
#: src/components/Alert.tsx
|
||||||
msgid "Warning"
|
msgid "Warning"
|
||||||
@@ -1056,9 +1166,13 @@ msgstr "Uyarı"
|
|||||||
msgid "Website"
|
msgid "Website"
|
||||||
msgstr "Web sitesi"
|
msgstr "Web sitesi"
|
||||||
|
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||||
|
msgstr "Hoş geldiniz! Görünüşe göre CommaFeed'i ilk kez çalıştırıyorsunuz. Başlamak için lütfen bir yönetici hesabı oluşturun."
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Yellow"
|
msgid "Yellow"
|
||||||
msgstr ""
|
msgstr "Sarı"
|
||||||
|
|
||||||
#: src/pages/app/FeedEntriesPage.tsx
|
#: src/pages/app/FeedEntriesPage.tsx
|
||||||
msgid "You don't have any subscriptions yet. Why not try adding one by clicking on the + sign at the top of the page?"
|
msgid "You don't have any subscriptions yet. Why not try adding one by clicking on the + sign at the top of the page?"
|
||||||
@@ -1067,3 +1181,7 @@ msgstr "Henüz aboneliğiniz yok. Sayfanın üstündeki + işaretiyle feed ekley
|
|||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Your feeds have been queued for refresh."
|
msgid "Your feeds have been queued for refresh."
|
||||||
msgstr "Feed'leriniz yenileme için sıraya alındı."
|
msgstr "Feed'leriniz yenileme için sıraya alındı."
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Your password has been changed. You can now log in with your new password."
|
||||||
|
msgstr "Şifreniz değiştirildi. Artık yeni şifrenizle giriş yapabilirsiniz."
|
||||||
|
|||||||
@@ -17,10 +17,6 @@ msgstr ""
|
|||||||
msgid "<0>CommaFeed is an open-source project. Sources are hosted on </0><1>GitHub</1>."
|
msgid "<0>CommaFeed is an open-source project. Sources are hosted on </0><1>GitHub</1>."
|
||||||
msgstr "<0>CommaFeed是一个开源项目,源码托管在 </0><1>GitHub</1>。"
|
msgstr "<0>CommaFeed是一个开源项目,源码托管在 </0><1>GitHub</1>。"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "<0>Complete syntax is available </0><1>here</1><2>.</2>"
|
|
||||||
msgstr "<0>可以使用完整的语法 </0><1>详情</1><2>.</2>"
|
|
||||||
|
|
||||||
#: src/pages/auth/RegistrationPage.tsx
|
#: src/pages/auth/RegistrationPage.tsx
|
||||||
msgid "<0>Have an account?</0><1>Log in!</1>"
|
msgid "<0>Have an account?</0><1>Log in!</1>"
|
||||||
msgstr "<0>有帐号吗?</0><1>登录!</1>"
|
msgstr "<0>有帐号吗?</0><1>登录!</1>"
|
||||||
@@ -33,11 +29,15 @@ 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/pages/app/AboutPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "关于"
|
msgstr "关于"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Access token"
|
||||||
|
msgstr "访问令牌"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Actions"
|
msgid "Actions"
|
||||||
msgstr "操作"
|
msgstr "操作"
|
||||||
@@ -54,17 +54,22 @@ msgstr "添加类别"
|
|||||||
msgid "Add user"
|
msgid "Add user"
|
||||||
msgstr "添加用户"
|
msgstr "添加用户"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Admin"
|
msgid "Admin"
|
||||||
msgstr "管理员"
|
msgstr "管理员"
|
||||||
|
|
||||||
#: src/pages/app/FeedEntriesPage.tsx
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
#: src/components/sidebar/Tree.tsx
|
msgid "Admin user name"
|
||||||
#: src/components/header/Header.tsx
|
msgstr "管理员用户名"
|
||||||
|
|
||||||
#: src/components/content/add/CategorySelect.tsx
|
#: src/components/content/add/CategorySelect.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedEntriesPage.tsx
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "全部"
|
msgstr "全部"
|
||||||
|
|
||||||
@@ -93,6 +98,14 @@ msgstr "公告"
|
|||||||
msgid "API key"
|
msgid "API key"
|
||||||
msgstr "API 密钥"
|
msgstr "API 密钥"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "API token"
|
||||||
|
msgstr "API 令牌"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "App token"
|
||||||
|
msgstr "应用令牌"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Are you sure you want to delete category <0>{categoryName}</0>?"
|
msgid "Are you sure you want to delete category <0>{categoryName}</0>?"
|
||||||
msgstr "您确定要删除类别 <0>{categoryName}</0> 吗?"
|
msgstr "您确定要删除类别 <0>{categoryName}</0> 吗?"
|
||||||
@@ -122,14 +135,15 @@ msgid "Asc"
|
|||||||
msgstr "升序"
|
msgstr "升序"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Available variables are 'title', 'content', 'url' 'author' and 'categories' and their content is converted to lower case to ease string comparison."
|
msgid "Auto-mark as read"
|
||||||
msgstr "可用变量为'title'、'content'、'url'、'author'和'categories',它们的内容被转换为小写以方便字符串比较。"
|
msgstr "自动标记为已读"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "Back"
|
msgid "Back"
|
||||||
msgstr "返回"
|
msgstr "返回"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
msgid "Back to log in"
|
msgid "Back to log in"
|
||||||
msgstr "返回登录"
|
msgstr "返回登录"
|
||||||
|
|
||||||
@@ -137,39 +151,44 @@ msgstr "返回登录"
|
|||||||
msgid "Blue"
|
msgid "Blue"
|
||||||
msgstr "蓝"
|
msgstr "蓝"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Browser extension required for Chrome"
|
msgid "Browser extension"
|
||||||
msgstr "浏览器扩展"
|
msgstr "浏览器扩展"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Browser extention"
|
msgid "Browser extension required for Chrome"
|
||||||
msgstr "浏览器扩展"
|
msgstr "浏览器扩展"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Browser tab"
|
msgid "Browser tab"
|
||||||
msgstr "浏览器标签页"
|
msgstr "浏览器标签页"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
msgid "Build a filter expression to indicate what you want to read. Entries that don't match will be marked as read automatically."
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
msgstr "构建过滤表达式以指示您想阅读的内容。不匹配的条目将被自动标记为已读。"
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/settings/CustomCodeSettings.tsx
|
|
||||||
#: src/components/content/add/ImportOpml.tsx
|
|
||||||
#: src/components/content/add/AddCategory.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/content/add/AddCategory.tsx
|
||||||
|
#: src/components/content/add/ImportOpml.tsx
|
||||||
|
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.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
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "取消"
|
msgstr "取消"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/components/content/add/AddCategory.tsx
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
#: src/components/content/add/AddCategory.tsx
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Category"
|
msgid "Category"
|
||||||
msgstr "类别"
|
msgstr "类别"
|
||||||
|
|
||||||
@@ -209,11 +228,11 @@ msgstr "CommaFeed版本:{version} ({revision})"
|
|||||||
msgid "Compact"
|
msgid "Compact"
|
||||||
msgstr "紧凑"
|
msgstr "紧凑"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Confirm"
|
msgid "Confirm"
|
||||||
msgstr "确认"
|
msgstr "确认"
|
||||||
|
|
||||||
@@ -221,10 +240,19 @@ msgstr "确认"
|
|||||||
msgid "Confirm password"
|
msgid "Confirm password"
|
||||||
msgstr "确认密码"
|
msgstr "确认密码"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Confirm Password"
|
||||||
|
msgstr "确认密码"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Cozy"
|
msgid "Cozy"
|
||||||
msgstr "宽松"
|
msgstr "宽松"
|
||||||
|
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Create Admin Account"
|
||||||
|
msgstr "创建管理员帐号"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Ctrl"
|
msgid "Ctrl"
|
||||||
msgstr "Ctrl"
|
msgstr "Ctrl"
|
||||||
@@ -249,8 +277,8 @@ msgstr "将在页面加载时执行的自定义JS代码"
|
|||||||
msgid "Cyan"
|
msgid "Cyan"
|
||||||
msgstr "青"
|
msgstr "青"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Dark"
|
msgid "Dark"
|
||||||
msgstr "暗黑"
|
msgstr "暗黑"
|
||||||
|
|
||||||
@@ -258,6 +286,10 @@ msgstr "暗黑"
|
|||||||
msgid "Date created"
|
msgid "Date created"
|
||||||
msgstr "创建日期"
|
msgstr "创建日期"
|
||||||
|
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "days"
|
||||||
|
msgstr "天"
|
||||||
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "删除"
|
msgstr "删除"
|
||||||
@@ -283,14 +315,18 @@ msgstr "降序"
|
|||||||
msgid "Detailed"
|
msgid "Detailed"
|
||||||
msgstr "详细"
|
msgstr "详细"
|
||||||
|
|
||||||
#: src/pages/app/SettingsPage.tsx
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
msgid "Disable \"Pull to refresh\" browser behavior"
|
||||||
|
msgstr "禁用浏览器的“下拉刷新”功能"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
msgid "Display"
|
msgid "Display"
|
||||||
msgstr "显示"
|
msgstr "显示"
|
||||||
|
|
||||||
#: src/pages/app/DonatePage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/app/DonatePage.tsx
|
||||||
msgid "Donate"
|
msgid "Donate"
|
||||||
msgstr "捐赠"
|
msgstr "捐赠"
|
||||||
|
|
||||||
@@ -302,11 +338,13 @@ msgstr "下载"
|
|||||||
msgid "Drag link to bookmark bar"
|
msgid "Drag link to bookmark bar"
|
||||||
msgstr "拖动链接到书签栏"
|
msgstr "拖动链接到书签栏"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "E-mail"
|
msgid "E-mail"
|
||||||
msgstr "电子邮件"
|
msgstr "电子邮件"
|
||||||
|
|
||||||
@@ -319,8 +357,8 @@ msgstr "电子邮件地址"
|
|||||||
msgid "Edit user"
|
msgid "Edit user"
|
||||||
msgstr "编辑用户"
|
msgstr "编辑用户"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Enabled"
|
msgid "Enabled"
|
||||||
msgstr "已启用"
|
msgstr "已启用"
|
||||||
|
|
||||||
@@ -344,10 +382,6 @@ msgstr "条目头部"
|
|||||||
msgid "Error"
|
msgid "Error"
|
||||||
msgstr "错误"
|
msgstr "错误"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "Example: {example}."
|
|
||||||
msgstr "示例:{示例}。"
|
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Expanded"
|
msgid "Expanded"
|
||||||
msgstr "展开"
|
msgstr "展开"
|
||||||
@@ -356,8 +390,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/pages/WelcomePage.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/pages/WelcomePage.tsx
|
||||||
msgid "Extension options"
|
msgid "Extension options"
|
||||||
msgstr "扩展选项"
|
msgstr "扩展选项"
|
||||||
|
|
||||||
@@ -365,9 +399,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 "信息流网址"
|
||||||
|
|
||||||
@@ -399,9 +433,9 @@ msgstr "强制获取订阅源功能不可用。"
|
|||||||
msgid "Forgot password?"
|
msgid "Forgot password?"
|
||||||
msgstr "忘记密码?"
|
msgstr "忘记密码?"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
msgid "Generate an API key in your profile first."
|
msgid "Generate an API key in your profile first."
|
||||||
msgstr "首先在您的配置文件中生成一个 API 密钥。"
|
msgstr "首先在您的配置文件中生成一个 API 密钥。"
|
||||||
|
|
||||||
@@ -409,9 +443,9 @@ msgstr "首先在您的配置文件中生成一个 API 密钥。"
|
|||||||
msgid "Generate new API key"
|
msgid "Generate new API key"
|
||||||
msgstr "生成新的 API 密钥"
|
msgstr "生成新的 API 密钥"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
msgid "Generated feed url"
|
msgid "Generated feed url"
|
||||||
msgstr "生成信息流网址"
|
msgstr "生成信息流网址"
|
||||||
|
|
||||||
@@ -448,10 +482,6 @@ msgstr "绿"
|
|||||||
msgid "Id"
|
msgid "Id"
|
||||||
msgstr "序号"
|
msgstr "序号"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
msgid "If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read automatically."
|
|
||||||
msgstr "如果不为空,则表达式的计算结果为“真”或“假”。如果为“假”,则此信息流的新条目将自动标记为已读。"
|
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "If the entry doesn't entirely fit on the screen"
|
msgid "If the entry doesn't entirely fit on the screen"
|
||||||
msgstr "如果条目不能完全显示在屏幕上"
|
msgstr "如果条目不能完全显示在屏幕上"
|
||||||
@@ -472,13 +502,21 @@ msgstr "在展开视图中,滚动条目将它们标记为已读"
|
|||||||
msgid "Indigo"
|
msgid "Indigo"
|
||||||
msgstr "靛蓝"
|
msgstr "靛蓝"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Initial Setup"
|
||||||
|
msgstr "初始化设置"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Invalid password reset link. Please request a new one."
|
||||||
|
msgstr "密码重置链接无效,请重新申请。"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
msgid "Keep unread"
|
msgid "Keep unread"
|
||||||
msgstr "保持未读状态"
|
msgstr "保持未读状态"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
|
||||||
#: src/components/content/FeedEntries.tsx
|
#: src/components/content/FeedEntries.tsx
|
||||||
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Keyboard shortcuts"
|
msgid "Keyboard shortcuts"
|
||||||
msgstr "键盘快捷键"
|
msgstr "键盘快捷键"
|
||||||
|
|
||||||
@@ -506,9 +544,9 @@ msgstr "浅色"
|
|||||||
msgid "Lime"
|
msgid "Lime"
|
||||||
msgstr "浅黄"
|
msgstr "浅黄"
|
||||||
|
|
||||||
#: src/pages/app/TagDetailsPage.tsx
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
#: src/pages/app/TagDetailsPage.tsx
|
||||||
msgid "Link"
|
msgid "Link"
|
||||||
msgstr "链接"
|
msgstr "链接"
|
||||||
|
|
||||||
@@ -532,9 +570,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 "登录"
|
||||||
|
|
||||||
@@ -546,8 +584,8 @@ msgstr "注销"
|
|||||||
msgid "Long press"
|
msgid "Long press"
|
||||||
msgstr "长按"
|
msgstr "长按"
|
||||||
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
msgid "Manage users"
|
msgid "Manage users"
|
||||||
msgstr "管理用户"
|
msgstr "管理用户"
|
||||||
|
|
||||||
@@ -555,21 +593,25 @@ msgstr "管理用户"
|
|||||||
msgid "Mark all as read"
|
msgid "Mark all as read"
|
||||||
msgstr "全部标记为已读"
|
msgstr "全部标记为已读"
|
||||||
|
|
||||||
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
|
#: src/components/MarkAllAsReadConfirmationDialog.tsx
|
||||||
msgid "Mark all entries as read"
|
msgid "Mark all entries as read"
|
||||||
msgstr "将所有条目标记为已读"
|
msgstr "将所有条目标记为已读"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
msgid "Mark as read"
|
msgid "Mark as read"
|
||||||
msgstr "标记为已读"
|
msgstr "标记为已读"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
msgid "Mark as read up to here"
|
msgid "Mark as read up to here"
|
||||||
msgstr "标记为已读到这里"
|
msgstr "标记为已读到这里"
|
||||||
|
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "Mark entries in this feed as read after this number of days. Leave empty to disable."
|
||||||
|
msgstr "在此天数后将此信息流中的条目标记为已读。留空以禁用。"
|
||||||
|
|
||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Metrics"
|
msgid "Metrics"
|
||||||
msgstr "指标"
|
msgstr "指标"
|
||||||
@@ -586,15 +628,15 @@ msgstr "下移页面"
|
|||||||
msgid "Move the page up"
|
msgid "Move the page up"
|
||||||
msgstr "上移页面"
|
msgstr "上移页面"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/components/RelativeDate.tsx
|
#: src/components/RelativeDate.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "N/A"
|
msgid "N/A"
|
||||||
msgstr "不适用"
|
msgstr "不适用"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/pages/admin/AdminUsersPage.tsx
|
|
||||||
#: src/components/admin/UserEdit.tsx
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/pages/admin/AdminUsersPage.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "名称"
|
msgstr "名称"
|
||||||
|
|
||||||
@@ -615,12 +657,17 @@ msgstr "从不"
|
|||||||
msgid "New password"
|
msgid "New password"
|
||||||
msgstr "新密码"
|
msgstr "新密码"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "New Password"
|
||||||
|
msgstr "新密码"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "Newest first"
|
msgid "Newest first"
|
||||||
msgstr "最新的优先"
|
msgstr "最新的优先"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
|
#: src/components/header/Header.tsx
|
||||||
msgid "Next"
|
msgid "Next"
|
||||||
msgstr "下一个"
|
msgstr "下一个"
|
||||||
|
|
||||||
@@ -742,19 +789,25 @@ 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/InitialSetupPage.tsx
|
||||||
|
#: src/pages/auth/InitialSetupPage.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 "密码"
|
||||||
|
|
||||||
|
#: src/hooks/useValidationRules.ts
|
||||||
|
msgid "Password must be at least {minimumPasswordLength} characters"
|
||||||
|
msgstr "密码最少需要 {minimumPasswordLength} 个字符"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "Password Recovery"
|
msgid "Password Recovery"
|
||||||
msgstr "密码恢复"
|
msgstr "密码恢复"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/hooks/useValidationRules.ts
|
||||||
msgid "Passwords do not match"
|
msgid "Passwords do not match"
|
||||||
msgstr "密码不匹配"
|
msgstr "密码不匹配"
|
||||||
|
|
||||||
@@ -762,8 +815,8 @@ msgstr "密码不匹配"
|
|||||||
msgid "Pink"
|
msgid "Pink"
|
||||||
msgstr "粉红"
|
msgstr "粉红"
|
||||||
|
|
||||||
#: src/pages/app/FeedDetailsPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Position"
|
msgid "Position"
|
||||||
msgstr "位置"
|
msgstr "位置"
|
||||||
|
|
||||||
@@ -779,6 +832,31 @@ msgstr "主颜色"
|
|||||||
msgid "Profile"
|
msgid "Profile"
|
||||||
msgstr "配置文件"
|
msgstr "配置文件"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Push notification service"
|
||||||
|
msgstr "推送通知服务"
|
||||||
|
|
||||||
|
#: src/pages/app/SettingsPage.tsx
|
||||||
|
msgid "Push notifications"
|
||||||
|
msgstr "推送通知"
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
msgid "Push notifications are not configured in your user settings."
|
||||||
|
msgstr "您的用户设置中未配置推送通知。"
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Push notifications are not enabled on this CommaFeed instance."
|
||||||
|
msgstr "此 CommaFeed 实例未启用推送通知。"
|
||||||
|
|
||||||
|
#: src/components/ReceivePushNotificationsChechbox.tsx
|
||||||
|
msgid "Receive push notifications"
|
||||||
|
msgstr "接收推送通知"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Receive push notifications when new feed entries are discovered. Enable \"Receive push notifications\" in the settings of each feed for which you want to receive notifications."
|
||||||
|
msgstr "当发现新的信息流条目时接收推送通知。在您希望接收通知的每个信息流设置中启用“接收推送通知”。"
|
||||||
|
|
||||||
#: src/pages/auth/PasswordRecoveryPage.tsx
|
#: src/pages/auth/PasswordRecoveryPage.tsx
|
||||||
msgid "Recover password"
|
msgid "Recover password"
|
||||||
msgstr "找回密码"
|
msgstr "找回密码"
|
||||||
@@ -787,8 +865,8 @@ msgstr "找回密码"
|
|||||||
msgid "Red"
|
msgid "Red"
|
||||||
msgstr "红"
|
msgstr "红"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "刷新"
|
msgstr "刷新"
|
||||||
|
|
||||||
@@ -796,6 +874,11 @@ msgstr "刷新"
|
|||||||
msgid "Registrations are closed on this CommaFeed instance"
|
msgid "Registrations are closed on this CommaFeed instance"
|
||||||
msgstr "此 CommaFeed 实例上的注册已关闭"
|
msgstr "此 CommaFeed 实例上的注册已关闭"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Reset Password"
|
||||||
|
msgstr "重置密码"
|
||||||
|
|
||||||
#: src/pages/app/AboutPage.tsx
|
#: src/pages/app/AboutPage.tsx
|
||||||
msgid "REST API"
|
msgid "REST API"
|
||||||
msgstr "REST API"
|
msgstr "REST API"
|
||||||
@@ -805,11 +888,12 @@ msgstr "REST API"
|
|||||||
msgid "Right click"
|
msgid "Right click"
|
||||||
msgstr "右键单击"
|
msgstr "右键单击"
|
||||||
|
|
||||||
#: 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
|
#: src/components/admin/UserEdit.tsx
|
||||||
|
#: src/components/settings/CustomCodeSettings.tsx
|
||||||
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "保存"
|
msgstr "保存"
|
||||||
|
|
||||||
@@ -825,17 +909,13 @@ msgstr "在条目之间导航时平滑滚动"
|
|||||||
msgid "Scrolling"
|
msgid "Scrolling"
|
||||||
msgstr "滚动"
|
msgstr "滚动"
|
||||||
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
|
||||||
#: src/components/sidebar/TreeSearch.tsx
|
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
#: src/components/header/Header.tsx
|
#: src/components/header/Header.tsx
|
||||||
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
|
#: src/components/sidebar/TreeSearch.tsx
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "搜索"
|
msgstr "搜索"
|
||||||
|
|
||||||
#: src/components/header/Header.tsx
|
|
||||||
msgid "Search requires at least 3 characters"
|
|
||||||
msgstr "搜索至少需要 3 个字符"
|
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Select next unread feed/category"
|
msgid "Select next unread feed/category"
|
||||||
msgstr "选择下一个未读信息流/类别"
|
msgstr "选择下一个未读信息流/类别"
|
||||||
@@ -844,6 +924,11 @@ msgstr "选择下一个未读信息流/类别"
|
|||||||
msgid "Select previous unread feed/category"
|
msgid "Select previous unread feed/category"
|
||||||
msgstr "选择上一个未读信息流/类别"
|
msgstr "选择上一个未读信息流/类别"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Server URL"
|
||||||
|
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 "将焦点放在下一个条目而不打开它"
|
||||||
@@ -918,9 +1003,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 "注册"
|
||||||
|
|
||||||
@@ -933,21 +1018,21 @@ msgstr "刚刚发生了不好的事情……"
|
|||||||
msgid "Space"
|
msgid "Space"
|
||||||
msgstr "空格"
|
msgstr "空格"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Star"
|
msgid "Star"
|
||||||
msgstr "星标"
|
msgstr "星标"
|
||||||
|
|
||||||
#: src/pages/app/FeedEntriesPage.tsx
|
|
||||||
#: src/pages/app/CategoryDetailsPage.tsx
|
|
||||||
#: src/components/sidebar/Tree.tsx
|
#: src/components/sidebar/Tree.tsx
|
||||||
|
#: src/pages/app/CategoryDetailsPage.tsx
|
||||||
|
#: src/pages/app/FeedEntriesPage.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 "订阅"
|
||||||
|
|
||||||
@@ -988,6 +1073,14 @@ msgstr "标签"
|
|||||||
msgid "Teal"
|
msgid "Teal"
|
||||||
msgstr "青绿"
|
msgstr "青绿"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Test"
|
||||||
|
msgstr "测试"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Test notification sent successfully."
|
||||||
|
msgstr "测试通知发送成功。"
|
||||||
|
|
||||||
#: src/components/content/add/Subscribe.tsx
|
#: src/components/content/add/Subscribe.tsx
|
||||||
msgid "The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed will try to find the feed in the page."
|
msgid "The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed will try to find the feed in the page."
|
||||||
msgstr "您要订阅的信息流的网址。您也可以直接使用网站的网址,CommaFeed 会尝试在页面中找到信息流。"
|
msgstr "您要订阅的信息流的网址。您也可以直接使用网站的网址,CommaFeed 会尝试在页面中找到信息流。"
|
||||||
@@ -996,10 +1089,19 @@ msgstr "您要订阅的信息流的网址。您也可以直接使用网站的网
|
|||||||
msgid "Theme"
|
msgid "Theme"
|
||||||
msgstr "主题"
|
msgstr "主题"
|
||||||
|
|
||||||
|
#. placeholder {0}: feed.filterLegacy
|
||||||
|
#: src/pages/app/FeedDetailsPage.tsx
|
||||||
|
msgid "This feed has a legacy filter that cannot be edited and is not applied. Please recreate the filter using the new expression editor. The legacy filter expression was: <0>{0}</0>"
|
||||||
|
msgstr "此信息流具有无法编辑且未应用的旧版过滤器。请使用新的表达式编辑器重新创建过滤器。旧版过滤器表达式为:<0>{0}</0>"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
msgid "This is your API key. It can be used for some read-only API operations and grants access to the Fever API. Use the form at the bottom of the page to generate a new API key"
|
||||||
msgstr "这是您的API 密钥,它可以被用于Fever API的只读操作及访问授权。使用页面底部的表单生成一个新的API密钥。"
|
msgstr "这是您的API 密钥,它可以被用于Fever API的只读操作及访问授权。使用页面底部的表单生成一个新的API密钥。"
|
||||||
|
|
||||||
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
|
msgid "This setting can cause scrolling issues on some browsers (e.g. Safari)"
|
||||||
|
msgstr "此设置在部分浏览器(例如 Safari)中可能导致滚动问题"
|
||||||
|
|
||||||
#: src/components/KeyboardShortcutsHelp.tsx
|
#: src/components/KeyboardShortcutsHelp.tsx
|
||||||
msgid "Toggle read status of current entry"
|
msgid "Toggle read status of current entry"
|
||||||
msgstr "切换当前条目的阅读状态"
|
msgstr "切换当前条目的阅读状态"
|
||||||
@@ -1012,6 +1114,10 @@ msgstr "切换侧边栏"
|
|||||||
msgid "Toggle starred status of current entry"
|
msgid "Toggle starred status of current entry"
|
||||||
msgstr "切换当前条目的星标状态"
|
msgstr "切换当前条目的星标状态"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "Topic"
|
||||||
|
msgstr "主题"
|
||||||
|
|
||||||
#: src/pages/auth/LoginPage.tsx
|
#: src/pages/auth/LoginPage.tsx
|
||||||
msgid "Try out CommaFeed with the demo account: demo/demo"
|
msgid "Try out CommaFeed with the demo account: demo/demo"
|
||||||
msgstr "使用演示帐户试用 CommaFeed:demo/demo"
|
msgstr "使用演示帐户试用 CommaFeed:demo/demo"
|
||||||
@@ -1024,8 +1130,8 @@ msgstr "尝试 demo!"
|
|||||||
msgid "Unread"
|
msgid "Unread"
|
||||||
msgstr "未读"
|
msgstr "未读"
|
||||||
|
|
||||||
#: src/components/content/FeedEntryFooter.tsx
|
|
||||||
#: src/components/content/FeedEntryContextMenu.tsx
|
#: src/components/content/FeedEntryContextMenu.tsx
|
||||||
|
#: src/components/content/FeedEntryFooter.tsx
|
||||||
#: src/components/content/header/Star.tsx
|
#: src/components/content/header/Star.tsx
|
||||||
msgid "Unstar"
|
msgid "Unstar"
|
||||||
msgstr "取消星标"
|
msgstr "取消星标"
|
||||||
@@ -1035,6 +1141,10 @@ msgstr "取消星标"
|
|||||||
msgid "Unsubscribe"
|
msgid "Unsubscribe"
|
||||||
msgstr "取消订阅"
|
msgstr "取消订阅"
|
||||||
|
|
||||||
|
#: src/components/settings/PushNotificationSettings.tsx
|
||||||
|
msgid "User key"
|
||||||
|
msgstr "用户密钥"
|
||||||
|
|
||||||
#: src/components/settings/ProfileSettings.tsx
|
#: src/components/settings/ProfileSettings.tsx
|
||||||
msgid "User name"
|
msgid "User name"
|
||||||
msgstr "用户名"
|
msgstr "用户名"
|
||||||
@@ -1056,6 +1166,10 @@ msgstr "警告"
|
|||||||
msgid "Website"
|
msgid "Website"
|
||||||
msgstr "网站"
|
msgstr "网站"
|
||||||
|
|
||||||
|
#: src/pages/auth/InitialSetupPage.tsx
|
||||||
|
msgid "Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get started."
|
||||||
|
msgstr "欢迎!当前页仅当您第一次使用CommaFeed时出现,请创建一个管理员帐号以开始使用。"
|
||||||
|
|
||||||
#: src/components/settings/DisplaySettings.tsx
|
#: src/components/settings/DisplaySettings.tsx
|
||||||
msgid "Yellow"
|
msgid "Yellow"
|
||||||
msgstr "黄"
|
msgstr "黄"
|
||||||
@@ -1067,3 +1181,7 @@ msgstr "您还没有任何订阅。"
|
|||||||
#: src/components/header/ProfileMenu.tsx
|
#: src/components/header/ProfileMenu.tsx
|
||||||
msgid "Your feeds have been queued for refresh."
|
msgid "Your feeds have been queued for refresh."
|
||||||
msgstr "您的订阅已经进入刷新队列。"
|
msgstr "您的订阅已经进入刷新队列。"
|
||||||
|
|
||||||
|
#: src/pages/auth/PasswordResetPage.tsx
|
||||||
|
msgid "Your password has been changed. You can now log in with your new password."
|
||||||
|
msgstr "您的密码已更改。您现在可以使用新密码登录。"
|
||||||
|
|||||||
@@ -19,10 +19,8 @@ const shownGauges: Record<string, string> = {
|
|||||||
"com.commafeed.backend.feed.FeedRefreshEngine.queue.size": "Feed Refresh Engine queue size",
|
"com.commafeed.backend.feed.FeedRefreshEngine.queue.size": "Feed Refresh Engine queue size",
|
||||||
"com.commafeed.backend.feed.FeedRefreshEngine.worker.active": "Feed Refresh Engine active HTTP workers",
|
"com.commafeed.backend.feed.FeedRefreshEngine.worker.active": "Feed Refresh Engine active HTTP workers",
|
||||||
"com.commafeed.backend.feed.FeedRefreshEngine.updater.active": "Feed Refresh Engine active database update workers",
|
"com.commafeed.backend.feed.FeedRefreshEngine.updater.active": "Feed Refresh Engine active database update workers",
|
||||||
"com.commafeed.backend.HttpGetter.pool.max": "HttpGetter max pool size",
|
"com.commafeed.backend.feed.FeedRefreshEngine.notifier.active": "Feed Refresh Engine active push notifications workers",
|
||||||
"com.commafeed.backend.HttpGetter.pool.size": "HttpGetter current pool size",
|
"com.commafeed.backend.feed.FeedRefreshEngine.notifier.queue": "Feed Refresh Engine queued push notifications workers",
|
||||||
"com.commafeed.backend.HttpGetter.pool.leased": "HttpGetter active connections",
|
|
||||||
"com.commafeed.backend.HttpGetter.pool.pending": "HttpGetter waiting for a connection",
|
|
||||||
"com.commafeed.backend.HttpGetter.cache.size": "HttpGetter cached entries",
|
"com.commafeed.backend.HttpGetter.cache.size": "HttpGetter cached entries",
|
||||||
"com.commafeed.backend.HttpGetter.cache.memoryUsage": "HttpGetter cache memory usage",
|
"com.commafeed.backend.HttpGetter.cache.memoryUsage": "HttpGetter cache memory usage",
|
||||||
"com.commafeed.frontend.ws.WebSocketSessions.users": "WebSocket users",
|
"com.commafeed.frontend.ws.WebSocketSessions.users": "WebSocket users",
|
||||||
@@ -35,10 +33,11 @@ export function MetricsPage() {
|
|||||||
setLoading: state => ({ ...state, loading: true }),
|
setLoading: state => ({ ...state, loading: true }),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const { execute } = query
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const interval = setInterval(() => query.execute(), 2000)
|
const interval = setInterval(() => execute(), 2000)
|
||||||
return () => clearInterval(interval)
|
return () => clearInterval(interval)
|
||||||
}, [query.execute])
|
}, [execute])
|
||||||
|
|
||||||
if (!query.result) return <Loader />
|
if (!query.result) return <Loader />
|
||||||
const { meters, gauges } = query.result.data
|
const { meters, gauges } = query.result.data
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ export function AboutPage() {
|
|||||||
<List>
|
<List>
|
||||||
<List.Item>
|
<List.Item>
|
||||||
<Anchor href={Constants.browserExtensionUrl} target="_blank" rel="noreferrer">
|
<Anchor href={Constants.browserExtensionUrl} target="_blank" rel="noreferrer">
|
||||||
<Trans>Browser extention</Trans>
|
<Trans>Browser extension</Trans>
|
||||||
</Anchor>
|
</Anchor>
|
||||||
</List.Item>
|
</List.Item>
|
||||||
<List.Item>
|
<List.Item>
|
||||||
|
|||||||
@@ -1,10 +1,27 @@
|
|||||||
|
import { msg } from "@lingui/core/macro"
|
||||||
|
import { useLingui } from "@lingui/react"
|
||||||
import { Trans } from "@lingui/react/macro"
|
import { Trans } from "@lingui/react/macro"
|
||||||
import { Anchor, Box, Button, Code, Container, Divider, Group, Input, NumberInput, Stack, Text, TextInput, Title } from "@mantine/core"
|
import {
|
||||||
|
Anchor,
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Code,
|
||||||
|
Container,
|
||||||
|
Divider,
|
||||||
|
Group,
|
||||||
|
Input,
|
||||||
|
Alert as MantineAlert,
|
||||||
|
NumberInput,
|
||||||
|
Stack,
|
||||||
|
Text,
|
||||||
|
TextInput,
|
||||||
|
Title,
|
||||||
|
} from "@mantine/core"
|
||||||
import { useForm } from "@mantine/form"
|
import { useForm } from "@mantine/form"
|
||||||
import { openConfirmModal } from "@mantine/modals"
|
import { openConfirmModal } from "@mantine/modals"
|
||||||
import { useEffect } from "react"
|
import { useEffect } from "react"
|
||||||
import { useAsync, useAsyncCallback } from "react-async-hook"
|
import { useAsync, useAsyncCallback } from "react-async-hook"
|
||||||
import { TbDeviceFloppy, TbTrash } from "react-icons/tb"
|
import { TbAlertTriangle, TbDeviceFloppy, TbTrash } from "react-icons/tb"
|
||||||
import { useParams } from "react-router-dom"
|
import { useParams } from "react-router-dom"
|
||||||
import { client, errorToStrings } from "@/app/client"
|
import { client, errorToStrings } from "@/app/client"
|
||||||
import { redirectToRootCategory, redirectToSelectedSource } from "@/app/redirect/thunks"
|
import { redirectToRootCategory, redirectToSelectedSource } from "@/app/redirect/thunks"
|
||||||
@@ -13,46 +30,17 @@ import { reloadTree } from "@/app/tree/thunks"
|
|||||||
import type { FeedModificationRequest } from "@/app/types"
|
import type { FeedModificationRequest } from "@/app/types"
|
||||||
import { Alert } from "@/components/Alert"
|
import { Alert } from "@/components/Alert"
|
||||||
import { CategorySelect } from "@/components/content/add/CategorySelect"
|
import { CategorySelect } from "@/components/content/add/CategorySelect"
|
||||||
|
import { FilteringExpressionEditor } from "@/components/content/edit/FilteringExpressionEditor"
|
||||||
import { Loader } from "@/components/Loader"
|
import { Loader } from "@/components/Loader"
|
||||||
|
import { ReceivePushNotificationsChechbox } from "@/components/ReceivePushNotificationsChechbox"
|
||||||
import { RelativeDate } from "@/components/RelativeDate"
|
import { RelativeDate } from "@/components/RelativeDate"
|
||||||
|
|
||||||
function FilteringExpressionDescription() {
|
|
||||||
const example = <Code>url.contains('youtube') or (author eq 'athou' and title.contains('github'))</Code>
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<Trans>
|
|
||||||
If not empty, an expression evaluating to 'true' or 'false'. If false, new entries for this feed will be marked as read
|
|
||||||
automatically.
|
|
||||||
</Trans>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Trans>
|
|
||||||
Available variables are 'title', 'content', 'url' 'author' and 'categories' and their content is converted to lower case
|
|
||||||
to ease string comparison.
|
|
||||||
</Trans>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Trans>Example: {example}.</Trans>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Trans>
|
|
||||||
<span>Complete syntax is available </span>
|
|
||||||
<a href="https://commons.apache.org/proper/commons-jexl/reference/syntax.html" target="_blank" rel="noreferrer">
|
|
||||||
here
|
|
||||||
</a>
|
|
||||||
<span>.</span>
|
|
||||||
</Trans>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function FeedDetailsPage() {
|
export function FeedDetailsPage() {
|
||||||
const { id } = useParams()
|
const { id } = useParams()
|
||||||
if (!id) throw Error("id required")
|
if (!id) throw new Error("id required")
|
||||||
|
|
||||||
const apiKey = useAppSelector(state => state.user.profile?.apiKey)
|
const apiKey = useAppSelector(state => state.user.profile?.apiKey)
|
||||||
|
const { _ } = useLingui()
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
const query = useAsync(async () => await client.feed.get(id), [id])
|
const query = useAsync(async () => await client.feed.get(id), [id])
|
||||||
const feed = query.result?.data
|
const feed = query.result?.data
|
||||||
@@ -158,11 +146,36 @@ export function FeedDetailsPage() {
|
|||||||
<TextInput label={<Trans>Name</Trans>} {...form.getInputProps("name")} required />
|
<TextInput label={<Trans>Name</Trans>} {...form.getInputProps("name")} required />
|
||||||
<CategorySelect label={<Trans>Category</Trans>} {...form.getInputProps("categoryId")} clearable />
|
<CategorySelect label={<Trans>Category</Trans>} {...form.getInputProps("categoryId")} clearable />
|
||||||
<NumberInput label={<Trans>Position</Trans>} {...form.getInputProps("position")} required min={0} />
|
<NumberInput label={<Trans>Position</Trans>} {...form.getInputProps("position")} required min={0} />
|
||||||
<TextInput
|
<ReceivePushNotificationsChechbox {...form.getInputProps("pushNotificationsEnabled", { type: "checkbox" })} />
|
||||||
label={<Trans>Filtering expression</Trans>}
|
<NumberInput
|
||||||
description={<FilteringExpressionDescription />}
|
label={<Trans>Auto-mark as read</Trans>}
|
||||||
{...form.getInputProps("filter")}
|
description={<Trans>Mark entries in this feed as read after this number of days. Leave empty to disable.</Trans>}
|
||||||
|
suffix={` ${_(msg`days`)}`}
|
||||||
|
{...form.getInputProps("autoMarkAsReadAfterDays")}
|
||||||
|
min={1}
|
||||||
|
max={3650}
|
||||||
/>
|
/>
|
||||||
|
<Input.Wrapper
|
||||||
|
label={<Trans>Filtering expression</Trans>}
|
||||||
|
description={
|
||||||
|
<Trans>
|
||||||
|
Build a filter expression to indicate what you want to read. Entries that don't match will be marked as read
|
||||||
|
automatically.
|
||||||
|
</Trans>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{feed.filterLegacy && (
|
||||||
|
<MantineAlert color="yellow" icon={<TbAlertTriangle />}>
|
||||||
|
<Trans>
|
||||||
|
This feed has a legacy filter that cannot be edited and is not applied. Please recreate the filter using
|
||||||
|
the new expression editor. The legacy filter expression was: <Code>{feed.filterLegacy}</Code>
|
||||||
|
</Trans>
|
||||||
|
</MantineAlert>
|
||||||
|
)}
|
||||||
|
<Box mt="xs">
|
||||||
|
<FilteringExpressionEditor initialValue={feed.filter} onChange={value => form.setFieldValue("filter", value)} />
|
||||||
|
</Box>
|
||||||
|
</Input.Wrapper>
|
||||||
|
|
||||||
<Group>
|
<Group>
|
||||||
<Button variant="default" onClick={async () => await dispatch(redirectToSelectedSource())}>
|
<Button variant="default" onClick={async () => await dispatch(redirectToSelectedSource())}>
|
||||||
|
|||||||
@@ -8,9 +8,11 @@ import { Constants } from "@/app/constants"
|
|||||||
import type { EntrySourceType } from "@/app/entries/slice"
|
import type { EntrySourceType } from "@/app/entries/slice"
|
||||||
import { loadEntries } from "@/app/entries/thunks"
|
import { loadEntries } from "@/app/entries/thunks"
|
||||||
import { redirectToCategoryDetails, redirectToFeedDetails, redirectToTagDetails } from "@/app/redirect/thunks"
|
import { redirectToCategoryDetails, redirectToFeedDetails, redirectToTagDetails } from "@/app/redirect/thunks"
|
||||||
import { useAppDispatch, useAppSelector } from "@/app/store"
|
import { useAppDispatch, useAppSelector, useShallowEqualAppSelector } from "@/app/store"
|
||||||
import { flattenCategoryTree } from "@/app/utils"
|
import { categoryHasNewEntries, categoryUnreadCount, flattenCategoryTree } from "@/app/utils"
|
||||||
import { FeedEntries } from "@/components/content/FeedEntries"
|
import { FeedEntries } from "@/components/content/FeedEntries"
|
||||||
|
import { UnreadCount } from "@/components/sidebar/UnreadCount"
|
||||||
|
import { useMobile } from "@/hooks/useMobile"
|
||||||
import { tss } from "@/tss"
|
import { tss } from "@/tss"
|
||||||
|
|
||||||
function NoSubscriptionHelp() {
|
function NoSubscriptionHelp() {
|
||||||
@@ -33,6 +35,12 @@ const useStyles = tss.create(() => ({
|
|||||||
sourceWebsiteLink: {
|
sourceWebsiteLink: {
|
||||||
color: "inherit",
|
color: "inherit",
|
||||||
textDecoration: "none",
|
textDecoration: "none",
|
||||||
|
overflow: "hidden",
|
||||||
|
},
|
||||||
|
titleText: {
|
||||||
|
overflow: "hidden",
|
||||||
|
textOverflow: "ellipsis",
|
||||||
|
whiteSpace: "nowrap",
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
@@ -48,6 +56,33 @@ export function FeedEntriesPage(props: Readonly<FeedEntriesPageProps>) {
|
|||||||
const sourceLabel = useAppSelector(state => state.entries.sourceLabel)
|
const sourceLabel = useAppSelector(state => state.entries.sourceLabel)
|
||||||
const sourceWebsiteUrl = useAppSelector(state => state.entries.sourceWebsiteUrl)
|
const sourceWebsiteUrl = useAppSelector(state => state.entries.sourceWebsiteUrl)
|
||||||
const hasMore = useAppSelector(state => state.entries.hasMore)
|
const hasMore = useAppSelector(state => state.entries.hasMore)
|
||||||
|
const mobile = useMobile()
|
||||||
|
const sidebarVisible = useAppSelector(state => state.tree.sidebarVisible)
|
||||||
|
const { unreadCount, hasNewEntries } = useShallowEqualAppSelector(state => {
|
||||||
|
const root = state.tree.rootCategory
|
||||||
|
if (!root) return { unreadCount: 0, hasNewEntries: false }
|
||||||
|
|
||||||
|
if (props.sourceType === "category") {
|
||||||
|
const category = id === Constants.categories.all.id ? root : flattenCategoryTree(root).find(c => c.id === id)
|
||||||
|
return {
|
||||||
|
unreadCount: categoryUnreadCount(category),
|
||||||
|
hasNewEntries: categoryHasNewEntries(category),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.sourceType === "feed") {
|
||||||
|
const feed = flattenCategoryTree(root)
|
||||||
|
.flatMap(c => c.feeds)
|
||||||
|
.find(f => f.id === +id)
|
||||||
|
return {
|
||||||
|
unreadCount: feed?.unread ?? 0,
|
||||||
|
hasNewEntries: !!feed?.hasNewEntries,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { unreadCount: 0, hasNewEntries: false }
|
||||||
|
})
|
||||||
|
const showUnreadCount = mobile || !sidebarVisible
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
|
|
||||||
let title: React.ReactNode = sourceLabel
|
let title: React.ReactNode = sourceLabel
|
||||||
@@ -89,16 +124,23 @@ export function FeedEntriesPage(props: Readonly<FeedEntriesPageProps>) {
|
|||||||
return (
|
return (
|
||||||
// add some room at the bottom of the page in order to be able to scroll the current entry at the top of the page when expanding
|
// add some room at the bottom of the page in order to be able to scroll the current entry at the top of the page when expanding
|
||||||
<Box mb={viewport.height * 0.7}>
|
<Box mb={viewport.height * 0.7}>
|
||||||
<Group gap="xl" className="cf-entries-title">
|
<Group className="cf-entries-title" wrap="nowrap">
|
||||||
{sourceWebsiteUrl && (
|
{sourceWebsiteUrl && (
|
||||||
<a href={sourceWebsiteUrl} target="_blank" rel="noreferrer" className={classes.sourceWebsiteLink}>
|
<a href={sourceWebsiteUrl} target="_blank" rel="noreferrer" className={classes.sourceWebsiteLink}>
|
||||||
<Title order={3}>{title}</Title>
|
<Title order={3} className={classes.titleText}>
|
||||||
|
{title}
|
||||||
|
</Title>
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
{!sourceWebsiteUrl && <Title order={3}>{title}</Title>}
|
{!sourceWebsiteUrl && (
|
||||||
|
<Title order={3} className={classes.titleText}>
|
||||||
|
{title}
|
||||||
|
</Title>
|
||||||
|
)}
|
||||||
<ActionIcon onClick={titleClicked} variant="subtle" color={theme.primaryColor}>
|
<ActionIcon onClick={titleClicked} variant="subtle" color={theme.primaryColor}>
|
||||||
<TbEdit size={18} />
|
<TbEdit size={18} />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
|
{showUnreadCount && <UnreadCount unreadCount={unreadCount} showIndicator={hasNewEntries} />}
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
<FeedEntries />
|
<FeedEntries />
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { Trans } from "@lingui/react/macro"
|
import { Trans } from "@lingui/react/macro"
|
||||||
import { Container, Tabs } from "@mantine/core"
|
import { Container, Tabs } from "@mantine/core"
|
||||||
import { TbCode, TbPhoto, TbUser } from "react-icons/tb"
|
import { TbBell, TbCode, TbPhoto, TbUser } from "react-icons/tb"
|
||||||
import { CustomCodeSettings } from "@/components/settings/CustomCodeSettings"
|
import { CustomCodeSettings } from "@/components/settings/CustomCodeSettings"
|
||||||
import { DisplaySettings } from "@/components/settings/DisplaySettings"
|
import { DisplaySettings } from "@/components/settings/DisplaySettings"
|
||||||
import { ProfileSettings } from "@/components/settings/ProfileSettings"
|
import { ProfileSettings } from "@/components/settings/ProfileSettings"
|
||||||
|
import { PushNotificationSettings } from "@/components/settings/PushNotificationSettings"
|
||||||
|
|
||||||
export function SettingsPage() {
|
export function SettingsPage() {
|
||||||
return (
|
return (
|
||||||
@@ -13,6 +14,9 @@ export function SettingsPage() {
|
|||||||
<Tabs.Tab value="display" leftSection={<TbPhoto size={16} />}>
|
<Tabs.Tab value="display" leftSection={<TbPhoto size={16} />}>
|
||||||
<Trans>Display</Trans>
|
<Trans>Display</Trans>
|
||||||
</Tabs.Tab>
|
</Tabs.Tab>
|
||||||
|
<Tabs.Tab value="push-notifications" leftSection={<TbBell size={16} />}>
|
||||||
|
<Trans>Push notifications</Trans>
|
||||||
|
</Tabs.Tab>
|
||||||
<Tabs.Tab value="customCode" leftSection={<TbCode size={16} />}>
|
<Tabs.Tab value="customCode" leftSection={<TbCode size={16} />}>
|
||||||
<Trans>Custom code</Trans>
|
<Trans>Custom code</Trans>
|
||||||
</Tabs.Tab>
|
</Tabs.Tab>
|
||||||
@@ -25,6 +29,10 @@ export function SettingsPage() {
|
|||||||
<DisplaySettings />
|
<DisplaySettings />
|
||||||
</Tabs.Panel>
|
</Tabs.Panel>
|
||||||
|
|
||||||
|
<Tabs.Panel value="push-notifications" pt="xl">
|
||||||
|
<PushNotificationSettings />
|
||||||
|
</Tabs.Panel>
|
||||||
|
|
||||||
<Tabs.Panel value="customCode" pt="xl">
|
<Tabs.Panel value="customCode" pt="xl">
|
||||||
<CustomCodeSettings />
|
<CustomCodeSettings />
|
||||||
</Tabs.Panel>
|
</Tabs.Panel>
|
||||||
|
|||||||
95
commafeed-client/src/pages/auth/InitialSetupPage.tsx
Normal file
95
commafeed-client/src/pages/auth/InitialSetupPage.tsx
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
import { msg } from "@lingui/core/macro"
|
||||||
|
import { useLingui } from "@lingui/react"
|
||||||
|
import { Trans } from "@lingui/react/macro"
|
||||||
|
import { Box, Button, Container, Paper, PasswordInput, Stack, TextInput, Title } from "@mantine/core"
|
||||||
|
import { useForm } from "@mantine/form"
|
||||||
|
import { useAsyncCallback } from "react-async-hook"
|
||||||
|
import { client, errorToStrings } from "@/app/client"
|
||||||
|
import { redirectToRootCategory } from "@/app/redirect/thunks"
|
||||||
|
import { useAppDispatch } from "@/app/store"
|
||||||
|
import type { InitialSetupRequest } from "@/app/types"
|
||||||
|
import { Alert } from "@/components/Alert"
|
||||||
|
import { useValidationRules } from "@/hooks/useValidationRules"
|
||||||
|
import { PageTitle } from "@/pages/PageTitle"
|
||||||
|
|
||||||
|
export function InitialSetupPage() {
|
||||||
|
const dispatch = useAppDispatch()
|
||||||
|
const { _ } = useLingui()
|
||||||
|
const validationRules = useValidationRules()
|
||||||
|
|
||||||
|
const form = useForm<InitialSetupRequest>({
|
||||||
|
initialValues: {
|
||||||
|
name: "",
|
||||||
|
password: "",
|
||||||
|
email: "",
|
||||||
|
},
|
||||||
|
validate: {
|
||||||
|
password: validationRules.password,
|
||||||
|
},
|
||||||
|
validateInputOnChange: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
const login = useAsyncCallback(client.user.login, {
|
||||||
|
onSuccess: () => {
|
||||||
|
dispatch(redirectToRootCategory())
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const setup = useAsyncCallback(client.user.initialSetup, {
|
||||||
|
onSuccess: () => {
|
||||||
|
login.execute(form.values)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container size="xs">
|
||||||
|
<PageTitle />
|
||||||
|
<Paper>
|
||||||
|
<Title order={2} mb="md">
|
||||||
|
<Trans>Initial Setup</Trans>
|
||||||
|
</Title>
|
||||||
|
<Box mb="md">
|
||||||
|
<Trans>
|
||||||
|
Welcome! This appears to be the first time you're running CommaFeed. Please create an administrator account to get
|
||||||
|
started.
|
||||||
|
</Trans>
|
||||||
|
</Box>
|
||||||
|
{setup.error && (
|
||||||
|
<Box mb="md">
|
||||||
|
<Alert messages={errorToStrings(setup.error)} />
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
<form onSubmit={form.onSubmit(setup.execute)}>
|
||||||
|
<Stack>
|
||||||
|
<TextInput
|
||||||
|
label={<Trans>Admin user name</Trans>}
|
||||||
|
placeholder={_(msg`Admin user name`)}
|
||||||
|
{...form.getInputProps("name")}
|
||||||
|
size="md"
|
||||||
|
required
|
||||||
|
autoCapitalize="off"
|
||||||
|
/>
|
||||||
|
<PasswordInput
|
||||||
|
label={<Trans>Password</Trans>}
|
||||||
|
placeholder={_(msg`Password`)}
|
||||||
|
{...form.getInputProps("password")}
|
||||||
|
size="md"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
type="email"
|
||||||
|
label={<Trans>E-mail</Trans>}
|
||||||
|
placeholder={_(msg`E-mail`)}
|
||||||
|
{...form.getInputProps("email")}
|
||||||
|
size="md"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button type="submit" loading={setup.loading}>
|
||||||
|
<Trans>Create Admin Account</Trans>
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
|
</form>
|
||||||
|
</Paper>
|
||||||
|
</Container>
|
||||||
|
)
|
||||||
|
}
|
||||||
119
commafeed-client/src/pages/auth/PasswordResetPage.tsx
Normal file
119
commafeed-client/src/pages/auth/PasswordResetPage.tsx
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
import { msg } from "@lingui/core/macro"
|
||||||
|
import { useLingui } from "@lingui/react"
|
||||||
|
import { Trans } from "@lingui/react/macro"
|
||||||
|
import { Anchor, Box, Button, Center, Container, Group, Paper, PasswordInput, Stack, Title } from "@mantine/core"
|
||||||
|
import { useForm } from "@mantine/form"
|
||||||
|
import { useState } from "react"
|
||||||
|
import { useAsyncCallback } from "react-async-hook"
|
||||||
|
import { Link, useSearchParams } from "react-router-dom"
|
||||||
|
import { client, errorToStrings } from "@/app/client"
|
||||||
|
import { Alert } from "@/components/Alert"
|
||||||
|
import { useValidationRules } from "@/hooks/useValidationRules"
|
||||||
|
import { PageTitle } from "@/pages/PageTitle"
|
||||||
|
|
||||||
|
interface PasswordResetFormValues {
|
||||||
|
password: string
|
||||||
|
passwordConfirmation: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PasswordResetPage() {
|
||||||
|
const [message, setMessage] = useState("")
|
||||||
|
const [searchParams] = useSearchParams()
|
||||||
|
const { _ } = useLingui()
|
||||||
|
const validationRules = useValidationRules()
|
||||||
|
|
||||||
|
const email = searchParams.get("email") ?? ""
|
||||||
|
const token = searchParams.get("token") ?? ""
|
||||||
|
|
||||||
|
const form = useForm<PasswordResetFormValues>({
|
||||||
|
initialValues: {
|
||||||
|
password: "",
|
||||||
|
passwordConfirmation: "",
|
||||||
|
},
|
||||||
|
validate: {
|
||||||
|
password: validationRules.password,
|
||||||
|
passwordConfirmation: (value, values) => validationRules.passwordConfirmation(value, values.password),
|
||||||
|
},
|
||||||
|
validateInputOnChange: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
const resetPassword = useAsyncCallback(client.user.passwordResetCallback, {
|
||||||
|
onSuccess: () => {
|
||||||
|
setMessage(_(msg`Your password has been changed. You can now log in with your new password.`))
|
||||||
|
form.reset()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const isMissingParams = !email || !token
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container size="xs">
|
||||||
|
<PageTitle />
|
||||||
|
<Paper>
|
||||||
|
<Title order={2} mb="md">
|
||||||
|
<Trans>Reset Password</Trans>
|
||||||
|
</Title>
|
||||||
|
|
||||||
|
{resetPassword.error && (
|
||||||
|
<Box mb="md">
|
||||||
|
<Alert messages={errorToStrings(resetPassword.error)} />
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{isMissingParams && (
|
||||||
|
<Box mb="md">
|
||||||
|
<Alert messages={[_(msg`Invalid password reset link. Please request a new one.`)]} />
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{message && (
|
||||||
|
<Box mb="md">
|
||||||
|
<Alert level="success" messages={[message]} />
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!isMissingParams && !message && (
|
||||||
|
<form
|
||||||
|
onSubmit={form.onSubmit(values => {
|
||||||
|
resetPassword.execute({
|
||||||
|
email,
|
||||||
|
token,
|
||||||
|
password: values.password,
|
||||||
|
})
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Stack>
|
||||||
|
<PasswordInput
|
||||||
|
label={<Trans>New Password</Trans>}
|
||||||
|
placeholder={_(msg`New Password`)}
|
||||||
|
{...form.getInputProps("password")}
|
||||||
|
size="md"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
|
||||||
|
<PasswordInput
|
||||||
|
label={<Trans>Confirm Password</Trans>}
|
||||||
|
placeholder={_(msg`Confirm Password`)}
|
||||||
|
{...form.getInputProps("passwordConfirmation")}
|
||||||
|
size="md"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button type="submit" loading={resetPassword.loading}>
|
||||||
|
<Trans>Reset Password</Trans>
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
|
</form>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Center mt="md">
|
||||||
|
<Group>
|
||||||
|
<Anchor component={Link} to="/login">
|
||||||
|
<Trans>Back to log in</Trans>
|
||||||
|
</Anchor>
|
||||||
|
</Group>
|
||||||
|
</Center>
|
||||||
|
</Paper>
|
||||||
|
</Container>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -10,12 +10,14 @@ import { redirectToRootCategory } from "@/app/redirect/thunks"
|
|||||||
import { useAppDispatch, useAppSelector } from "@/app/store"
|
import { useAppDispatch, useAppSelector } from "@/app/store"
|
||||||
import type { RegistrationRequest } from "@/app/types"
|
import type { RegistrationRequest } from "@/app/types"
|
||||||
import { Alert } from "@/components/Alert"
|
import { Alert } from "@/components/Alert"
|
||||||
|
import { useValidationRules } from "@/hooks/useValidationRules"
|
||||||
import { PageTitle } from "@/pages/PageTitle"
|
import { PageTitle } from "@/pages/PageTitle"
|
||||||
|
|
||||||
export function RegistrationPage() {
|
export function RegistrationPage() {
|
||||||
const serverInfos = useAppSelector(state => state.server.serverInfos)
|
const serverInfos = useAppSelector(state => state.server.serverInfos)
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
const { _ } = useLingui()
|
const { _ } = useLingui()
|
||||||
|
const validationRules = useValidationRules()
|
||||||
|
|
||||||
const form = useForm<RegistrationRequest>({
|
const form = useForm<RegistrationRequest>({
|
||||||
initialValues: {
|
initialValues: {
|
||||||
@@ -23,6 +25,10 @@ export function RegistrationPage() {
|
|||||||
password: "",
|
password: "",
|
||||||
email: "",
|
email: "",
|
||||||
},
|
},
|
||||||
|
validate: {
|
||||||
|
password: validationRules.password,
|
||||||
|
},
|
||||||
|
validateInputOnChange: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const login = useAsyncCallback(client.user.login, {
|
const login = useAsyncCallback(client.user.login, {
|
||||||
@@ -72,7 +78,7 @@ export function RegistrationPage() {
|
|||||||
placeholder={_(msg`E-mail address`)}
|
placeholder={_(msg`E-mail address`)}
|
||||||
{...form.getInputProps("email")}
|
{...form.getInputProps("email")}
|
||||||
size="md"
|
size="md"
|
||||||
required
|
required={serverInfos.emailAddressRequired}
|
||||||
/>
|
/>
|
||||||
<PasswordInput
|
<PasswordInput
|
||||||
label={<Trans>Password</Trans>}
|
label={<Trans>Password</Trans>}
|
||||||
|
|||||||
@@ -1,27 +1,17 @@
|
|||||||
import { lingui } from "@lingui/vite-plugin"
|
import { lingui } from "@lingui/vite-plugin"
|
||||||
import react from "@vitejs/plugin-react"
|
import babel from "@rolldown/plugin-babel"
|
||||||
import { visualizer } from "rollup-plugin-visualizer"
|
import react, { reactCompilerPreset } from "@vitejs/plugin-react"
|
||||||
import { defineConfig } from "vite"
|
import { defineConfig } from "vite"
|
||||||
import checker from "vite-plugin-checker"
|
import checker from "vite-plugin-checker"
|
||||||
import tsconfigPaths from "vite-tsconfig-paths"
|
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
|
||||||
export default defineConfig(() => ({
|
export default defineConfig(() => ({
|
||||||
plugins: [
|
plugins: [
|
||||||
react({
|
react(),
|
||||||
babel: {
|
babel({
|
||||||
plugins: [
|
presets: [reactCompilerPreset()],
|
||||||
// support for lingui macros
|
plugins: ["@lingui/babel-plugin-lingui-macro"],
|
||||||
// needs to be before the react compiler plugin
|
|
||||||
"@lingui/babel-plugin-lingui-macro",
|
|
||||||
// react compiler
|
|
||||||
["babel-plugin-react-compiler", { target: "19" }],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
lingui(),
|
lingui(),
|
||||||
tsconfigPaths(),
|
|
||||||
visualizer(),
|
|
||||||
checker({
|
checker({
|
||||||
typescript: true,
|
typescript: true,
|
||||||
biome: {
|
biome: {
|
||||||
@@ -45,22 +35,32 @@ export default defineConfig(() => ({
|
|||||||
"/logout": "http://localhost:8083",
|
"/logout": "http://localhost:8083",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
build: {
|
resolve: {
|
||||||
chunkSizeWarningLimit: 3500,
|
tsconfigPaths: true,
|
||||||
rollupOptions: {
|
},
|
||||||
output: {
|
legacy: {
|
||||||
manualChunks: id => {
|
// required for websocket-heartbeat-js
|
||||||
// output mantine as its own chunk because it is quite large
|
inconsistentCjsInterop: true,
|
||||||
if (id.includes("@mantine")) {
|
|
||||||
return "mantine"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
test: {
|
test: {
|
||||||
environment: "jsdom",
|
environment: "jsdom",
|
||||||
globals: true,
|
globals: true,
|
||||||
setupFiles: "./src/setupTests.ts",
|
setupFiles: "./src/setupTests.ts",
|
||||||
},
|
},
|
||||||
|
build: {
|
||||||
|
chunkSizeWarningLimit: 4000,
|
||||||
|
rolldownOptions: {
|
||||||
|
output: {
|
||||||
|
codeSplitting: {
|
||||||
|
groups: [
|
||||||
|
// output mantine as its own chunk because it is quite large
|
||||||
|
{
|
||||||
|
name: "mantine",
|
||||||
|
test: "@mantine",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}))
|
}))
|
||||||
|
|||||||
@@ -6,14 +6,15 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.commafeed</groupId>
|
<groupId>com.commafeed</groupId>
|
||||||
<artifactId>commafeed</artifactId>
|
<artifactId>commafeed</artifactId>
|
||||||
<version>5.11.0</version>
|
<version>7.0.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>commafeed-server</artifactId>
|
<artifactId>commafeed-server</artifactId>
|
||||||
<name>CommaFeed Server</name>
|
<name>CommaFeed Server</name>
|
||||||
|
<packaging>quarkus</packaging>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<quarkus.version>3.25.0</quarkus.version>
|
<quarkus.version>3.32.4</quarkus.version>
|
||||||
<querydsl.version>7.0</querydsl.version>
|
<querydsl.version>7.1</querydsl.version>
|
||||||
<rome.version>2.1.0</rome.version>
|
<rome.version>2.1.0</rome.version>
|
||||||
|
|
||||||
<build.database>h2</build.database>
|
<build.database>h2</build.database>
|
||||||
@@ -28,6 +29,12 @@
|
|||||||
<type>pom</type>
|
<type>pom</type>
|
||||||
<scope>import</scope>
|
<scope>import</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- the quarkus bom declares a dependency on an old version of protobuf, we need to override it for cel-java -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.protobuf</groupId>
|
||||||
|
<artifactId>protobuf-java</artifactId>
|
||||||
|
<version>4.34.1</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
|
|
||||||
@@ -55,7 +62,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
<artifactId>properties-maven-plugin</artifactId>
|
<artifactId>properties-maven-plugin</artifactId>
|
||||||
<version>1.2.1</version>
|
<version>1.3.0</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<goals>
|
<goals>
|
||||||
@@ -77,24 +84,14 @@
|
|||||||
<artifactId>quarkus-maven-plugin</artifactId>
|
<artifactId>quarkus-maven-plugin</artifactId>
|
||||||
<version>${quarkus.version}</version>
|
<version>${quarkus.version}</version>
|
||||||
<extensions>true</extensions>
|
<extensions>true</extensions>
|
||||||
<executions>
|
<configuration>
|
||||||
<execution>
|
<properties>
|
||||||
<goals>
|
<quarkus.package.output-name>commafeed-${project.version}</quarkus.package.output-name>
|
||||||
<goal>build</goal>
|
<quarkus.package.runner-suffix>
|
||||||
<goal>generate-code</goal>
|
-${build.database}-${os.detected.name}-${os.detected.arch}-runner
|
||||||
<goal>generate-code-tests</goal>
|
</quarkus.package.runner-suffix>
|
||||||
<goal>native-image-agent</goal>
|
</properties>
|
||||||
</goals>
|
</configuration>
|
||||||
<configuration>
|
|
||||||
<properties>
|
|
||||||
<quarkus.package.output-name>commafeed-${project.version}</quarkus.package.output-name>
|
|
||||||
<quarkus.package.runner-suffix>
|
|
||||||
-${build.database}-${os.detected.name}-${os.detected.arch}-runner
|
|
||||||
</quarkus.package.runner-suffix>
|
|
||||||
</properties>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>io.quarkus</groupId>
|
<groupId>io.quarkus</groupId>
|
||||||
@@ -117,7 +114,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
<artifactId>exec-maven-plugin</artifactId>
|
<artifactId>exec-maven-plugin</artifactId>
|
||||||
<version>3.5.1</version>
|
<version>3.6.3</version>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.quarkus</groupId>
|
<groupId>io.quarkus</groupId>
|
||||||
@@ -145,7 +142,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-assembly-plugin</artifactId>
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
<version>3.7.1</version>
|
<version>3.8.0</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<phase>package</phase>
|
<phase>package</phase>
|
||||||
@@ -165,8 +162,9 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<version>3.5.3</version>
|
<version>3.5.5</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
|
<argLine>@{argLine}</argLine>
|
||||||
<systemPropertyVariables>
|
<systemPropertyVariables>
|
||||||
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
|
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
|
||||||
<quarkus.datasource.db-kind>${build.database}</quarkus.datasource.db-kind>
|
<quarkus.datasource.db-kind>${build.database}</quarkus.datasource.db-kind>
|
||||||
@@ -176,7 +174,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-failsafe-plugin</artifactId>
|
<artifactId>maven-failsafe-plugin</artifactId>
|
||||||
<version>3.5.3</version>
|
<version>3.5.5</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<goals>
|
<goals>
|
||||||
@@ -186,6 +184,7 @@
|
|||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
<configuration>
|
<configuration>
|
||||||
|
<argLine>@{argLine}</argLine>
|
||||||
<systemPropertyVariables>
|
<systemPropertyVariables>
|
||||||
<native.image.path>${project.build.directory}/${project.build.finalName}-runner
|
<native.image.path>${project.build.directory}/${project.build.finalName}-runner
|
||||||
</native.image.path>
|
</native.image.path>
|
||||||
@@ -217,61 +216,6 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
|
||||||
<groupId>org.jacoco</groupId>
|
|
||||||
<artifactId>jacoco-maven-plugin</artifactId>
|
|
||||||
<version>0.8.13</version>
|
|
||||||
<configuration>
|
|
||||||
<!-- excluding SACParserCSS21TokenManager because it causes a "Method too large" exception -->
|
|
||||||
<excludes>
|
|
||||||
<exclude>com/steadystate/css/parser/SACParserCSS21TokenManager</exclude>
|
|
||||||
</excludes>
|
|
||||||
</configuration>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>unit-tests-agent</id>
|
|
||||||
<goals>
|
|
||||||
<goal>prepare-agent</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<destFile>${project.build.directory}/jacoco-output/jacoco-unit-tests.exec</destFile>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
<execution>
|
|
||||||
<id>integration-tests-agent</id>
|
|
||||||
<goals>
|
|
||||||
<goal>prepare-agent-integration</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<destFile>${project.build.directory}/jacoco-output/jacoco-integration-tests.exec</destFile>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
<execution>
|
|
||||||
<id>merge</id>
|
|
||||||
<phase>post-integration-test</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>merge</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<fileSets>
|
|
||||||
<fileSet>
|
|
||||||
<directory>${project.build.directory}/jacoco-output</directory>
|
|
||||||
<includes>
|
|
||||||
<include>*.exec</include>
|
|
||||||
</includes>
|
|
||||||
</fileSet>
|
|
||||||
</fileSets>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
<execution>
|
|
||||||
<id>generate-code-coverage-report</id>
|
|
||||||
<phase>post-integration-test</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>report</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>io.github.git-commit-id</groupId>
|
<groupId>io.github.git-commit-id</groupId>
|
||||||
<artifactId>git-commit-id-maven-plugin</artifactId>
|
<artifactId>git-commit-id-maven-plugin</artifactId>
|
||||||
@@ -299,7 +243,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.puppycrawl.tools</groupId>
|
<groupId>com.puppycrawl.tools</groupId>
|
||||||
<artifactId>checkstyle</artifactId>
|
<artifactId>checkstyle</artifactId>
|
||||||
<version>10.26.1</version>
|
<version>13.3.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<executions>
|
<executions>
|
||||||
@@ -328,7 +272,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>com.diffplug.spotless</groupId>
|
<groupId>com.diffplug.spotless</groupId>
|
||||||
<artifactId>spotless-maven-plugin</artifactId>
|
<artifactId>spotless-maven-plugin</artifactId>
|
||||||
<version>2.46.1</version>
|
<version>3.4.0</version>
|
||||||
<?m2e ignore?>
|
<?m2e ignore?>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
@@ -357,14 +301,14 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.commafeed</groupId>
|
<groupId>com.commafeed</groupId>
|
||||||
<artifactId>commafeed-client</artifactId>
|
<artifactId>commafeed-client</artifactId>
|
||||||
<version>5.11.0</version>
|
<version>7.0.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- compile-time processors -->
|
<!-- compile-time processors -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
<version>1.18.38</version>
|
<version>1.18.44</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -376,7 +320,6 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.quarkus</groupId>
|
<groupId>io.quarkus</groupId>
|
||||||
<artifactId>quarkus-extension-processor</artifactId>
|
<artifactId>quarkus-extension-processor</artifactId>
|
||||||
<version>${quarkus.version}</version>
|
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
@@ -425,7 +368,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.dropwizard.metrics</groupId>
|
<groupId>io.dropwizard.metrics</groupId>
|
||||||
<artifactId>metrics-json</artifactId>
|
<artifactId>metrics-json</artifactId>
|
||||||
<version>4.2.33</version>
|
<version>4.2.38</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.github.openfeign.querydsl</groupId>
|
<groupId>io.github.openfeign.querydsl</groupId>
|
||||||
@@ -454,15 +397,9 @@
|
|||||||
<version>3.6.1</version>
|
<version>3.6.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>dev.cel</groupId>
|
||||||
<artifactId>commons-jexl</artifactId>
|
<artifactId>cel</artifactId>
|
||||||
<version>2.1.1</version>
|
<version>0.12.0</version>
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<artifactId>commons-logging</artifactId>
|
|
||||||
<groupId>commons-logging</groupId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.passay</groupId>
|
<groupId>org.passay</groupId>
|
||||||
@@ -492,12 +429,12 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jsoup</groupId>
|
<groupId>org.jsoup</groupId>
|
||||||
<artifactId>jsoup</artifactId>
|
<artifactId>jsoup</artifactId>
|
||||||
<version>1.21.1</version>
|
<version>1.22.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.ibm.icu</groupId>
|
<groupId>com.ibm.icu</groupId>
|
||||||
<artifactId>icu4j</artifactId>
|
<artifactId>icu4j</artifactId>
|
||||||
<version>77.1</version>
|
<version>78.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.sourceforge.cssparser</groupId>
|
<groupId>net.sourceforge.cssparser</groupId>
|
||||||
@@ -512,35 +449,29 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.httpcomponents.client5</groupId>
|
<groupId>org.apache.httpcomponents.client5</groupId>
|
||||||
<artifactId>httpclient5</artifactId>
|
<artifactId>httpclient5</artifactId>
|
||||||
<version>5.5</version>
|
<version>5.6</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.hakky54</groupId>
|
||||||
|
<artifactId>ayza-for-apache5</artifactId>
|
||||||
|
<version>10.0.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- add brotli support for httpclient5 -->
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.brotli</groupId>
|
<groupId>org.brotli</groupId>
|
||||||
<artifactId>dec</artifactId>
|
<artifactId>dec</artifactId>
|
||||||
<version>0.1.2</version>
|
<version>0.1.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>io.github.hakky54</groupId>
|
|
||||||
<artifactId>sslcontext-kickstart-for-apache5</artifactId>
|
|
||||||
<version>9.1.0</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- test dependencies -->
|
<!-- test dependencies -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.quarkus</groupId>
|
<groupId>io.quarkus</groupId>
|
||||||
<artifactId>quarkus-junit5-mockito</artifactId>
|
<artifactId>quarkus-junit-mockito</artifactId>
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.quarkus</groupId>
|
|
||||||
<artifactId>quarkus-jacoco</artifactId>
|
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.quarkiverse.playwright</groupId>
|
<groupId>io.quarkiverse.playwright</groupId>
|
||||||
<artifactId>quarkus-playwright</artifactId>
|
<artifactId>quarkus-playwright</artifactId>
|
||||||
<version>2.1.3</version>
|
<version>2.3.3</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM ibm-semeru-runtimes:open-21.0.8_9-jre@sha256:551139c6639d176c9591c2e2eee16b0092b97a31761c8a9202cf9fffc844d845
|
FROM ibm-semeru-runtimes:open-jdk-25.0.2_10-jre@sha256:b02e4cd184d9ece59b01129af1d0a069fa01e4f0f798f0bc4f3ff1a8391ba694
|
||||||
EXPOSE 8082
|
EXPOSE 8082
|
||||||
|
|
||||||
RUN mkdir -p /commafeed/data
|
RUN mkdir -p /commafeed/data
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM debian:12.11@sha256:b6507e340c43553136f5078284c8c68d86ec8262b1724dde73c325e8d3dcdeba
|
FROM debian:13.4@sha256:55a15a112b42be10bfc8092fcc40b6748dc236f7ef46a358d9392b339e9d60e8
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
|
|
||||||
EXPOSE 8082
|
EXPOSE 8082
|
||||||
@@ -6,7 +6,7 @@ EXPOSE 8082
|
|||||||
RUN mkdir -p /commafeed/data
|
RUN mkdir -p /commafeed/data
|
||||||
VOLUME /commafeed/data
|
VOLUME /commafeed/data
|
||||||
|
|
||||||
COPY artifacts/commafeed-*-${TARGETARCH}-runner /commafeed/application
|
COPY artifacts/commafeed-*-${TARGETARCH}-runner /commafeed/commafeed
|
||||||
WORKDIR /commafeed
|
WORKDIR /commafeed
|
||||||
|
|
||||||
CMD ["./application"]
|
CMD ["./commafeed"]
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ 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. The app will be accessible 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/data:/commafeed/data --memory 256M athou/commafeed:latest-h2`
|
||||||
|
|
||||||
### docker-compose
|
### docker-compose
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ services:
|
|||||||
image: athou/commafeed:latest-h2
|
image: athou/commafeed:latest-h2
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
- /path/to/commafeed/db:/commafeed/data
|
- ./data:/commafeed/data
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
@@ -56,7 +56,7 @@ services:
|
|||||||
POSTGRES_PASSWORD: commafeed
|
POSTGRES_PASSWORD: commafeed
|
||||||
POSTGRES_DB: commafeed
|
POSTGRES_DB: commafeed
|
||||||
volumes:
|
volumes:
|
||||||
- /path/to/commafeed/db:/var/lib/postgresql/data
|
- ./data:/var/lib/postgresql
|
||||||
```
|
```
|
||||||
|
|
||||||
CommaFeed also supports:
|
CommaFeed also supports:
|
||||||
|
|||||||
@@ -4,33 +4,35 @@ import jakarta.enterprise.event.Observes;
|
|||||||
import jakarta.inject.Singleton;
|
import jakarta.inject.Singleton;
|
||||||
|
|
||||||
import com.commafeed.backend.feed.FeedRefreshEngine;
|
import com.commafeed.backend.feed.FeedRefreshEngine;
|
||||||
import com.commafeed.backend.service.db.DatabaseStartupService;
|
|
||||||
import com.commafeed.backend.task.TaskScheduler;
|
import com.commafeed.backend.task.TaskScheduler;
|
||||||
import com.commafeed.security.password.PasswordConstraintValidator;
|
import com.commafeed.security.password.PasswordConstraintValidator;
|
||||||
|
|
||||||
import io.quarkus.runtime.ShutdownEvent;
|
import io.quarkus.runtime.ShutdownEvent;
|
||||||
import io.quarkus.runtime.StartupEvent;
|
import io.quarkus.runtime.StartupEvent;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@Singleton
|
@Singleton
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class CommaFeedApplication {
|
public class CommaFeedApplication {
|
||||||
|
|
||||||
private final DatabaseStartupService databaseStartupService;
|
|
||||||
private final FeedRefreshEngine feedRefreshEngine;
|
private final FeedRefreshEngine feedRefreshEngine;
|
||||||
private final TaskScheduler taskScheduler;
|
private final TaskScheduler taskScheduler;
|
||||||
private final CommaFeedConfiguration config;
|
private final CommaFeedConfiguration config;
|
||||||
|
|
||||||
public void start(@Observes StartupEvent ev) {
|
public void start(@Observes StartupEvent ev) {
|
||||||
PasswordConstraintValidator.setStrict(config.users().strictPasswordPolicy());
|
log.info("starting up...");
|
||||||
|
|
||||||
databaseStartupService.populateInitialData();
|
PasswordConstraintValidator.setMinimumPasswordLength(config.users().minimumPasswordLength());
|
||||||
|
|
||||||
feedRefreshEngine.start();
|
feedRefreshEngine.start();
|
||||||
taskScheduler.start();
|
taskScheduler.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stop(@Observes ShutdownEvent ev) {
|
public void stop(@Observes ShutdownEvent ev) {
|
||||||
|
log.info("shutting down...");
|
||||||
|
|
||||||
feedRefreshEngine.stop();
|
feedRefreshEngine.stop();
|
||||||
taskScheduler.stop();
|
taskScheduler.stop();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,12 @@ public interface CommaFeedConfiguration {
|
|||||||
@ConfigDocSection
|
@ConfigDocSection
|
||||||
FeedRefresh feedRefresh();
|
FeedRefresh feedRefresh();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push notification settings.
|
||||||
|
*/
|
||||||
|
@ConfigDocSection
|
||||||
|
PushNotifications pushNotifications();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Database settings.
|
* Database settings.
|
||||||
*/
|
*/
|
||||||
@@ -86,6 +92,12 @@ public interface CommaFeedConfiguration {
|
|||||||
@ConfigDocSection
|
@ConfigDocSection
|
||||||
Websocket websocket();
|
Websocket websocket();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Duration to wait for the feed refresh engine and the task scheduler to stop when the application is shutting down.
|
||||||
|
*/
|
||||||
|
@WithDefault("2s")
|
||||||
|
Duration shutdownTimeout();
|
||||||
|
|
||||||
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.
|
||||||
@@ -138,10 +150,9 @@ public interface CommaFeedConfiguration {
|
|||||||
* Prevent access to local addresses to mitigate server-side request forgery (SSRF) attacks, which could potentially expose internal
|
* Prevent access to local addresses to mitigate server-side request forgery (SSRF) attacks, which could potentially expose internal
|
||||||
* resources.
|
* 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
|
* You may want to enable this if you host a public instance of CommaFeed with registrations open.
|
||||||
* your CommaFeed instance.
|
|
||||||
*/
|
*/
|
||||||
@WithDefault("true")
|
@WithDefault("false")
|
||||||
boolean blockLocalAddresses();
|
boolean blockLocalAddresses();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -242,6 +253,28 @@ public interface CommaFeedConfiguration {
|
|||||||
Duration forceRefreshCooldownDuration();
|
Duration forceRefreshCooldownDuration();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface PushNotifications {
|
||||||
|
/**
|
||||||
|
* Whether to enable push notifications to notify users of new entries in their feeds.
|
||||||
|
*/
|
||||||
|
@WithDefault("true")
|
||||||
|
boolean enabled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Amount of threads used to send external notifications about new entries.
|
||||||
|
*/
|
||||||
|
@Min(1)
|
||||||
|
@WithDefault("5")
|
||||||
|
int threads();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum amount of notifications that can be queued before new notifications are discarded.
|
||||||
|
*/
|
||||||
|
@Min(1)
|
||||||
|
@WithDefault("100")
|
||||||
|
int queueCapacity();
|
||||||
|
}
|
||||||
|
|
||||||
interface FeedRefreshErrorHandling {
|
interface FeedRefreshErrorHandling {
|
||||||
/**
|
/**
|
||||||
* Number of retries before backoff is applied.
|
* Number of retries before backoff is applied.
|
||||||
@@ -312,6 +345,12 @@ public interface CommaFeedConfiguration {
|
|||||||
@WithDefault("100")
|
@WithDefault("100")
|
||||||
int batchSize();
|
int batchSize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to keep starred entries when cleaning up old entries.
|
||||||
|
*/
|
||||||
|
@WithDefault("true")
|
||||||
|
boolean keepStarredEntries();
|
||||||
|
|
||||||
default Instant statusesInstantThreshold() {
|
default Instant statusesInstantThreshold() {
|
||||||
return statusesMaxAge().toMillis() > 0 ? Instant.now().minus(statusesMaxAge()) : null;
|
return statusesMaxAge().toMillis() > 0 ? Instant.now().minus(statusesMaxAge()) : null;
|
||||||
}
|
}
|
||||||
@@ -326,10 +365,16 @@ public interface CommaFeedConfiguration {
|
|||||||
boolean allowRegistrations();
|
boolean allowRegistrations();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to enable strict password validation (1 uppercase char, 1 lowercase char, 1 digit, 1 special char).
|
* Minimum password length for user accounts.
|
||||||
*/
|
*/
|
||||||
@WithDefault("true")
|
@WithDefault("4")
|
||||||
boolean strictPasswordPolicy();
|
int minimumPasswordLength();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether an email address is required when creating a user account.
|
||||||
|
*/
|
||||||
|
@WithDefault("false")
|
||||||
|
boolean emailAddressRequired();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to create a demo account the first time the app starts.
|
* Whether to create a demo account the first time the app starts.
|
||||||
|
|||||||
@@ -4,6 +4,5 @@ import lombok.experimental.UtilityClass;
|
|||||||
|
|
||||||
@UtilityClass
|
@UtilityClass
|
||||||
public class CommaFeedConstants {
|
public class CommaFeedConstants {
|
||||||
public static final String USERNAME_ADMIN = "admin";
|
|
||||||
public static final String USERNAME_DEMO = "demo";
|
public static final String USERNAME_DEMO = "demo";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,16 @@ package com.commafeed;
|
|||||||
|
|
||||||
import jakarta.annotation.Priority;
|
import jakarta.annotation.Priority;
|
||||||
import jakarta.validation.ValidationException;
|
import jakarta.validation.ValidationException;
|
||||||
|
import jakarta.ws.rs.core.NewCookie;
|
||||||
import jakarta.ws.rs.ext.Provider;
|
import jakarta.ws.rs.ext.Provider;
|
||||||
|
|
||||||
import org.jboss.resteasy.reactive.RestResponse;
|
import org.jboss.resteasy.reactive.RestResponse;
|
||||||
|
import org.jboss.resteasy.reactive.RestResponse.ResponseBuilder;
|
||||||
import org.jboss.resteasy.reactive.RestResponse.Status;
|
import org.jboss.resteasy.reactive.RestResponse.Status;
|
||||||
import org.jboss.resteasy.reactive.server.ServerExceptionMapper;
|
import org.jboss.resteasy.reactive.server.ServerExceptionMapper;
|
||||||
|
|
||||||
|
import com.commafeed.security.CookieService;
|
||||||
|
|
||||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||||
import io.quarkus.security.AuthenticationFailedException;
|
import io.quarkus.security.AuthenticationFailedException;
|
||||||
import io.quarkus.security.UnauthorizedException;
|
import io.quarkus.security.UnauthorizedException;
|
||||||
@@ -18,17 +22,18 @@ import lombok.RequiredArgsConstructor;
|
|||||||
@Priority(1)
|
@Priority(1)
|
||||||
public class ExceptionMappers {
|
public class ExceptionMappers {
|
||||||
|
|
||||||
|
private final CookieService cookieService;
|
||||||
private final CommaFeedConfiguration config;
|
private final CommaFeedConfiguration config;
|
||||||
|
|
||||||
@ServerExceptionMapper(UnauthorizedException.class)
|
@ServerExceptionMapper(UnauthorizedException.class)
|
||||||
public RestResponse<UnauthorizedResponse> unauthorized(UnauthorizedException e) {
|
public RestResponse<UnauthorizedResponse> unauthorized(UnauthorizedException e) {
|
||||||
return RestResponse.status(RestResponse.Status.UNAUTHORIZED,
|
return RestResponse.status(Status.UNAUTHORIZED, new UnauthorizedResponse(e.getMessage(), config.users().allowRegistrations()));
|
||||||
new UnauthorizedResponse(e.getMessage(), config.users().allowRegistrations()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ServerExceptionMapper(AuthenticationFailedException.class)
|
@ServerExceptionMapper(AuthenticationFailedException.class)
|
||||||
public RestResponse<AuthenticationFailed> authenticationFailed(AuthenticationFailedException e) {
|
public RestResponse<AuthenticationFailed> authenticationFailed(AuthenticationFailedException e) {
|
||||||
return RestResponse.status(RestResponse.Status.UNAUTHORIZED, new AuthenticationFailed(e.getMessage()));
|
NewCookie logoutCookie = cookieService.buildLogoutCookie();
|
||||||
|
return ResponseBuilder.create(Status.UNAUTHORIZED, new AuthenticationFailed(e.getMessage())).cookie(logoutCookie).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ServerExceptionMapper(ValidationException.class)
|
@ServerExceptionMapper(ValidationException.class)
|
||||||
|
|||||||
@@ -0,0 +1,166 @@
|
|||||||
|
package com.commafeed.backend;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.SequencedMap;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
|
import jakarta.inject.Singleton;
|
||||||
|
|
||||||
|
import org.apache.hc.client5.http.DnsResolver;
|
||||||
|
import org.apache.hc.client5.http.SystemDefaultDnsResolver;
|
||||||
|
import org.apache.hc.client5.http.config.ConnectionConfig;
|
||||||
|
import org.apache.hc.client5.http.config.TlsConfig;
|
||||||
|
import org.apache.hc.client5.http.entity.DeflateInputStream;
|
||||||
|
import org.apache.hc.client5.http.entity.InputStreamFactory;
|
||||||
|
import org.apache.hc.client5.http.entity.compress.ContentCoding;
|
||||||
|
import org.apache.hc.client5.http.impl.DefaultRedirectStrategy;
|
||||||
|
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||||
|
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
|
||||||
|
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
|
||||||
|
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
|
||||||
|
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
|
||||||
|
import org.apache.hc.client5.http.protocol.RedirectStrategy;
|
||||||
|
import org.apache.hc.core5.http.Header;
|
||||||
|
import org.apache.hc.core5.http.HttpException;
|
||||||
|
import org.apache.hc.core5.http.HttpRequest;
|
||||||
|
import org.apache.hc.core5.http.HttpResponse;
|
||||||
|
import org.apache.hc.core5.http.message.BasicHeader;
|
||||||
|
import org.apache.hc.core5.http.protocol.HttpContext;
|
||||||
|
import org.apache.hc.core5.util.TimeValue;
|
||||||
|
import org.apache.hc.core5.util.Timeout;
|
||||||
|
import org.brotli.dec.BrotliInputStream;
|
||||||
|
|
||||||
|
import com.commafeed.CommaFeedConfiguration;
|
||||||
|
import com.commafeed.CommaFeedVersion;
|
||||||
|
import com.google.common.net.HttpHeaders;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import nl.altindag.ssl.SSLFactory;
|
||||||
|
import nl.altindag.ssl.apache5.util.Apache5SslUtils;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class HttpClientFactory {
|
||||||
|
|
||||||
|
private static final DnsResolver DNS_RESOLVER = SystemDefaultDnsResolver.INSTANCE;
|
||||||
|
|
||||||
|
private final CommaFeedConfiguration config;
|
||||||
|
private final CommaFeedVersion version;
|
||||||
|
|
||||||
|
public CloseableHttpClient newClient(int poolSize) {
|
||||||
|
PoolingHttpClientConnectionManager connectionManager = newConnectionManager(config, poolSize);
|
||||||
|
String userAgent = config.httpClient()
|
||||||
|
.userAgent()
|
||||||
|
.orElseGet(() -> String.format("CommaFeed/%s (https://github.com/Athou/commafeed)", version.getVersion()));
|
||||||
|
return newClient(config, connectionManager, userAgent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CloseableHttpClient newClient(CommaFeedConfiguration config, HttpClientConnectionManager connectionManager, String userAgent) {
|
||||||
|
List<Header> headers = new ArrayList<>();
|
||||||
|
headers.add(new BasicHeader(HttpHeaders.ACCEPT_LANGUAGE, "en"));
|
||||||
|
headers.add(new BasicHeader(HttpHeaders.PRAGMA, "No-cache"));
|
||||||
|
headers.add(new BasicHeader(HttpHeaders.CACHE_CONTROL, "no-cache"));
|
||||||
|
|
||||||
|
SequencedMap<String, InputStreamFactory> contentDecoderMap = new LinkedHashMap<>();
|
||||||
|
contentDecoderMap.put(ContentCoding.GZIP.token(), GZIPInputStream::new);
|
||||||
|
contentDecoderMap.put(ContentCoding.DEFLATE.token(), DeflateInputStream::new);
|
||||||
|
contentDecoderMap.put(ContentCoding.BROTLI.token(), BrotliInputStream::new);
|
||||||
|
|
||||||
|
RedirectStrategy redirectStrategy = config.httpClient().blockLocalAddresses()
|
||||||
|
? new BlockLocalAddressesRedirectStrategy(DNS_RESOLVER)
|
||||||
|
: new DefaultRedirectStrategy();
|
||||||
|
|
||||||
|
return HttpClientBuilder.create()
|
||||||
|
.useSystemProperties()
|
||||||
|
.disableAutomaticRetries()
|
||||||
|
.disableCookieManagement()
|
||||||
|
.setUserAgent(userAgent)
|
||||||
|
.setDefaultHeaders(headers)
|
||||||
|
.setConnectionManager(connectionManager)
|
||||||
|
.evictExpiredConnections()
|
||||||
|
.evictIdleConnections(TimeValue.of(config.httpClient().idleConnectionsEvictionInterval()))
|
||||||
|
.setContentDecoderRegistry(new LinkedHashMap<>(contentDecoderMap))
|
||||||
|
.setRedirectStrategy(redirectStrategy)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private PoolingHttpClientConnectionManager newConnectionManager(CommaFeedConfiguration config, int poolSize) {
|
||||||
|
SSLFactory sslFactory = SSLFactory.builder().withUnsafeTrustMaterial().withUnsafeHostnameVerifier().build();
|
||||||
|
DnsResolver dnsResolver = config.httpClient().blockLocalAddresses() ? new BlockLocalAddressesDnsResolver(DNS_RESOLVER)
|
||||||
|
: DNS_RESOLVER;
|
||||||
|
|
||||||
|
return PoolingHttpClientConnectionManagerBuilder.create()
|
||||||
|
.setTlsSocketStrategy(Apache5SslUtils.toTlsSocketStrategy(sslFactory))
|
||||||
|
.setDefaultConnectionConfig(ConnectionConfig.custom()
|
||||||
|
.setConnectTimeout(Timeout.of(config.httpClient().connectTimeout()))
|
||||||
|
.setSocketTimeout(Timeout.of(config.httpClient().socketTimeout()))
|
||||||
|
.setTimeToLive(Timeout.of(config.httpClient().connectionTimeToLive()))
|
||||||
|
.build())
|
||||||
|
.setDefaultTlsConfig(TlsConfig.custom().setHandshakeTimeout(Timeout.of(config.httpClient().sslHandshakeTimeout())).build())
|
||||||
|
.setMaxConnPerRoute(poolSize)
|
||||||
|
.setMaxConnTotal(poolSize)
|
||||||
|
.setDnsResolver(dnsResolver)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isLocalAddress(InetAddress address) {
|
||||||
|
return address.isSiteLocalAddress() || address.isAnyLocalAddress() || address.isLinkLocalAddress() || address.isLoopbackAddress()
|
||||||
|
|| address.isMulticastAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
private record BlockLocalAddressesDnsResolver(DnsResolver delegate) implements DnsResolver {
|
||||||
|
@Override
|
||||||
|
public InetAddress[] resolve(String host) throws UnknownHostException {
|
||||||
|
InetAddress[] addresses = delegate.resolve(host);
|
||||||
|
for (InetAddress addr : addresses) {
|
||||||
|
if (isLocalAddress(addr)) {
|
||||||
|
throw new UnknownHostException("Access to local address blocked: " + addr.getHostAddress());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return addresses;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String resolveCanonicalHostname(String host) throws UnknownHostException {
|
||||||
|
return delegate.resolveCanonicalHostname(host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
private static class BlockLocalAddressesRedirectStrategy extends DefaultRedirectStrategy {
|
||||||
|
|
||||||
|
private final DnsResolver delegate;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URI getLocationURI(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException {
|
||||||
|
URI redirectUri = super.getLocationURI(request, response, context);
|
||||||
|
|
||||||
|
String host = redirectUri.getHost();
|
||||||
|
if (host == null) {
|
||||||
|
throw new HttpException("Redirect URI does not have a host: " + redirectUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
InetAddress[] addresses;
|
||||||
|
try {
|
||||||
|
addresses = delegate.resolve(host);
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
throw new HttpException("Unknown host: " + host);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (InetAddress addr : addresses) {
|
||||||
|
if (isLocalAddress(addr)) {
|
||||||
|
throw new HttpException("Access to local address blocked: " + addr.getHostAddress());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirectUri;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,51 +2,34 @@ 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.URI;
|
import java.net.URI;
|
||||||
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.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 jakarta.inject.Singleton;
|
import jakarta.inject.Singleton;
|
||||||
import jakarta.ws.rs.core.CacheControl;
|
import jakarta.ws.rs.core.CacheControl;
|
||||||
|
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.hc.client5.http.DnsResolver;
|
|
||||||
import org.apache.hc.client5.http.SystemDefaultDnsResolver;
|
|
||||||
import org.apache.hc.client5.http.config.ConnectionConfig;
|
|
||||||
import org.apache.hc.client5.http.config.RequestConfig;
|
import org.apache.hc.client5.http.config.RequestConfig;
|
||||||
import org.apache.hc.client5.http.config.TlsConfig;
|
|
||||||
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||||
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
|
|
||||||
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
|
|
||||||
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
|
|
||||||
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
|
|
||||||
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
import org.apache.hc.client5.http.protocol.HttpClientContext;
|
||||||
import org.apache.hc.client5.http.protocol.RedirectLocations;
|
import org.apache.hc.client5.http.protocol.RedirectLocations;
|
||||||
import org.apache.hc.client5.http.utils.DateUtils;
|
import org.apache.hc.client5.http.utils.DateUtils;
|
||||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||||
import org.apache.hc.core5.http.Header;
|
|
||||||
import org.apache.hc.core5.http.HttpEntity;
|
import org.apache.hc.core5.http.HttpEntity;
|
||||||
import org.apache.hc.core5.http.HttpStatus;
|
import org.apache.hc.core5.http.HttpStatus;
|
||||||
import org.apache.hc.core5.http.NameValuePair;
|
import org.apache.hc.core5.http.NameValuePair;
|
||||||
import org.apache.hc.core5.http.io.support.ClassicRequestBuilder;
|
import org.apache.hc.core5.http.io.support.ClassicRequestBuilder;
|
||||||
import org.apache.hc.core5.http.message.BasicHeader;
|
|
||||||
import org.apache.hc.core5.util.TimeValue;
|
|
||||||
import org.apache.hc.core5.util.Timeout;
|
import org.apache.hc.core5.util.Timeout;
|
||||||
import org.jboss.resteasy.reactive.common.headers.CacheControlDelegate;
|
import org.jboss.resteasy.reactive.common.headers.CacheControlDelegate;
|
||||||
|
|
||||||
import com.codahale.metrics.MetricRegistry;
|
import com.codahale.metrics.MetricRegistry;
|
||||||
import com.commafeed.CommaFeedConfiguration;
|
import com.commafeed.CommaFeedConfiguration;
|
||||||
import com.commafeed.CommaFeedConfiguration.HttpClientCache;
|
import com.commafeed.CommaFeedConfiguration.HttpClientCache;
|
||||||
import com.commafeed.CommaFeedVersion;
|
|
||||||
import com.google.common.cache.Cache;
|
import com.google.common.cache.Cache;
|
||||||
import com.google.common.cache.CacheBuilder;
|
import com.google.common.cache.CacheBuilder;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
@@ -58,10 +41,7 @@ import lombok.EqualsAndHashCode;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Lombok;
|
import lombok.Lombok;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.Value;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
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
|
||||||
@@ -69,49 +49,32 @@ import nl.altindag.ssl.apache5.util.Apache5SslUtils;
|
|||||||
@Singleton
|
@Singleton
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class HttpGetter {
|
public class HttpGetter {
|
||||||
private static final DnsResolver DNS_RESOLVER = SystemDefaultDnsResolver.INSTANCE;
|
|
||||||
|
|
||||||
private final CommaFeedConfiguration config;
|
private final CommaFeedConfiguration config;
|
||||||
private final InstantSource instantSource;
|
private final InstantSource instantSource;
|
||||||
private final CloseableHttpClient client;
|
private final CloseableHttpClient client;
|
||||||
private final Cache<HttpRequest, HttpResponse> cache;
|
private final Cache<HttpRequest, HttpResponse> cache;
|
||||||
|
|
||||||
public HttpGetter(CommaFeedConfiguration config, InstantSource instantSource, CommaFeedVersion version, MetricRegistry metrics) {
|
public HttpGetter(CommaFeedConfiguration config, InstantSource instantSource, HttpClientFactory httpClientFactory,
|
||||||
|
MetricRegistry metrics) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.instantSource = instantSource;
|
this.instantSource = instantSource;
|
||||||
|
this.client = httpClientFactory.newClient(config.feedRefresh().httpThreads());
|
||||||
PoolingHttpClientConnectionManager connectionManager = newConnectionManager(config);
|
|
||||||
String userAgent = config.httpClient()
|
|
||||||
.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.cache = newCache(config);
|
||||||
|
|
||||||
metrics.registerGauge(MetricRegistry.name(getClass(), "pool", "max"), () -> connectionManager.getTotalStats().getMax());
|
|
||||||
metrics.registerGauge(MetricRegistry.name(getClass(), "pool", "size"),
|
|
||||||
() -> connectionManager.getTotalStats().getAvailable() + connectionManager.getTotalStats().getLeased());
|
|
||||||
metrics.registerGauge(MetricRegistry.name(getClass(), "pool", "leased"), () -> connectionManager.getTotalStats().getLeased());
|
|
||||||
metrics.registerGauge(MetricRegistry.name(getClass(), "pool", "pending"), () -> connectionManager.getTotalStats().getPending());
|
|
||||||
metrics.registerGauge(MetricRegistry.name(getClass(), "cache", "size"), () -> cache == null ? 0 : cache.size());
|
metrics.registerGauge(MetricRegistry.name(getClass(), "cache", "size"), () -> cache == null ? 0 : cache.size());
|
||||||
metrics.registerGauge(MetricRegistry.name(getClass(), "cache", "memoryUsage"),
|
metrics.registerGauge(MetricRegistry.name(getClass(), "cache", "memoryUsage"),
|
||||||
() -> cache == null ? 0 : cache.asMap().values().stream().mapToInt(e -> ArrayUtils.getLength(e.content)).sum());
|
() -> cache == null ? 0 : cache.asMap().values().stream().mapToInt(e -> ArrayUtils.getLength(e.content)).sum());
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpResult get(String url)
|
public HttpResult get(String url) throws IOException, NotModifiedException, TooManyRequestsException, SchemeNotAllowedException {
|
||||||
throws IOException, NotModifiedException, TooManyRequestsException, SchemeNotAllowedException, HostNotAllowedException {
|
|
||||||
return get(HttpRequest.builder(url).build());
|
return get(HttpRequest.builder(url).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpResult get(HttpRequest request)
|
public HttpResult get(HttpRequest request)
|
||||||
throws IOException, NotModifiedException, TooManyRequestsException, SchemeNotAllowedException, HostNotAllowedException {
|
throws IOException, NotModifiedException, TooManyRequestsException, SchemeNotAllowedException {
|
||||||
URI uri = URI.create(request.getUrl());
|
URI uri = URI.create(request.getUrl());
|
||||||
ensureHttpScheme(uri.getScheme());
|
ensureHttpScheme(uri.getScheme());
|
||||||
|
|
||||||
if (config.httpClient().blockLocalAddresses()) {
|
|
||||||
ensurePublicAddress(uri.getHost());
|
|
||||||
}
|
|
||||||
|
|
||||||
final HttpResponse response;
|
final HttpResponse response;
|
||||||
if (cache == null) {
|
if (cache == null) {
|
||||||
response = invoke(request);
|
response = invoke(request);
|
||||||
@@ -127,9 +90,9 @@ public class HttpGetter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int code = response.getCode();
|
int code = response.code();
|
||||||
if (code == HttpStatus.SC_TOO_MANY_REQUESTS || code == HttpStatus.SC_SERVICE_UNAVAILABLE && response.getRetryAfter() != null) {
|
if (code == HttpStatus.SC_TOO_MANY_REQUESTS || code == HttpStatus.SC_SERVICE_UNAVAILABLE && response.retryAfter() != null) {
|
||||||
throw new TooManyRequestsException(response.getRetryAfter());
|
throw new TooManyRequestsException(response.retryAfter());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (code == HttpStatus.SC_NOT_MODIFIED) {
|
if (code == HttpStatus.SC_NOT_MODIFIED) {
|
||||||
@@ -140,16 +103,16 @@ public class HttpGetter {
|
|||||||
throw new HttpResponseException(code, "Server returned HTTP error code " + code);
|
throw new HttpResponseException(code, "Server returned HTTP error code " + code);
|
||||||
}
|
}
|
||||||
|
|
||||||
String lastModifiedHeader = response.getLastModifiedHeader();
|
String lastModifiedHeader = response.lastModifiedHeader();
|
||||||
String eTagHeader = response.getETagHeader();
|
String eTagHeader = response.eTagHeader();
|
||||||
|
|
||||||
Duration validFor = Optional.ofNullable(response.getCacheControl())
|
Duration validFor = Optional.ofNullable(response.cacheControl())
|
||||||
.filter(cc -> cc.getMaxAge() >= 0)
|
.filter(cc -> cc.getMaxAge() >= 0)
|
||||||
.map(cc -> Duration.ofSeconds(cc.getMaxAge()))
|
.map(cc -> Duration.ofSeconds(cc.getMaxAge()))
|
||||||
.orElse(Duration.ZERO);
|
.orElse(Duration.ZERO);
|
||||||
|
|
||||||
return new HttpResult(response.getContent(), response.getContentType(), lastModifiedHeader, eTagHeader,
|
return new HttpResult(response.content(), response.contentType(), lastModifiedHeader, eTagHeader, response.urlAfterRedirect(),
|
||||||
response.getUrlAfterRedirect(), validFor);
|
validFor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureHttpScheme(String scheme) throws SchemeNotAllowedException {
|
private void ensureHttpScheme(String scheme) throws SchemeNotAllowedException {
|
||||||
@@ -158,22 +121,6 @@ public class HttpGetter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensurePublicAddress(String host) throws HostNotAllowedException, UnknownHostException {
|
|
||||||
if (host == null) {
|
|
||||||
throw new HostNotAllowedException(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
InetAddress[] addresses = DNS_RESOLVER.resolve(host);
|
|
||||||
if (Stream.of(addresses).anyMatch(this::isPrivateAddress)) {
|
|
||||||
throw new HostNotAllowedException(host);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isPrivateAddress(InetAddress address) {
|
|
||||||
return address.isSiteLocalAddress() || address.isAnyLocalAddress() || address.isLinkLocalAddress() || address.isLoopbackAddress()
|
|
||||||
|| address.isMulticastAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
private HttpResponse invoke(HttpRequest request) throws IOException {
|
private HttpResponse invoke(HttpRequest request) throws IOException {
|
||||||
log.debug("fetching {}", request.getUrl());
|
log.debug("fetching {}", request.getUrl());
|
||||||
|
|
||||||
@@ -254,52 +201,14 @@ public class HttpGetter {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] bytes = ByteStreams.limit(input, maxBytes).readAllBytes();
|
byte[] bytes = ByteStreams.limit(input, maxBytes + 1).readAllBytes();
|
||||||
if (bytes.length == maxBytes) {
|
if (bytes.length > maxBytes) {
|
||||||
throw new IOException("Response size exceeds the maximum allowed size (%s bytes)".formatted(maxBytes));
|
throw new IOException("Response size exceeds the maximum allowed size (%s bytes)".formatted(maxBytes));
|
||||||
}
|
}
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private PoolingHttpClientConnectionManager newConnectionManager(CommaFeedConfiguration config) {
|
|
||||||
SSLFactory sslFactory = SSLFactory.builder().withUnsafeTrustMaterial().withUnsafeHostnameVerifier().build();
|
|
||||||
|
|
||||||
int poolSize = config.feedRefresh().httpThreads();
|
|
||||||
return PoolingHttpClientConnectionManagerBuilder.create()
|
|
||||||
.setTlsSocketStrategy(Apache5SslUtils.toTlsSocketStrategy(sslFactory))
|
|
||||||
.setDefaultConnectionConfig(ConnectionConfig.custom()
|
|
||||||
.setConnectTimeout(Timeout.of(config.httpClient().connectTimeout()))
|
|
||||||
.setSocketTimeout(Timeout.of(config.httpClient().socketTimeout()))
|
|
||||||
.setTimeToLive(Timeout.of(config.httpClient().connectionTimeToLive()))
|
|
||||||
.build())
|
|
||||||
.setDefaultTlsConfig(TlsConfig.custom().setHandshakeTimeout(Timeout.of(config.httpClient().sslHandshakeTimeout())).build())
|
|
||||||
.setMaxConnPerRoute(poolSize)
|
|
||||||
.setMaxConnTotal(poolSize)
|
|
||||||
.setDnsResolver(DNS_RESOLVER)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static CloseableHttpClient newClient(HttpClientConnectionManager connectionManager, String userAgent,
|
|
||||||
Duration idleConnectionsEvictionInterval) {
|
|
||||||
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"));
|
|
||||||
|
|
||||||
return HttpClientBuilder.create()
|
|
||||||
.useSystemProperties()
|
|
||||||
.disableAutomaticRetries()
|
|
||||||
.disableCookieManagement()
|
|
||||||
.setUserAgent(userAgent)
|
|
||||||
.setDefaultHeaders(headers)
|
|
||||||
.setConnectionManager(connectionManager)
|
|
||||||
.evictExpiredConnections()
|
|
||||||
.evictIdleConnections(TimeValue.of(idleConnectionsEvictionInterval))
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Cache<HttpRequest, HttpResponse> newCache(CommaFeedConfiguration config) {
|
private static Cache<HttpRequest, HttpResponse> newCache(CommaFeedConfiguration config) {
|
||||||
HttpClientCache cacheConfig = config.httpClient().cache();
|
HttpClientCache cacheConfig = config.httpClient().cache();
|
||||||
if (!cacheConfig.enabled()) {
|
if (!cacheConfig.enabled()) {
|
||||||
@@ -307,7 +216,7 @@ public class HttpGetter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return CacheBuilder.newBuilder()
|
return CacheBuilder.newBuilder()
|
||||||
.weigher((HttpRequest key, HttpResponse value) -> value.getContent() != null ? value.getContent().length : 0)
|
.weigher((HttpRequest key, HttpResponse value) -> value.content() != null ? value.content().length : 0)
|
||||||
.maximumWeight(cacheConfig.maximumMemorySize().asLongValue())
|
.maximumWeight(cacheConfig.maximumMemorySize().asLongValue())
|
||||||
.expireAfterWrite(cacheConfig.expiration())
|
.expireAfterWrite(cacheConfig.expiration())
|
||||||
.build();
|
.build();
|
||||||
@@ -321,14 +230,6 @@ public class HttpGetter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class HostNotAllowedException extends Exception {
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public HostNotAllowedException(String host) {
|
|
||||||
super("Host not allowed: " + host);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public static class NotModifiedException extends Exception {
|
public static class NotModifiedException extends Exception {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
@@ -398,26 +299,12 @@ public class HttpGetter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Value
|
private record HttpResponse(int code, String lastModifiedHeader, String eTagHeader, CacheControl cacheControl, Instant retryAfter,
|
||||||
private static class HttpResponse {
|
byte[] content, String contentType, String urlAfterRedirect) {
|
||||||
int code;
|
|
||||||
String lastModifiedHeader;
|
|
||||||
String eTagHeader;
|
|
||||||
CacheControl cacheControl;
|
|
||||||
Instant retryAfter;
|
|
||||||
byte[] content;
|
|
||||||
String contentType;
|
|
||||||
String urlAfterRedirect;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Value
|
public record HttpResult(byte[] content, String contentType, String lastModifiedSince, String eTag, String urlAfterRedirect,
|
||||||
public static class HttpResult {
|
Duration validFor) {
|
||||||
byte[] content;
|
|
||||||
String contentType;
|
|
||||||
String lastModifiedSince;
|
|
||||||
String eTag;
|
|
||||||
String urlAfterRedirect;
|
|
||||||
Duration validFor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,10 @@ import org.netpreserve.urlcanon.Canonicalizer;
|
|||||||
import org.netpreserve.urlcanon.ParsedUrl;
|
import org.netpreserve.urlcanon.ParsedUrl;
|
||||||
|
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@UtilityClass
|
@UtilityClass
|
||||||
|
@Slf4j
|
||||||
public class Urls {
|
public class Urls {
|
||||||
|
|
||||||
private static final String ESCAPED_QUESTION_MARK = Pattern.quote("?");
|
private static final String ESCAPED_QUESTION_MARK = Pattern.quote("?");
|
||||||
@@ -42,10 +44,19 @@ public class Urls {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return URI.create(baseUrl).resolve(relativeUrl).toString();
|
try {
|
||||||
|
return URI.create(baseUrl).resolve(relativeUrl).toString();
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
log.debug("Unable to create absolute url from relative url: {} base: {}", relativeUrl, baseUrl, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String removeTrailingSlash(String url) {
|
public static String removeTrailingSlash(String url) {
|
||||||
|
if (url == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (url.endsWith("/")) {
|
if (url.endsWith("/")) {
|
||||||
url = url.substring(0, url.length() - 1);
|
url = url.substring(0, url.length() - 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,7 @@ import com.commafeed.backend.model.FeedEntry;
|
|||||||
import com.commafeed.backend.model.QFeedEntry;
|
import com.commafeed.backend.model.QFeedEntry;
|
||||||
import com.querydsl.core.Tuple;
|
import com.querydsl.core.Tuple;
|
||||||
import com.querydsl.core.types.dsl.NumberExpression;
|
import com.querydsl.core.types.dsl.NumberExpression;
|
||||||
|
import com.querydsl.jpa.impl.JPAQuery;
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class FeedEntryDAO extends GenericDAO<FeedEntry> {
|
public class FeedEntryDAO extends GenericDAO<FeedEntry> {
|
||||||
@@ -28,15 +26,21 @@ public class FeedEntryDAO extends GenericDAO<FeedEntry> {
|
|||||||
return query().select(ENTRY).from(ENTRY).where(ENTRY.guidHash.eq(guidHash), ENTRY.feed.eq(feed)).limit(1).fetchOne();
|
return query().select(ENTRY).from(ENTRY).where(ENTRY.guidHash.eq(guidHash), ENTRY.feed.eq(feed)).limit(1).fetchOne();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<FeedCapacity> findFeedsExceedingCapacity(long maxCapacity, long max) {
|
public List<FeedCapacity> findFeedsExceedingCapacity(long maxCapacity, long max, boolean keepStarredEntries) {
|
||||||
NumberExpression<Long> count = ENTRY.id.count();
|
NumberExpression<Long> count = ENTRY.id.count();
|
||||||
List<Tuple> tuples = query().select(ENTRY.feed.id, count)
|
JPAQuery<Tuple> query = query().select(ENTRY.feed.id, count).from(ENTRY);
|
||||||
.from(ENTRY)
|
|
||||||
.groupBy(ENTRY.feed)
|
if (keepStarredEntries) {
|
||||||
|
query.where(Predicates.isNotStarred(ENTRY));
|
||||||
|
}
|
||||||
|
|
||||||
|
return query.groupBy(ENTRY.feed)
|
||||||
.having(count.gt(maxCapacity))
|
.having(count.gt(maxCapacity))
|
||||||
.limit(max)
|
.limit(max)
|
||||||
.fetch();
|
.fetch()
|
||||||
return tuples.stream().map(t -> new FeedCapacity(t.get(ENTRY.feed.id), t.get(count))).toList();
|
.stream()
|
||||||
|
.map(t -> new FeedCapacity(t.get(ENTRY.feed.id), t.get(count)))
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int delete(Long feedId, long max) {
|
public int delete(Long feedId, long max) {
|
||||||
@@ -47,27 +51,32 @@ public class FeedEntryDAO extends GenericDAO<FeedEntry> {
|
|||||||
/**
|
/**
|
||||||
* Delete entries older than a certain date
|
* Delete entries older than a certain date
|
||||||
*/
|
*/
|
||||||
public int deleteEntriesOlderThan(Instant olderThan, long max) {
|
public int deleteEntriesOlderThan(Instant olderThan, long max, boolean keepStarredEntries) {
|
||||||
List<FeedEntry> list = query().selectFrom(ENTRY)
|
JPAQuery<FeedEntry> query = query().selectFrom(ENTRY)
|
||||||
.where(ENTRY.published.lt(olderThan))
|
.where(ENTRY.published.lt(olderThan))
|
||||||
.orderBy(ENTRY.published.asc())
|
.orderBy(ENTRY.published.asc())
|
||||||
.limit(max)
|
.limit(max);
|
||||||
.fetch();
|
|
||||||
return delete(list);
|
if (keepStarredEntries) {
|
||||||
|
query.where(Predicates.isNotStarred(ENTRY));
|
||||||
|
}
|
||||||
|
|
||||||
|
return delete(query.fetch());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete the oldest entries of a feed
|
* Delete the oldest entries of a feed
|
||||||
*/
|
*/
|
||||||
public int deleteOldEntries(Long feedId, long max) {
|
public int deleteOldEntries(Long feedId, long max, boolean keepStarredEntries) {
|
||||||
List<FeedEntry> list = query().selectFrom(ENTRY).where(ENTRY.feed.id.eq(feedId)).orderBy(ENTRY.published.asc()).limit(max).fetch();
|
JPAQuery<FeedEntry> query = query().selectFrom(ENTRY).where(ENTRY.feed.id.eq(feedId)).orderBy(ENTRY.published.asc()).limit(max);
|
||||||
return delete(list);
|
|
||||||
|
if (keepStarredEntries) {
|
||||||
|
query.where(Predicates.isNotStarred(ENTRY));
|
||||||
|
}
|
||||||
|
|
||||||
|
return delete(query.fetch());
|
||||||
}
|
}
|
||||||
|
|
||||||
@AllArgsConstructor
|
public record FeedCapacity(Long id, Long capacity) {
|
||||||
@Getter
|
|
||||||
public static class FeedCapacity {
|
|
||||||
private Long id;
|
|
||||||
private Long capacity;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,15 +18,19 @@ import com.commafeed.backend.model.FeedEntry;
|
|||||||
import com.commafeed.backend.model.FeedEntryStatus;
|
import com.commafeed.backend.model.FeedEntryStatus;
|
||||||
import com.commafeed.backend.model.FeedEntryTag;
|
import com.commafeed.backend.model.FeedEntryTag;
|
||||||
import com.commafeed.backend.model.FeedSubscription;
|
import com.commafeed.backend.model.FeedSubscription;
|
||||||
|
import com.commafeed.backend.model.QFeed;
|
||||||
import com.commafeed.backend.model.QFeedEntry;
|
import com.commafeed.backend.model.QFeedEntry;
|
||||||
import com.commafeed.backend.model.QFeedEntryContent;
|
import com.commafeed.backend.model.QFeedEntryContent;
|
||||||
import com.commafeed.backend.model.QFeedEntryStatus;
|
import com.commafeed.backend.model.QFeedEntryStatus;
|
||||||
import com.commafeed.backend.model.QFeedEntryTag;
|
import com.commafeed.backend.model.QFeedEntryTag;
|
||||||
|
import com.commafeed.backend.model.QFeedSubscription;
|
||||||
import com.commafeed.backend.model.User;
|
import com.commafeed.backend.model.User;
|
||||||
import com.commafeed.backend.model.UserSettings.ReadingOrder;
|
import com.commafeed.backend.model.UserSettings.ReadingOrder;
|
||||||
import com.commafeed.frontend.model.UnreadCount;
|
import com.commafeed.frontend.model.UnreadCount;
|
||||||
import com.querydsl.core.BooleanBuilder;
|
import com.querydsl.core.BooleanBuilder;
|
||||||
import com.querydsl.core.Tuple;
|
import com.querydsl.core.Tuple;
|
||||||
|
import com.querydsl.core.types.dsl.Expressions;
|
||||||
|
import com.querydsl.core.types.dsl.NumberExpression;
|
||||||
import com.querydsl.jpa.impl.JPAQuery;
|
import com.querydsl.jpa.impl.JPAQuery;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@@ -34,8 +38,10 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
|||||||
|
|
||||||
private static final QFeedEntryStatus STATUS = QFeedEntryStatus.feedEntryStatus;
|
private static final QFeedEntryStatus STATUS = QFeedEntryStatus.feedEntryStatus;
|
||||||
private static final QFeedEntry ENTRY = QFeedEntry.feedEntry;
|
private static final QFeedEntry ENTRY = QFeedEntry.feedEntry;
|
||||||
|
private static final QFeed FEED = QFeed.feed;
|
||||||
private static final QFeedEntryContent CONTENT = QFeedEntryContent.feedEntryContent;
|
private static final QFeedEntryContent CONTENT = QFeedEntryContent.feedEntryContent;
|
||||||
private static final QFeedEntryTag TAG = QFeedEntryTag.feedEntryTag;
|
private static final QFeedEntryTag TAG = QFeedEntryTag.feedEntryTag;
|
||||||
|
private static final QFeedSubscription SUBSCRIPTION = QFeedSubscription.feedSubscription;
|
||||||
|
|
||||||
private final FeedEntryTagDAO feedEntryTagDAO;
|
private final FeedEntryTagDAO feedEntryTagDAO;
|
||||||
private final CommaFeedConfiguration config;
|
private final CommaFeedConfiguration config;
|
||||||
@@ -129,9 +135,9 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
|||||||
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.keyword()));
|
||||||
or.or(CONTENT.title.containsIgnoreCase(keyword.getKeyword()));
|
or.or(CONTENT.title.containsIgnoreCase(keyword.keyword()));
|
||||||
if (keyword.getMode() == Mode.EXCLUDE) {
|
if (keyword.mode() == Mode.EXCLUDE) {
|
||||||
or.not();
|
or.not();
|
||||||
}
|
}
|
||||||
query.where(or);
|
query.where(or);
|
||||||
@@ -232,4 +238,58 @@ public class FeedEntryStatusDAO extends GenericDAO<FeedEntryStatus> {
|
|||||||
return deleteQuery(STATUS).where(STATUS.id.in(ids)).execute();
|
return deleteQuery(STATUS).where(STATUS.id.in(ids)).execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long autoMarkAsRead(int limit) {
|
||||||
|
Instant now = Instant.now();
|
||||||
|
|
||||||
|
BooleanBuilder where = new BooleanBuilder();
|
||||||
|
where.and(SUBSCRIPTION.autoMarkAsReadAfterDays.isNotNull());
|
||||||
|
where.and(SUBSCRIPTION.autoMarkAsReadAfterDays.gt(0));
|
||||||
|
|
||||||
|
NumberExpression<Integer> daysDiff = Expressions.numberTemplate(Integer.class, "TIMESTAMPDIFF(DAY, {0}, {1})", ENTRY.published,
|
||||||
|
now);
|
||||||
|
where.and(daysDiff.goe(SUBSCRIPTION.autoMarkAsReadAfterDays));
|
||||||
|
|
||||||
|
where.and(buildUnreadPredicate());
|
||||||
|
|
||||||
|
List<Tuple> tuples = query().select(ENTRY, STATUS, SUBSCRIPTION)
|
||||||
|
.from(ENTRY)
|
||||||
|
.join(ENTRY.feed, FEED)
|
||||||
|
.join(SUBSCRIPTION)
|
||||||
|
.on(SUBSCRIPTION.feed.eq(FEED))
|
||||||
|
.leftJoin(ENTRY.statuses, STATUS)
|
||||||
|
.on(STATUS.subscription.eq(SUBSCRIPTION))
|
||||||
|
.where(where)
|
||||||
|
.limit(limit)
|
||||||
|
.fetch();
|
||||||
|
|
||||||
|
long updated = 0;
|
||||||
|
|
||||||
|
// Update existing statuses
|
||||||
|
List<Long> statusIdsToUpdate = tuples.stream()
|
||||||
|
.map(t -> t.get(STATUS))
|
||||||
|
.filter(s -> s != null && s.getId() != null)
|
||||||
|
.map(FeedEntryStatus::getId)
|
||||||
|
.distinct()
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
if (!statusIdsToUpdate.isEmpty()) {
|
||||||
|
updated += updateQuery(STATUS).where(STATUS.id.in(statusIdsToUpdate)).set(STATUS.read, true).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert new statuses for entries without existing status
|
||||||
|
for (Tuple tuple : tuples) {
|
||||||
|
FeedEntryStatus status = tuple.get(STATUS);
|
||||||
|
if (status == null || status.getId() == null) {
|
||||||
|
FeedEntry entry = tuple.get(ENTRY);
|
||||||
|
FeedSubscription sub = tuple.get(SUBSCRIPTION);
|
||||||
|
FeedEntryStatus newStatus = new FeedEntryStatus(sub.getUser(), sub, entry);
|
||||||
|
newStatus.setRead(true);
|
||||||
|
persist(newStatus);
|
||||||
|
updated++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.commafeed.backend.dao;
|
||||||
|
|
||||||
|
import com.commafeed.backend.model.QFeedEntry;
|
||||||
|
import com.commafeed.backend.model.QFeedEntryStatus;
|
||||||
|
import com.querydsl.core.types.dsl.BooleanExpression;
|
||||||
|
import com.querydsl.jpa.JPAExpressions;
|
||||||
|
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
|
@UtilityClass
|
||||||
|
public class Predicates {
|
||||||
|
|
||||||
|
private static final QFeedEntryStatus STATUS = QFeedEntryStatus.feedEntryStatus;
|
||||||
|
|
||||||
|
public static BooleanExpression isNotStarred(QFeedEntry entry) {
|
||||||
|
return JPAExpressions.selectOne().from(STATUS).where(STATUS.entry.eq(entry).and(STATUS.starred.isTrue())).notExists();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -32,4 +32,8 @@ public class UserRoleDAO extends GenericDAO<UserRole> {
|
|||||||
public Set<Role> findRoles(User user) {
|
public Set<Role> findRoles(User user) {
|
||||||
return findAll(user).stream().map(UserRole::getRole).collect(Collectors.toSet());
|
return findAll(user).stream().map(UserRole::getRole).collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long countAdmins() {
|
||||||
|
return query().select(ROLE.count()).from(ROLE).where(ROLE.role.eq(Role.ADMIN)).fetchOne();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,11 +71,10 @@ public class DefaultFaviconFetcher extends AbstractFaviconFetcher {
|
|||||||
url = Urls.removeTrailingSlash(url) + "/favicon.ico";
|
url = Urls.removeTrailingSlash(url) + "/favicon.ico";
|
||||||
log.debug("getting root icon at {}", url);
|
log.debug("getting root icon at {}", url);
|
||||||
HttpResult result = getter.get(url);
|
HttpResult result = getter.get(url);
|
||||||
bytes = result.getContent();
|
bytes = result.content();
|
||||||
contentType = result.getContentType();
|
contentType = result.contentType();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.debug("Failed to retrieve iconAtRoot for url {}: ", url);
|
log.debug("Failed to retrieve iconAtRoot for url {}: ", url, e);
|
||||||
log.trace("Failed to retrieve iconAtRoot for url {}: ", url, e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isValidIconResponse(bytes, contentType)) {
|
if (!isValidIconResponse(bytes, contentType)) {
|
||||||
@@ -89,10 +88,9 @@ public class DefaultFaviconFetcher extends AbstractFaviconFetcher {
|
|||||||
Document doc;
|
Document doc;
|
||||||
try {
|
try {
|
||||||
HttpResult result = getter.get(url);
|
HttpResult result = getter.get(url);
|
||||||
doc = Jsoup.parse(new String(result.getContent()), url);
|
doc = Jsoup.parse(new String(result.content()), url);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.debug("Failed to retrieve page to find icon");
|
log.debug("Failed to retrieve page to find icon", e);
|
||||||
log.trace("Failed to retrieve page to find icon", e);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +101,7 @@ public class DefaultFaviconFetcher extends AbstractFaviconFetcher {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String href = icons.get(0).attr("abs:href");
|
String href = icons.getFirst().attr("abs:href");
|
||||||
if (StringUtils.isBlank(href)) {
|
if (StringUtils.isBlank(href)) {
|
||||||
log.debug("No icon found in page");
|
log.debug("No icon found in page");
|
||||||
return null;
|
return null;
|
||||||
@@ -115,11 +113,10 @@ public class DefaultFaviconFetcher extends AbstractFaviconFetcher {
|
|||||||
String contentType;
|
String contentType;
|
||||||
try {
|
try {
|
||||||
HttpResult result = getter.get(href);
|
HttpResult result = getter.get(href);
|
||||||
bytes = result.getContent();
|
bytes = result.content();
|
||||||
contentType = result.getContentType();
|
contentType = result.contentType();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.debug("Failed to retrieve icon found in page {}", href);
|
log.debug("Failed to retrieve icon found in page {}", href, e);
|
||||||
log.trace("Failed to retrieve icon found in page {}", href, e);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ public class FacebookFaviconFetcher extends AbstractFaviconFetcher {
|
|||||||
log.debug("Getting Facebook user's icon, {}", url);
|
log.debug("Getting Facebook user's icon, {}", url);
|
||||||
|
|
||||||
HttpResult iconResult = getter.get(iconUrl);
|
HttpResult iconResult = getter.get(iconUrl);
|
||||||
bytes = iconResult.getContent();
|
bytes = iconResult.content();
|
||||||
contentType = iconResult.getContentType();
|
contentType = iconResult.contentType();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.debug("Failed to retrieve Facebook icon", e);
|
log.debug("Failed to retrieve Facebook icon", e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,20 +2,13 @@ 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.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@Getter
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class Favicon {
|
public record Favicon(byte[] icon, MediaType mediaType) {
|
||||||
|
|
||||||
private static final MediaType DEFAULT_MEDIA_TYPE = MediaType.valueOf("image/x-icon");
|
private static final MediaType DEFAULT_MEDIA_TYPE = MediaType.valueOf("image/x-icon");
|
||||||
|
|
||||||
private final byte[] icon;
|
|
||||||
private final MediaType mediaType;
|
|
||||||
|
|
||||||
public Favicon(byte[] icon, String contentType) {
|
public Favicon(byte[] icon, String contentType) {
|
||||||
this(icon, parseMediaType(contentType));
|
this(icon, parseMediaType(contentType));
|
||||||
}
|
}
|
||||||
@@ -24,7 +17,7 @@ public class Favicon {
|
|||||||
try {
|
try {
|
||||||
return MediaType.valueOf(contentType);
|
return MediaType.valueOf(contentType);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.debug("invalid content type '{}' received, returning default value", contentType);
|
log.debug("invalid content type '{}' received, returning default value", contentType, e);
|
||||||
return DEFAULT_MEDIA_TYPE;
|
return DEFAULT_MEDIA_TYPE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import org.apache.hc.core5.net.URIBuilder;
|
|||||||
|
|
||||||
import com.commafeed.CommaFeedConfiguration;
|
import com.commafeed.CommaFeedConfiguration;
|
||||||
import com.commafeed.backend.HttpGetter;
|
import com.commafeed.backend.HttpGetter;
|
||||||
import com.commafeed.backend.HttpGetter.HostNotAllowedException;
|
|
||||||
import com.commafeed.backend.HttpGetter.HttpResult;
|
import com.commafeed.backend.HttpGetter.HttpResult;
|
||||||
import com.commafeed.backend.HttpGetter.NotModifiedException;
|
import com.commafeed.backend.HttpGetter.NotModifiedException;
|
||||||
import com.commafeed.backend.HttpGetter.SchemeNotAllowedException;
|
import com.commafeed.backend.HttpGetter.SchemeNotAllowedException;
|
||||||
@@ -85,8 +84,8 @@ public class YoutubeFaviconFetcher extends AbstractFaviconFetcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HttpResult iconResult = getter.get(thumbnailUrl.asText());
|
HttpResult iconResult = getter.get(thumbnailUrl.asText());
|
||||||
bytes = iconResult.getContent();
|
bytes = iconResult.content();
|
||||||
contentType = iconResult.getContentType();
|
contentType = iconResult.contentType();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.debug("Failed to retrieve YouTube icon", e);
|
log.debug("Failed to retrieve YouTube icon", e);
|
||||||
}
|
}
|
||||||
@@ -98,33 +97,33 @@ public class YoutubeFaviconFetcher extends AbstractFaviconFetcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private byte[] fetchForUser(String googleAuthKey, String userId)
|
private byte[] fetchForUser(String googleAuthKey, String userId)
|
||||||
throws IOException, NotModifiedException, TooManyRequestsException, HostNotAllowedException, SchemeNotAllowedException {
|
throws IOException, NotModifiedException, TooManyRequestsException, SchemeNotAllowedException {
|
||||||
URI uri = UriBuilder.fromUri("https://www.googleapis.com/youtube/v3/channels")
|
URI uri = UriBuilder.fromUri("https://www.googleapis.com/youtube/v3/channels")
|
||||||
.queryParam("part", PART_SNIPPET)
|
.queryParam("part", PART_SNIPPET)
|
||||||
.queryParam("key", googleAuthKey)
|
.queryParam("key", googleAuthKey)
|
||||||
.queryParam("forUsername", userId)
|
.queryParam("forUsername", userId)
|
||||||
.build();
|
.build();
|
||||||
return getter.get(uri.toString()).getContent();
|
return getter.get(uri.toString()).content();
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] fetchForChannel(String googleAuthKey, String channelId)
|
private byte[] fetchForChannel(String googleAuthKey, String channelId)
|
||||||
throws IOException, NotModifiedException, TooManyRequestsException, HostNotAllowedException, SchemeNotAllowedException {
|
throws IOException, NotModifiedException, TooManyRequestsException, SchemeNotAllowedException {
|
||||||
URI uri = UriBuilder.fromUri("https://www.googleapis.com/youtube/v3/channels")
|
URI uri = UriBuilder.fromUri("https://www.googleapis.com/youtube/v3/channels")
|
||||||
.queryParam("part", PART_SNIPPET)
|
.queryParam("part", PART_SNIPPET)
|
||||||
.queryParam("key", googleAuthKey)
|
.queryParam("key", googleAuthKey)
|
||||||
.queryParam("id", channelId)
|
.queryParam("id", channelId)
|
||||||
.build();
|
.build();
|
||||||
return getter.get(uri.toString()).getContent();
|
return getter.get(uri.toString()).content();
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] fetchForPlaylist(String googleAuthKey, String playlistId)
|
private byte[] fetchForPlaylist(String googleAuthKey, String playlistId)
|
||||||
throws IOException, NotModifiedException, TooManyRequestsException, HostNotAllowedException, SchemeNotAllowedException {
|
throws IOException, NotModifiedException, TooManyRequestsException, SchemeNotAllowedException {
|
||||||
URI uri = UriBuilder.fromUri("https://www.googleapis.com/youtube/v3/playlists")
|
URI uri = UriBuilder.fromUri("https://www.googleapis.com/youtube/v3/playlists")
|
||||||
.queryParam("part", PART_SNIPPET)
|
.queryParam("part", PART_SNIPPET)
|
||||||
.queryParam("key", googleAuthKey)
|
.queryParam("key", googleAuthKey)
|
||||||
.queryParam("id", playlistId)
|
.queryParam("id", playlistId)
|
||||||
.build();
|
.build();
|
||||||
byte[] playlistBytes = getter.get(uri.toString()).getContent();
|
byte[] playlistBytes = getter.get(uri.toString()).content();
|
||||||
|
|
||||||
JsonNode channelId = objectMapper.readTree(playlistBytes).at(PLAYLIST_CHANNEL_ID);
|
JsonNode channelId = objectMapper.readTree(playlistBytes).at(PLAYLIST_CHANNEL_ID);
|
||||||
if (channelId.isMissingNode()) {
|
if (channelId.isMissingNode()) {
|
||||||
|
|||||||
@@ -5,23 +5,15 @@ import java.util.List;
|
|||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A keyword used in a search query
|
* A keyword used in a search query
|
||||||
*/
|
*/
|
||||||
@Getter
|
public record FeedEntryKeyword(String keyword, Mode mode) {
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class FeedEntryKeyword {
|
|
||||||
|
|
||||||
public enum Mode {
|
public enum Mode {
|
||||||
INCLUDE, EXCLUDE
|
INCLUDE, EXCLUDE
|
||||||
}
|
}
|
||||||
|
|
||||||
private final String keyword;
|
|
||||||
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) {
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import org.apache.commons.lang3.Strings;
|
|||||||
|
|
||||||
import com.commafeed.backend.Digests;
|
import com.commafeed.backend.Digests;
|
||||||
import com.commafeed.backend.HttpGetter;
|
import com.commafeed.backend.HttpGetter;
|
||||||
import com.commafeed.backend.HttpGetter.HostNotAllowedException;
|
|
||||||
import com.commafeed.backend.HttpGetter.HttpRequest;
|
import com.commafeed.backend.HttpGetter.HttpRequest;
|
||||||
import com.commafeed.backend.HttpGetter.HttpResult;
|
import com.commafeed.backend.HttpGetter.HttpResult;
|
||||||
import com.commafeed.backend.HttpGetter.NotModifiedException;
|
import com.commafeed.backend.HttpGetter.NotModifiedException;
|
||||||
@@ -46,24 +45,24 @@ public class FeedFetcher {
|
|||||||
|
|
||||||
public FeedFetcherResult fetch(String feedUrl, boolean extractFeedUrlFromHtml, String lastModified, String eTag,
|
public FeedFetcherResult fetch(String feedUrl, boolean extractFeedUrlFromHtml, String lastModified, String eTag,
|
||||||
Instant lastPublishedDate, String lastContentHash) throws FeedParsingException, IOException, NotModifiedException,
|
Instant lastPublishedDate, String lastContentHash) throws FeedParsingException, IOException, NotModifiedException,
|
||||||
TooManyRequestsException, SchemeNotAllowedException, HostNotAllowedException, NoFeedFoundException {
|
TooManyRequestsException, SchemeNotAllowedException, NoFeedFoundException {
|
||||||
log.debug("Fetching feed {}", feedUrl);
|
log.debug("Fetching feed {}", feedUrl);
|
||||||
|
|
||||||
HttpResult result = getter.get(HttpRequest.builder(feedUrl).lastModified(lastModified).eTag(eTag).build());
|
HttpResult result = getter.get(HttpRequest.builder(feedUrl).lastModified(lastModified).eTag(eTag).build());
|
||||||
byte[] content = result.getContent();
|
byte[] content = result.content();
|
||||||
|
|
||||||
FeedParserResult parserResult;
|
FeedParserResult parserResult;
|
||||||
try {
|
try {
|
||||||
parserResult = parser.parse(result.getUrlAfterRedirect(), content);
|
parserResult = parser.parse(result.urlAfterRedirect(), content);
|
||||||
} catch (FeedParsingException e) {
|
} catch (FeedParsingException e) {
|
||||||
if (extractFeedUrlFromHtml) {
|
if (extractFeedUrlFromHtml) {
|
||||||
String extractedUrl = extractFeedUrl(urlProviders, feedUrl, new String(result.getContent(), StandardCharsets.UTF_8));
|
String extractedUrl = extractFeedUrl(urlProviders, feedUrl, new String(result.content(), StandardCharsets.UTF_8));
|
||||||
if (StringUtils.isNotBlank(extractedUrl)) {
|
if (StringUtils.isNotBlank(extractedUrl)) {
|
||||||
feedUrl = extractedUrl;
|
feedUrl = extractedUrl;
|
||||||
|
|
||||||
result = getter.get(HttpRequest.builder(extractedUrl).lastModified(lastModified).eTag(eTag).build());
|
result = getter.get(HttpRequest.builder(extractedUrl).lastModified(lastModified).eTag(eTag).build());
|
||||||
content = result.getContent();
|
content = result.content();
|
||||||
parserResult = parser.parse(result.getUrlAfterRedirect(), content);
|
parserResult = parser.parse(result.urlAfterRedirect(), content);
|
||||||
} else {
|
} else {
|
||||||
throw new NoFeedFoundException(e);
|
throw new NoFeedFoundException(e);
|
||||||
}
|
}
|
||||||
@@ -76,26 +75,24 @@ public class FeedFetcher {
|
|||||||
throw new IOException("Feed content is empty.");
|
throw new IOException("Feed content is empty.");
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean lastModifiedHeaderValueChanged = !Strings.CS.equals(lastModified, result.getLastModifiedSince());
|
boolean lastModifiedHeaderValueChanged = !Strings.CS.equals(lastModified, result.lastModifiedSince());
|
||||||
boolean etagHeaderValueChanged = !Strings.CS.equals(eTag, result.getETag());
|
boolean etagHeaderValueChanged = !Strings.CS.equals(eTag, result.eTag());
|
||||||
|
|
||||||
String hash = Digests.sha1Hex(content);
|
String hash = Digests.sha1Hex(content);
|
||||||
if (lastContentHash != null && lastContentHash.equals(hash)) {
|
if (lastContentHash != null && lastContentHash.equals(hash)) {
|
||||||
log.debug("content hash not modified: {}", feedUrl);
|
log.debug("content hash not modified: {}", feedUrl);
|
||||||
throw new NotModifiedException("content hash not modified",
|
throw new NotModifiedException("content hash not modified", lastModifiedHeaderValueChanged ? result.lastModifiedSince() : null,
|
||||||
lastModifiedHeaderValueChanged ? result.getLastModifiedSince() : null,
|
etagHeaderValueChanged ? result.eTag() : null);
|
||||||
etagHeaderValueChanged ? result.getETag() : null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastPublishedDate != null && lastPublishedDate.equals(parserResult.lastPublishedDate())) {
|
if (lastPublishedDate != null && lastPublishedDate.equals(parserResult.lastPublishedDate())) {
|
||||||
log.debug("publishedDate not modified: {}", feedUrl);
|
log.debug("publishedDate not modified: {}", feedUrl);
|
||||||
throw new NotModifiedException("publishedDate not modified",
|
throw new NotModifiedException("publishedDate not modified", lastModifiedHeaderValueChanged ? result.lastModifiedSince() : null,
|
||||||
lastModifiedHeaderValueChanged ? result.getLastModifiedSince() : null,
|
etagHeaderValueChanged ? result.eTag() : null);
|
||||||
etagHeaderValueChanged ? result.getETag() : null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new FeedFetcherResult(parserResult, result.getUrlAfterRedirect(), result.getLastModifiedSince(), result.getETag(), hash,
|
return new FeedFetcherResult(parserResult, result.urlAfterRedirect(), result.lastModifiedSince(), result.eTag(), hash,
|
||||||
result.getValidFor());
|
result.validFor());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String extractFeedUrl(List<FeedURLProvider> urlProviders, String url, String urlContent) {
|
private static String extractFeedUrl(List<FeedURLProvider> urlProviders, String url, String urlContent) {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ 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.LinkedBlockingQueue;
|
||||||
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;
|
||||||
@@ -21,6 +22,9 @@ import com.commafeed.backend.dao.FeedDAO;
|
|||||||
import com.commafeed.backend.dao.UnitOfWork;
|
import com.commafeed.backend.dao.UnitOfWork;
|
||||||
import com.commafeed.backend.model.AbstractModel;
|
import com.commafeed.backend.model.AbstractModel;
|
||||||
import com.commafeed.backend.model.Feed;
|
import com.commafeed.backend.model.Feed;
|
||||||
|
import com.commafeed.backend.model.FeedEntry;
|
||||||
|
import com.commafeed.backend.model.FeedSubscription;
|
||||||
|
import com.google.common.util.concurrent.MoreExecutors;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@@ -32,40 +36,51 @@ public class FeedRefreshEngine {
|
|||||||
private final FeedDAO feedDAO;
|
private final FeedDAO feedDAO;
|
||||||
private final FeedRefreshWorker worker;
|
private final FeedRefreshWorker worker;
|
||||||
private final FeedRefreshUpdater updater;
|
private final FeedRefreshUpdater updater;
|
||||||
|
private final FeedUpdateNotifier notifier;
|
||||||
private final CommaFeedConfiguration config;
|
private final CommaFeedConfiguration config;
|
||||||
private final Meter refill;
|
private final Meter refill;
|
||||||
|
|
||||||
private final BlockingDeque<Feed> queue;
|
private final BlockingDeque<Feed> queue;
|
||||||
|
|
||||||
private final ExecutorService feedProcessingLoopExecutor;
|
private ExecutorService feedProcessingLoopExecutor;
|
||||||
private final ExecutorService refillLoopExecutor;
|
private ExecutorService refillLoopExecutor;
|
||||||
private final ExecutorService refillExecutor;
|
private ThreadPoolExecutor refillExecutor;
|
||||||
private final ThreadPoolExecutor workerExecutor;
|
private ThreadPoolExecutor workerExecutor;
|
||||||
private final ThreadPoolExecutor databaseUpdaterExecutor;
|
private ThreadPoolExecutor databaseUpdaterExecutor;
|
||||||
|
private ThreadPoolExecutor notifierExecutor;
|
||||||
|
|
||||||
public FeedRefreshEngine(UnitOfWork unitOfWork, FeedDAO feedDAO, FeedRefreshWorker worker, FeedRefreshUpdater updater,
|
public FeedRefreshEngine(UnitOfWork unitOfWork, FeedDAO feedDAO, FeedRefreshWorker worker, FeedRefreshUpdater updater,
|
||||||
CommaFeedConfiguration config, MetricRegistry metrics) {
|
FeedUpdateNotifier notifier, CommaFeedConfiguration config, MetricRegistry metrics) {
|
||||||
this.unitOfWork = unitOfWork;
|
this.unitOfWork = unitOfWork;
|
||||||
this.feedDAO = feedDAO;
|
this.feedDAO = feedDAO;
|
||||||
this.worker = worker;
|
this.worker = worker;
|
||||||
this.updater = updater;
|
this.updater = updater;
|
||||||
|
this.notifier = notifier;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.refill = metrics.meter(MetricRegistry.name(getClass(), "refill"));
|
this.refill = metrics.meter(MetricRegistry.name(getClass(), "refill"));
|
||||||
|
|
||||||
this.queue = new LinkedBlockingDeque<>();
|
this.queue = new LinkedBlockingDeque<>();
|
||||||
|
|
||||||
|
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(), "updater", "active"),
|
||||||
|
(Gauge<Integer>) () -> databaseUpdaterExecutor.getActiveCount());
|
||||||
|
metrics.register(MetricRegistry.name(getClass(), "notifier", "active"), (Gauge<Integer>) () -> notifierExecutor.getActiveCount());
|
||||||
|
metrics.register(MetricRegistry.name(getClass(), "notifier", "queue"), (Gauge<Integer>) () -> notifierExecutor.getQueue().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createExecutors() {
|
||||||
this.feedProcessingLoopExecutor = Executors.newSingleThreadExecutor();
|
this.feedProcessingLoopExecutor = Executors.newSingleThreadExecutor();
|
||||||
this.refillLoopExecutor = Executors.newSingleThreadExecutor();
|
this.refillLoopExecutor = Executors.newSingleThreadExecutor();
|
||||||
this.refillExecutor = newDiscardingSingleThreadExecutorService();
|
this.refillExecutor = newDiscardingSingleThreadExecutorService();
|
||||||
this.workerExecutor = newBlockingExecutorService(config.feedRefresh().httpThreads());
|
this.workerExecutor = newBlockingExecutorService(config.feedRefresh().httpThreads());
|
||||||
this.databaseUpdaterExecutor = newBlockingExecutorService(config.feedRefresh().databaseThreads());
|
this.databaseUpdaterExecutor = newBlockingExecutorService(config.feedRefresh().databaseThreads());
|
||||||
|
this.notifierExecutor = newDiscardingExecutorService(config.pushNotifications().threads(),
|
||||||
metrics.register(MetricRegistry.name(getClass(), "queue", "size"), (Gauge<Integer>) queue::size);
|
config.pushNotifications().queueCapacity());
|
||||||
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() {
|
public void start() {
|
||||||
|
createExecutors();
|
||||||
startFeedProcessingLoop();
|
startFeedProcessingLoop();
|
||||||
startRefillLoop();
|
startRefillLoop();
|
||||||
}
|
}
|
||||||
@@ -152,10 +167,19 @@ public class FeedRefreshEngine {
|
|||||||
private void processFeedAsync(Feed feed) {
|
private void processFeedAsync(Feed feed) {
|
||||||
CompletableFuture.supplyAsync(() -> worker.update(feed), workerExecutor)
|
CompletableFuture.supplyAsync(() -> worker.update(feed), workerExecutor)
|
||||||
.thenApplyAsync(r -> updater.update(r.feed(), r.entries()), databaseUpdaterExecutor)
|
.thenApplyAsync(r -> updater.update(r.feed(), r.entries()), databaseUpdaterExecutor)
|
||||||
.whenComplete((data, ex) -> {
|
.thenCompose(r -> {
|
||||||
if (ex != null) {
|
List<CompletableFuture<Void>> futures = r.insertedUnreadEntriesBySubscription().entrySet().stream().map(e -> {
|
||||||
log.error("error while processing feed {}", feed.getUrl(), ex);
|
FeedSubscription sub = e.getKey();
|
||||||
}
|
List<FeedEntry> entries = e.getValue();
|
||||||
|
|
||||||
|
notifier.notifyOverWebsocket(sub, entries);
|
||||||
|
return CompletableFuture.runAsync(() -> notifier.sendPushNotifications(sub, entries), notifierExecutor);
|
||||||
|
}).toList();
|
||||||
|
return CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new));
|
||||||
|
})
|
||||||
|
.exceptionally(ex -> {
|
||||||
|
log.error("error while processing feed {}", feed.getUrl(), ex);
|
||||||
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,9 +188,11 @@ public class FeedRefreshEngine {
|
|||||||
Instant lastLoginThreshold = config.feedRefresh().userInactivityPeriod().isZero() ? null
|
Instant lastLoginThreshold = config.feedRefresh().userInactivityPeriod().isZero() ? null
|
||||||
: Instant.now().minus(config.feedRefresh().userInactivityPeriod());
|
: Instant.now().minus(config.feedRefresh().userInactivityPeriod());
|
||||||
List<Feed> feeds = feedDAO.findNextUpdatable(max, lastLoginThreshold);
|
List<Feed> feeds = feedDAO.findNextUpdatable(max, lastLoginThreshold);
|
||||||
// update disabledUntil to prevent feeds from being returned again by feedDAO.findNextUpdatable()
|
if (!feeds.isEmpty()) {
|
||||||
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());
|
||||||
|
feedDAO.setDisabledUntil(feeds.stream().map(AbstractModel::getId).toList(), nextUpdateDate);
|
||||||
|
}
|
||||||
return feeds;
|
return feeds;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -176,11 +202,14 @@ public class FeedRefreshEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
this.feedProcessingLoopExecutor.shutdownNow();
|
MoreExecutors.shutdownAndAwaitTermination(this.feedProcessingLoopExecutor, config.shutdownTimeout());
|
||||||
this.refillLoopExecutor.shutdownNow();
|
MoreExecutors.shutdownAndAwaitTermination(this.refillLoopExecutor, config.shutdownTimeout());
|
||||||
this.refillExecutor.shutdownNow();
|
MoreExecutors.shutdownAndAwaitTermination(this.refillExecutor, config.shutdownTimeout());
|
||||||
this.workerExecutor.shutdownNow();
|
MoreExecutors.shutdownAndAwaitTermination(this.workerExecutor, config.shutdownTimeout());
|
||||||
this.databaseUpdaterExecutor.shutdownNow();
|
MoreExecutors.shutdownAndAwaitTermination(this.databaseUpdaterExecutor, config.shutdownTimeout());
|
||||||
|
MoreExecutors.shutdownAndAwaitTermination(this.notifierExecutor, config.shutdownTimeout());
|
||||||
|
|
||||||
|
queue.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -192,6 +221,16 @@ public class FeedRefreshEngine {
|
|||||||
return pool;
|
return pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns an ExecutorService that discards tasks if the queue is full
|
||||||
|
*/
|
||||||
|
private ThreadPoolExecutor newDiscardingExecutorService(int threads, int queueCapacity) {
|
||||||
|
ThreadPoolExecutor pool = new ThreadPoolExecutor(threads, threads, 0L, TimeUnit.MILLISECONDS,
|
||||||
|
new LinkedBlockingQueue<>(queueCapacity));
|
||||||
|
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
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.commafeed.backend.feed;
|
package com.commafeed.backend.feed;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -27,11 +28,8 @@ import com.commafeed.backend.model.FeedSubscription;
|
|||||||
import com.commafeed.backend.model.Models;
|
import com.commafeed.backend.model.Models;
|
||||||
import com.commafeed.backend.service.FeedEntryService;
|
import com.commafeed.backend.service.FeedEntryService;
|
||||||
import com.commafeed.backend.service.FeedService;
|
import com.commafeed.backend.service.FeedService;
|
||||||
import com.commafeed.frontend.ws.WebSocketMessageBuilder;
|
|
||||||
import com.commafeed.frontend.ws.WebSocketSessions;
|
|
||||||
import com.google.common.util.concurrent.Striped;
|
import com.google.common.util.concurrent.Striped;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,7 +43,6 @@ public class FeedRefreshUpdater {
|
|||||||
private final FeedService feedService;
|
private final FeedService feedService;
|
||||||
private final FeedEntryService feedEntryService;
|
private final FeedEntryService feedEntryService;
|
||||||
private final FeedSubscriptionDAO feedSubscriptionDAO;
|
private final FeedSubscriptionDAO feedSubscriptionDAO;
|
||||||
private final WebSocketSessions webSocketSessions;
|
|
||||||
|
|
||||||
private final Striped<Lock> locks;
|
private final Striped<Lock> locks;
|
||||||
|
|
||||||
@@ -53,12 +50,11 @@ public class FeedRefreshUpdater {
|
|||||||
private final Meter entryInserted;
|
private final Meter entryInserted;
|
||||||
|
|
||||||
public FeedRefreshUpdater(UnitOfWork unitOfWork, FeedService feedService, FeedEntryService feedEntryService, MetricRegistry metrics,
|
public FeedRefreshUpdater(UnitOfWork unitOfWork, FeedService feedService, FeedEntryService feedEntryService, MetricRegistry metrics,
|
||||||
FeedSubscriptionDAO feedSubscriptionDAO, WebSocketSessions webSocketSessions) {
|
FeedSubscriptionDAO feedSubscriptionDAO) {
|
||||||
this.unitOfWork = unitOfWork;
|
this.unitOfWork = unitOfWork;
|
||||||
this.feedService = feedService;
|
this.feedService = feedService;
|
||||||
this.feedEntryService = feedEntryService;
|
this.feedEntryService = feedEntryService;
|
||||||
this.feedSubscriptionDAO = feedSubscriptionDAO;
|
this.feedSubscriptionDAO = feedSubscriptionDAO;
|
||||||
this.webSocketSessions = webSocketSessions;
|
|
||||||
|
|
||||||
locks = Striped.lazyWeakLock(100000);
|
locks = Striped.lazyWeakLock(100000);
|
||||||
|
|
||||||
@@ -68,7 +64,7 @@ public class FeedRefreshUpdater {
|
|||||||
|
|
||||||
private AddEntryResult addEntry(final Feed feed, final Entry entry, final List<FeedSubscription> subscriptions) {
|
private AddEntryResult addEntry(final Feed feed, final Entry entry, final List<FeedSubscription> subscriptions) {
|
||||||
boolean processed = false;
|
boolean processed = false;
|
||||||
boolean inserted = false;
|
FeedEntry insertedEntry = null;
|
||||||
Set<FeedSubscription> subscriptionsForWhichEntryIsUnread = new HashSet<>();
|
Set<FeedSubscription> subscriptionsForWhichEntryIsUnread = new HashSet<>();
|
||||||
|
|
||||||
// lock on feed, make sure we are not updating the same feed twice at
|
// lock on feed, make sure we are not updating the same feed twice at
|
||||||
@@ -91,23 +87,21 @@ public class FeedRefreshUpdater {
|
|||||||
locked2 = lock2.tryLock(1, TimeUnit.MINUTES);
|
locked2 = lock2.tryLock(1, TimeUnit.MINUTES);
|
||||||
if (locked1 && locked2) {
|
if (locked1 && locked2) {
|
||||||
processed = true;
|
processed = true;
|
||||||
inserted = unitOfWork.call(() -> {
|
insertedEntry = unitOfWork.call(() -> {
|
||||||
boolean newEntry = false;
|
if (feedEntryService.find(feed, entry) != null) {
|
||||||
FeedEntry feedEntry = feedEntryService.find(feed, entry);
|
// entry already exists, nothing to do
|
||||||
if (feedEntry == null) {
|
return null;
|
||||||
feedEntry = feedEntryService.create(feed, entry);
|
|
||||||
newEntry = true;
|
|
||||||
}
|
}
|
||||||
if (newEntry) {
|
|
||||||
entryInserted.mark();
|
FeedEntry feedEntry = feedEntryService.create(feed, entry);
|
||||||
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 feedEntry;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
log.error("lock timeout for {} - {}", feed.getUrl(), key1);
|
log.error("lock timeout for {} - {}", feed.getUrl(), key1);
|
||||||
@@ -123,13 +117,13 @@ public class FeedRefreshUpdater {
|
|||||||
lock2.unlock();
|
lock2.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new AddEntryResult(processed, inserted, subscriptionsForWhichEntryIsUnread);
|
return new AddEntryResult(processed, insertedEntry, subscriptionsForWhichEntryIsUnread);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean update(Feed feed, List<Entry> entries) {
|
public FeedRefreshUpdaterResult update(Feed feed, List<Entry> entries) {
|
||||||
boolean processed = true;
|
boolean processed = true;
|
||||||
long inserted = 0;
|
long inserted = 0;
|
||||||
Map<FeedSubscription, Long> unreadCountBySubscription = new HashMap<>();
|
Map<FeedSubscription, List<FeedEntry>> insertedUnreadEntriesBySubscription = new HashMap<>();
|
||||||
|
|
||||||
if (!entries.isEmpty()) {
|
if (!entries.isEmpty()) {
|
||||||
List<FeedSubscription> subscriptions = null;
|
List<FeedSubscription> subscriptions = null;
|
||||||
@@ -139,8 +133,12 @@ public class FeedRefreshUpdater {
|
|||||||
}
|
}
|
||||||
AddEntryResult addEntryResult = addEntry(feed, entry, subscriptions);
|
AddEntryResult addEntryResult = addEntry(feed, entry, subscriptions);
|
||||||
processed &= addEntryResult.processed;
|
processed &= addEntryResult.processed;
|
||||||
inserted += addEntryResult.inserted ? 1 : 0;
|
inserted += addEntryResult.insertedEntry != null ? 1 : 0;
|
||||||
addEntryResult.subscriptionsForWhichEntryIsUnread.forEach(sub -> unreadCountBySubscription.merge(sub, 1L, Long::sum));
|
addEntryResult.subscriptionsForWhichEntryIsUnread.forEach(sub -> {
|
||||||
|
if (addEntryResult.insertedEntry != null) {
|
||||||
|
insertedUnreadEntriesBySubscription.computeIfAbsent(sub, k -> new ArrayList<>()).add(addEntryResult.insertedEntry);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inserted == 0) {
|
if (inserted == 0) {
|
||||||
@@ -161,21 +159,13 @@ public class FeedRefreshUpdater {
|
|||||||
|
|
||||||
unitOfWork.run(() -> feedService.update(feed));
|
unitOfWork.run(() -> feedService.update(feed));
|
||||||
|
|
||||||
notifyOverWebsocket(unreadCountBySubscription);
|
return new FeedRefreshUpdaterResult(insertedUnreadEntriesBySubscription);
|
||||||
|
|
||||||
return processed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyOverWebsocket(Map<FeedSubscription, Long> unreadCountBySubscription) {
|
private record AddEntryResult(boolean processed, FeedEntry insertedEntry, Set<FeedSubscription> subscriptionsForWhichEntryIsUnread) {
|
||||||
unreadCountBySubscription.forEach((sub, unreadCount) -> webSocketSessions.sendMessage(sub.getUser(),
|
|
||||||
WebSocketMessageBuilder.newFeedEntries(sub, unreadCount)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@AllArgsConstructor
|
public record FeedRefreshUpdaterResult(Map<FeedSubscription, List<FeedEntry>> insertedUnreadEntriesBySubscription) {
|
||||||
private static class AddEntryResult {
|
|
||||||
private final boolean processed;
|
|
||||||
private final boolean inserted;
|
|
||||||
private final Set<FeedSubscription> subscriptionsForWhichEntryIsUnread;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user