mirror of
https://github.com/glitch-soc/mastodon.git
synced 2025-12-12 23:38:20 +00:00
Compare commits
422 Commits
v4.4.3
...
167c46adce
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
167c46adce | ||
|
|
7040d14476 | ||
|
|
3260d25a8e | ||
|
|
b635c419fc | ||
|
|
d2f1767b81 | ||
|
|
9636fc22cc | ||
|
|
3924b33914 | ||
|
|
99efed9aee | ||
|
|
f97834019a | ||
|
|
6dee9a12d2 | ||
|
|
81ed241061 | ||
|
|
aa1d3825cd | ||
|
|
032aa9eb68 | ||
|
|
50b586ef02 | ||
|
|
233f7570b3 | ||
|
|
51b1a49834 | ||
|
|
90955d4ca5 | ||
|
|
5ef8a632bf | ||
|
|
6d55436687 | ||
|
|
5983f8292b | ||
|
|
30c34606a1 | ||
|
|
a53edd223e | ||
|
|
22c9f190e8 | ||
|
|
f88b139a70 | ||
|
|
82edd1bcf5 | ||
|
|
414f8ff60d | ||
|
|
9e1c33f96a | ||
|
|
ef4ecd5eeb | ||
|
|
a86078e8bb | ||
|
|
a3a02549e8 | ||
|
|
06081721ef | ||
|
|
60771df3e7 | ||
|
|
21b324cc88 | ||
|
|
5f07606955 | ||
|
|
51b29f4c30 | ||
|
|
0ec46833fa | ||
|
|
de488fbea2 | ||
|
|
d595641b73 | ||
|
|
fd733d0603 | ||
|
|
055be70c59 | ||
|
|
0eeb0f00ba | ||
|
|
6e406e119f | ||
|
|
789df6b196 | ||
|
|
6b78be274b | ||
|
|
a3d4b7c9b9 | ||
|
|
d2b544e584 | ||
|
|
84c5ffb565 | ||
|
|
1d26fa9fed | ||
|
|
62f21ab1fc | ||
|
|
42594f253e | ||
|
|
b21e29cc7c | ||
|
|
ef8b45f004 | ||
|
|
16a3fcbe26 | ||
|
|
65f1d77043 | ||
|
|
6202cf6b65 | ||
|
|
8ee8228d46 | ||
|
|
18869e9c90 | ||
|
|
70ca99224f | ||
|
|
2232de0bfa | ||
|
|
37b642d59c | ||
|
|
11ec1a8d7b | ||
|
|
ec8c7dca2f | ||
|
|
b6264ea625 | ||
|
|
36c5b0e2f0 | ||
|
|
645c910d38 | ||
|
|
a076fa2063 | ||
|
|
f6dbb2206c | ||
|
|
ea6736681b | ||
|
|
9ee5872f14 | ||
|
|
447527c154 | ||
|
|
973eb0a1d3 | ||
|
|
5039e9d474 | ||
|
|
980c336ca4 | ||
|
|
4632be68eb | ||
|
|
8db52f2e66 | ||
|
|
b38bbd04ea | ||
|
|
bd0c865bbb | ||
|
|
936827013b | ||
|
|
f1cfde4152 | ||
|
|
8c25742d4c | ||
|
|
44a88ad4d5 | ||
|
|
45fa4d99b3 | ||
|
|
11a466ab53 | ||
|
|
e517c2a1bf | ||
|
|
787702c26b | ||
|
|
91b3859b7b | ||
|
|
9b31a5fc4c | ||
|
|
b6aa0b4990 | ||
|
|
7868b545ed | ||
|
|
bd8d96e699 | ||
|
|
e6591bf322 | ||
|
|
30e25ff7fc | ||
|
|
5ef82d7937 | ||
|
|
e14bf631b5 | ||
|
|
6d46225718 | ||
|
|
022af54ea2 | ||
|
|
bcf788dad7 | ||
|
|
7917b495d2 | ||
|
|
ec2023233d | ||
|
|
e6a6c26c36 | ||
|
|
86a8aa5e5c | ||
|
|
a9f8b1ad96 | ||
|
|
698e4fdef2 | ||
|
|
72b1af137e | ||
|
|
8291afae35 | ||
|
|
1ce0733cac | ||
|
|
8bfbf2abaf | ||
|
|
a63511425f | ||
|
|
459e3451b6 | ||
|
|
58d2c7b481 | ||
|
|
ae43b6bb09 | ||
|
|
6f16011c5a | ||
|
|
f79810313c | ||
|
|
65a6840f71 | ||
|
|
527d9200d0 | ||
|
|
cbb9b83160 | ||
|
|
51fcb9ca99 | ||
|
|
4a271072f5 | ||
|
|
6d53e8c6c5 | ||
|
|
d9fb61f305 | ||
|
|
6af733d1d8 | ||
|
|
29eae75ca0 | ||
|
|
8a3f25a4fa | ||
|
|
0615febd84 | ||
|
|
86d8df0c03 | ||
|
|
105e5b1d76 | ||
|
|
d6442b5455 | ||
|
|
653868bb0c | ||
|
|
4cb3fe35be | ||
|
|
8197e65cb3 | ||
|
|
c48413ad4c | ||
|
|
9be391514b | ||
|
|
2340f4df81 | ||
|
|
db86ec3d62 | ||
|
|
da6e667123 | ||
|
|
cdcd77ebff | ||
|
|
c79c9e8c42 | ||
|
|
e84031ea97 | ||
|
|
d01e407177 | ||
|
|
e1ff48978d | ||
|
|
24304fbbe6 | ||
|
|
644caeb156 | ||
|
|
ad92660de6 | ||
|
|
c5d17a3997 | ||
|
|
a8613b7cda | ||
|
|
0c2fa2aab4 | ||
|
|
62f019252a | ||
|
|
4228ca614c | ||
|
|
7e20ee7695 | ||
|
|
1ed1cdba1b | ||
|
|
b73e968641 | ||
|
|
559f7a8e61 | ||
|
|
bcfd6ab3e4 | ||
|
|
1704a7d858 | ||
|
|
97fd14e141 | ||
|
|
c1f398ae93 | ||
|
|
19b3469c29 | ||
|
|
57e4232b3e | ||
|
|
c6b501c42d | ||
|
|
5140f31cbb | ||
|
|
adee65ad1b | ||
|
|
fba7e85b9b | ||
|
|
bc95675236 | ||
|
|
ccc4fcbdb8 | ||
|
|
e3afbab115 | ||
|
|
baac429103 | ||
|
|
b1a584d252 | ||
|
|
8787077462 | ||
|
|
10bcbf15af | ||
|
|
fb29ac0f5f | ||
|
|
b0f88be86f | ||
|
|
018b85e767 | ||
|
|
08d2250ad2 | ||
|
|
679e7555ee | ||
|
|
452153d55d | ||
|
|
2954c2facb | ||
|
|
44e38b79de | ||
|
|
b32a67ff74 | ||
|
|
4f33b041f0 | ||
|
|
6e906884cf | ||
|
|
317715254f | ||
|
|
2b148d3e88 | ||
|
|
227d48dbd5 | ||
|
|
94fed6e140 | ||
|
|
37b029d400 | ||
|
|
11baa26db2 | ||
|
|
c7172b54fe | ||
|
|
74496838e7 | ||
|
|
ca39069433 | ||
|
|
7ad9581940 | ||
|
|
e4f2a054c9 | ||
|
|
68eb62f4a9 | ||
|
|
e63d0cfe85 | ||
|
|
4da31b8263 | ||
|
|
17695ace33 | ||
|
|
fa2625a0d9 | ||
|
|
1005b2f7b2 | ||
|
|
f24b0e9505 | ||
|
|
4db64491ee | ||
|
|
fd79e2417d | ||
|
|
96455304bc | ||
|
|
63f4e2070c | ||
|
|
faed9bf9f1 | ||
|
|
10f10844ff | ||
|
|
5c8d2be23b | ||
|
|
90072f4367 | ||
|
|
512bfc0a54 | ||
|
|
d764ae017d | ||
|
|
757aed3290 | ||
|
|
3cff7caffd | ||
|
|
533477e77c | ||
|
|
afcfc64007 | ||
|
|
734f0dd182 | ||
|
|
bcc798d6a7 | ||
|
|
3a4242ce01 | ||
|
|
23376cb691 | ||
|
|
c2d65f7142 | ||
|
|
13ab4b54e2 | ||
|
|
df0b641914 | ||
|
|
624b942c2e | ||
|
|
cfa2e0503a | ||
|
|
de945eef63 | ||
|
|
9a7030fb69 | ||
|
|
221da1ba04 | ||
|
|
ff85540904 | ||
|
|
c2862049a2 | ||
|
|
0d69cc068c | ||
|
|
26f25ef4ba | ||
|
|
3b4070cfcc | ||
|
|
eb997c9f0e | ||
|
|
4239baa1f4 | ||
|
|
5532d1c2cb | ||
|
|
3f0d90f019 | ||
|
|
15e1a63e4a | ||
|
|
6b8ff1cf6e | ||
|
|
6cbd217055 | ||
|
|
90c7c1bf7d | ||
|
|
e06448e652 | ||
|
|
3752db3c9a | ||
|
|
cc5c125cc7 | ||
|
|
f65523c5b6 | ||
|
|
5b6b23eeef | ||
|
|
0cbf03efa7 | ||
|
|
90f2c7a1e9 | ||
|
|
f0d734cc6e | ||
|
|
0720ef5f62 | ||
|
|
dc9a106d4c | ||
|
|
c634da32cf | ||
|
|
2d8ce9e19a | ||
|
|
1ddf1aedf1 | ||
|
|
931870ca34 | ||
|
|
7f9b0f36ba | ||
|
|
dd0992b25d | ||
|
|
9b677f099e | ||
|
|
c13b8026f0 | ||
|
|
bf1375ae37 | ||
|
|
b06161dba3 | ||
|
|
a089109b77 | ||
|
|
74f9f7c600 | ||
|
|
ea1b598246 | ||
|
|
dbedd021f5 | ||
|
|
5d79af928c | ||
|
|
a62be22cb1 | ||
|
|
96ffbc05c0 | ||
|
|
39fb314421 | ||
|
|
90f6984ff1 | ||
|
|
9adb96f3a1 | ||
|
|
d5a3478864 | ||
|
|
9877a053f6 | ||
|
|
605ed50603 | ||
|
|
e1609c6813 | ||
|
|
de5d6e98ae | ||
|
|
2b0410f903 | ||
|
|
f7aab0cc2f | ||
|
|
de5f522cc0 | ||
|
|
d728fa9991 | ||
|
|
044dd3f788 | ||
|
|
afc440435c | ||
|
|
d0fb7939bb | ||
|
|
7388a6ce9a | ||
|
|
cd2a3bac79 | ||
|
|
f0e011fbc9 | ||
|
|
acbc273d6e | ||
|
|
1f0c84749d | ||
|
|
e507b4f884 | ||
|
|
93348136a5 | ||
|
|
3a5e83b91a | ||
|
|
8d37565c19 | ||
|
|
177e8fe972 | ||
|
|
198283a188 | ||
|
|
36452845d7 | ||
|
|
5c4bcd2f08 | ||
|
|
a20f38c930 | ||
|
|
b01bd74698 | ||
|
|
41e342a88f | ||
|
|
9258ee8847 | ||
|
|
6d72c13a4d | ||
|
|
ad4be12473 | ||
|
|
527d1253bf | ||
|
|
ae676edc2b | ||
|
|
63df649fe5 | ||
|
|
0ff427fab3 | ||
|
|
dc2f9eef77 | ||
|
|
ff1247ad16 | ||
|
|
fbe55a4545 | ||
|
|
a72819660a | ||
|
|
c292ed07fe | ||
|
|
2d008108a4 | ||
|
|
0c59ef44b1 | ||
|
|
12297faa1d | ||
|
|
9b6f92e47f | ||
|
|
8b6247ca44 | ||
|
|
836cbca469 | ||
|
|
b091e531a5 | ||
|
|
49b3d5692e | ||
|
|
70472de726 | ||
|
|
304e440f88 | ||
|
|
ca68a3cacb | ||
|
|
066efc2d3f | ||
|
|
a2e24ee2de | ||
|
|
ee61f7772a | ||
|
|
5ee72f0e2d | ||
|
|
192e9d16eb | ||
|
|
a3f40309fb | ||
|
|
782a785893 | ||
|
|
9f165436d2 | ||
|
|
592945e498 | ||
|
|
bfb610922d | ||
|
|
480dcecc11 | ||
|
|
2647606a15 | ||
|
|
b40adb4a89 | ||
|
|
f99da81ef8 | ||
|
|
799f507dce | ||
|
|
81472396bc | ||
|
|
a295832960 | ||
|
|
e018e6321f | ||
|
|
f75eb1a8b0 | ||
|
|
de4f7859b4 | ||
|
|
e5e0144957 | ||
|
|
45a520603b | ||
|
|
6ac78ead52 | ||
|
|
c0d3b3de10 | ||
|
|
9e04e46521 | ||
|
|
fa4a82326d | ||
|
|
93fa102f9a | ||
|
|
9ee86a738e | ||
|
|
e272cf5983 | ||
|
|
4382de310c | ||
|
|
94c69bba25 | ||
|
|
ab36c152f9 | ||
|
|
fc5b558b32 | ||
|
|
77ff94d3d2 | ||
|
|
959841ae95 | ||
|
|
f669493d96 | ||
|
|
83b3c50778 | ||
|
|
dc7a42551f | ||
|
|
4a859140ec | ||
|
|
edcf3d9234 | ||
|
|
cae93e79a4 | ||
|
|
83a98cb81a | ||
|
|
889edc560a | ||
|
|
2e0d918d7d | ||
|
|
3b4312476f | ||
|
|
4fba4f8c82 | ||
|
|
25de2f57ee | ||
|
|
026643ab24 | ||
|
|
61e3e81e28 | ||
|
|
354f54907d | ||
|
|
4d611e94ee | ||
|
|
a09a26da49 | ||
|
|
59a8066045 | ||
|
|
3cad5095c9 | ||
|
|
e58d99a771 | ||
|
|
69c76fd94a | ||
|
|
1b6bd585ab | ||
|
|
dfe851b476 | ||
|
|
6d5aa58f88 | ||
|
|
81cd489208 | ||
|
|
55b5364534 | ||
|
|
2e8b752c55 | ||
|
|
d82ffdccbb | ||
|
|
5c72b46a4e | ||
|
|
aa46348c03 | ||
|
|
404f467fcf | ||
|
|
4a2d3929c5 | ||
|
|
ceba0f082e | ||
|
|
7de8d5ffca | ||
|
|
74291dfb77 | ||
|
|
f07707a9bb | ||
|
|
931553844d | ||
|
|
243a85ec8d | ||
|
|
cbf1349370 | ||
|
|
b8fdffe824 | ||
|
|
c91e06bcad | ||
|
|
b2ce9bb4c7 | ||
|
|
19d1392b33 | ||
|
|
09cf617d7f | ||
|
|
784d1bfb29 | ||
|
|
754b03d8cb | ||
|
|
f397550311 | ||
|
|
97db4bd4dd | ||
|
|
1e19242134 | ||
|
|
4e6f13a0fb | ||
|
|
f517f0dbef | ||
|
|
53624b1b54 | ||
|
|
a473988969 | ||
|
|
4ad1e955eb | ||
|
|
66ef4b9984 | ||
|
|
ce2481a81b | ||
|
|
efa74a6c44 | ||
|
|
bdceb1dacf | ||
|
|
e13453aec4 | ||
|
|
25e8a6eaeb | ||
|
|
c828e7731c | ||
|
|
6734b6550f | ||
|
|
6398d7b784 | ||
|
|
1283c3544c | ||
|
|
8ac00533ff | ||
|
|
1b3472bec8 | ||
|
|
c8df7f4995 | ||
|
|
94743fea2c | ||
|
|
deee164acf |
@@ -73,6 +73,16 @@ DB_PORT=5432
|
||||
SECRET_KEY_BASE=
|
||||
OTP_SECRET=
|
||||
|
||||
# Encryption secrets
|
||||
# ------------------
|
||||
# Must be available (and set to same values) for all server processes
|
||||
# These are private/secret values, do not share outside hosting environment
|
||||
# Use `bin/rails db:encryption:init` to generate fresh secrets
|
||||
# Do NOT change these secrets once in use, as this would cause data loss and other issues
|
||||
# ------------------
|
||||
# ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=
|
||||
# ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=
|
||||
# ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=
|
||||
|
||||
# Web Push
|
||||
# --------
|
||||
|
||||
1
.github/actions/setup-ruby/action.yml
vendored
1
.github/actions/setup-ruby/action.yml
vendored
@@ -21,3 +21,4 @@ runs:
|
||||
with:
|
||||
ruby-version: ${{ inputs.ruby-version }}
|
||||
bundler-cache: true
|
||||
cache-version: 4.3
|
||||
|
||||
164
.github/workflows/build-container-image.yml
vendored
164
.github/workflows/build-container-image.yml
vendored
@@ -1,14 +1,9 @@
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
platforms:
|
||||
required: true
|
||||
type: string
|
||||
cache:
|
||||
type: boolean
|
||||
default: true
|
||||
use_native_arm64_builder:
|
||||
type: boolean
|
||||
push_to_images:
|
||||
type: string
|
||||
version_prerelease:
|
||||
@@ -24,42 +19,36 @@ on:
|
||||
file_to_build:
|
||||
type: string
|
||||
|
||||
# This builds multiple images with one runner each, allowing us to build for multiple architectures
|
||||
# using Github's runners.
|
||||
# The two-step process is adapted form:
|
||||
# https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners
|
||||
jobs:
|
||||
# Build each (amd64 and arm64) image separately
|
||||
build-image:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ${{ startsWith(matrix.platform, 'linux/arm') && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform:
|
||||
- linux/amd64
|
||||
- linux/arm64
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: docker/setup-qemu-action@v3
|
||||
if: contains(inputs.platforms, 'linux/arm64') && !inputs.use_native_arm64_builder
|
||||
- name: Prepare
|
||||
env:
|
||||
PUSH_TO_IMAGES: ${{ inputs.push_to_images }}
|
||||
run: |
|
||||
platform=${{ matrix.platform }}
|
||||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||
# Transform multi-line variable into comma-separated variable
|
||||
image_names=${PUSH_TO_IMAGES//$'\n'/,}
|
||||
echo "IMAGE_NAMES=${image_names%,}" >> $GITHUB_ENV
|
||||
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
id: buildx
|
||||
if: ${{ !(inputs.use_native_arm64_builder && contains(inputs.platforms, 'linux/arm64')) }}
|
||||
|
||||
- name: Start a local Docker Builder
|
||||
if: inputs.use_native_arm64_builder && contains(inputs.platforms, 'linux/arm64')
|
||||
run: |
|
||||
docker run --rm -d --name buildkitd -p 1234:1234 --privileged moby/buildkit:latest --addr tcp://0.0.0.0:1234
|
||||
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
id: buildx-native
|
||||
if: inputs.use_native_arm64_builder && contains(inputs.platforms, 'linux/arm64')
|
||||
with:
|
||||
driver: remote
|
||||
endpoint: tcp://localhost:1234
|
||||
platforms: linux/amd64
|
||||
append: |
|
||||
- endpoint: tcp://${{ vars.DOCKER_BUILDER_HETZNER_ARM64_01_HOST }}:13865
|
||||
platforms: linux/arm64
|
||||
name: mastodon-docker-builder-arm64-01
|
||||
driver-opts:
|
||||
- servername=mastodon-docker-builder-arm64-01
|
||||
env:
|
||||
BUILDER_NODE_1_AUTH_TLS_CACERT: ${{ secrets.DOCKER_BUILDER_HETZNER_ARM64_01_CACERT }}
|
||||
BUILDER_NODE_1_AUTH_TLS_CERT: ${{ secrets.DOCKER_BUILDER_HETZNER_ARM64_01_CERT }}
|
||||
BUILDER_NODE_1_AUTH_TLS_KEY: ${{ secrets.DOCKER_BUILDER_HETZNER_ARM64_01_KEY }}
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
if: contains(inputs.push_to_images, 'tootsuite')
|
||||
@@ -76,8 +65,91 @@ jobs:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- uses: docker/metadata-action@v5
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
if: ${{ inputs.push_to_images != '' }}
|
||||
with:
|
||||
images: ${{ inputs.push_to_images }}
|
||||
flavor: ${{ inputs.flavor }}
|
||||
labels: ${{ inputs.labels }}
|
||||
|
||||
- name: Build and push by digest
|
||||
id: build
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ${{ inputs.file_to_build }}
|
||||
build-args: |
|
||||
MASTODON_VERSION_PRERELEASE=${{ inputs.version_prerelease }}
|
||||
MASTODON_VERSION_METADATA=${{ inputs.version_metadata }}
|
||||
SOURCE_COMMIT=${{ github.sha }}
|
||||
platforms: ${{ matrix.platform }}
|
||||
provenance: false
|
||||
push: ${{ inputs.push_to_images != '' }}
|
||||
cache-from: ${{ inputs.cache && 'type=gha' || '' }}
|
||||
cache-to: ${{ inputs.cache && 'type=gha,mode=max' || '' }}
|
||||
outputs: type=image,"name=${{ env.IMAGE_NAMES }}",push-by-digest=true,name-canonical=true,push=${{ inputs.push_to_images != '' }}
|
||||
|
||||
- name: Export digest
|
||||
if: ${{ inputs.push_to_images != '' }}
|
||||
run: |
|
||||
mkdir -p "${{ runner.temp }}/digests"
|
||||
digest="${{ steps.build.outputs.digest }}"
|
||||
touch "${{ runner.temp }}/digests/${digest#sha256:}"
|
||||
|
||||
- name: Upload digest
|
||||
if: ${{ inputs.push_to_images != '' }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
# `hashFiles` is used to disambiguate between streaming and non-streaming images
|
||||
name: digests-${{ hashFiles(inputs.file_to_build) }}-${{ env.PLATFORM_PAIR }}
|
||||
path: ${{ runner.temp }}/digests/*
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
# Then merge the docker images into a single one
|
||||
merge-images:
|
||||
if: ${{ inputs.push_to_images != '' }}
|
||||
runs-on: ubuntu-24.04
|
||||
needs:
|
||||
- build-image
|
||||
|
||||
env:
|
||||
PUSH_TO_IMAGES: ${{ inputs.push_to_images }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Download digests
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ${{ runner.temp }}/digests
|
||||
# `hashFiles` is used to disambiguate between streaming and non-streaming images
|
||||
pattern: digests-${{ hashFiles(inputs.file_to_build) }}-*
|
||||
merge-multiple: true
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
if: contains(inputs.push_to_images, 'tootsuite')
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Log in to the GitHub Container registry
|
||||
if: contains(inputs.push_to_images, 'ghcr.io')
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
if: ${{ inputs.push_to_images != '' }}
|
||||
with:
|
||||
images: ${{ inputs.push_to_images }}
|
||||
@@ -85,18 +157,14 @@ jobs:
|
||||
tags: ${{ inputs.tags }}
|
||||
labels: ${{ inputs.labels }}
|
||||
|
||||
- uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ${{ inputs.file_to_build }}
|
||||
build-args: |
|
||||
MASTODON_VERSION_PRERELEASE=${{ inputs.version_prerelease }}
|
||||
MASTODON_VERSION_METADATA=${{ inputs.version_metadata }}
|
||||
platforms: ${{ inputs.platforms }}
|
||||
provenance: false
|
||||
builder: ${{ steps.buildx.outputs.name || steps.buildx-native.outputs.name }}
|
||||
push: ${{ inputs.push_to_images != '' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: ${{ inputs.cache && 'type=gha' || '' }}
|
||||
cache-to: ${{ inputs.cache && 'type=gha,mode=max' || '' }}
|
||||
- name: Create manifest list and push
|
||||
working-directory: ${{ runner.temp }}/digests
|
||||
run: |
|
||||
echo "$PUSH_TO_IMAGES" | xargs -I{} \
|
||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
||||
$(printf '{}@sha256:%s ' *)
|
||||
|
||||
- name: Inspect image
|
||||
run: |
|
||||
echo "$PUSH_TO_IMAGES" | xargs -i{} \
|
||||
docker buildx imagetools inspect {}:${{ steps.meta.outputs.version }}
|
||||
|
||||
4
.github/workflows/build-nightly.yml
vendored
4
.github/workflows/build-nightly.yml
vendored
@@ -26,8 +26,6 @@ jobs:
|
||||
uses: ./.github/workflows/build-container-image.yml
|
||||
with:
|
||||
file_to_build: Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
use_native_arm64_builder: false
|
||||
cache: false
|
||||
push_to_images: |
|
||||
ghcr.io/${{ github.repository_owner }}/mastodon
|
||||
@@ -47,8 +45,6 @@ jobs:
|
||||
uses: ./.github/workflows/build-container-image.yml
|
||||
with:
|
||||
file_to_build: streaming/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
use_native_arm64_builder: false
|
||||
cache: false
|
||||
push_to_images: |
|
||||
ghcr.io/${{ github.repository_owner }}/mastodon-streaming
|
||||
|
||||
10
.github/workflows/build-push-pr.yml
vendored
10
.github/workflows/build-push-pr.yml
vendored
@@ -21,17 +21,17 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
- id: version_vars
|
||||
run: |
|
||||
echo mastodon_version_metadata=pr-${{ github.event.pull_request.number }}-$(git rev-parse --short HEAD) >> $GITHUB_OUTPUT
|
||||
echo mastodon_version_metadata=pr-${{ github.event.pull_request.number }}-$(git rev-parse --short ${{github.event.pull_request.head.sha}}) >> $GITHUB_OUTPUT
|
||||
echo mastodon_short_sha=$(git rev-parse --short ${{github.event.pull_request.head.sha}}) >> $GITHUB_OUTPUT
|
||||
outputs:
|
||||
metadata: ${{ steps.version_vars.outputs.mastodon_version_metadata }}
|
||||
short_sha: ${{ steps.version_vars.outputs.mastodon_short_sha }}
|
||||
|
||||
build-image:
|
||||
needs: compute-suffix
|
||||
uses: ./.github/workflows/build-container-image.yml
|
||||
with:
|
||||
file_to_build: Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
use_native_arm64_builder: false
|
||||
push_to_images: |
|
||||
ghcr.io/${{ github.repository_owner }}/mastodon
|
||||
version_metadata: ${{ needs.compute-suffix.outputs.metadata }}
|
||||
@@ -39,6 +39,7 @@ jobs:
|
||||
latest=auto
|
||||
tags: |
|
||||
type=ref,event=pr
|
||||
type=ref,event=pr,suffix=-${{ needs.compute-suffix.outputs.short_sha }}
|
||||
secrets: inherit
|
||||
|
||||
build-image-streaming:
|
||||
@@ -46,8 +47,6 @@ jobs:
|
||||
uses: ./.github/workflows/build-container-image.yml
|
||||
with:
|
||||
file_to_build: streaming/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
use_native_arm64_builder: false
|
||||
push_to_images: |
|
||||
ghcr.io/${{ github.repository_owner }}/mastodon-streaming
|
||||
version_metadata: ${{ needs.compute-suffix.outputs.metadata }}
|
||||
@@ -55,4 +54,5 @@ jobs:
|
||||
latest=auto
|
||||
tags: |
|
||||
type=ref,event=pr
|
||||
type=ref,event=pr,suffix=-${{ needs.compute-suffix.outputs.short_sha }}
|
||||
secrets: inherit
|
||||
|
||||
8
.github/workflows/build-releases.yml
vendored
8
.github/workflows/build-releases.yml
vendored
@@ -13,8 +13,6 @@ jobs:
|
||||
uses: ./.github/workflows/build-container-image.yml
|
||||
with:
|
||||
file_to_build: Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
use_native_arm64_builder: false
|
||||
push_to_images: |
|
||||
ghcr.io/${{ github.repository_owner }}/mastodon
|
||||
# Do not use cache when building releases, so apt update is always ran and the release always contain the latest packages
|
||||
@@ -22,7 +20,7 @@ jobs:
|
||||
# Only tag with latest when ran against the latest stable branch
|
||||
# This needs to be updated after each minor version release
|
||||
flavor: |
|
||||
latest=${{ startsWith(github.ref, 'refs/tags/v4.2.') }}
|
||||
latest=false
|
||||
tags: |
|
||||
type=pep440,pattern={{raw}}
|
||||
type=pep440,pattern=v{{major}}.{{minor}}
|
||||
@@ -33,8 +31,6 @@ jobs:
|
||||
uses: ./.github/workflows/build-container-image.yml
|
||||
with:
|
||||
file_to_build: streaming/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
use_native_arm64_builder: false
|
||||
push_to_images: |
|
||||
ghcr.io/${{ github.repository_owner }}/mastodon-streaming
|
||||
# Do not use cache when building releases, so apt update is always ran and the release always contain the latest packages
|
||||
@@ -42,7 +38,7 @@ jobs:
|
||||
# Only tag with latest when ran against the latest stable branch
|
||||
# This needs to be updated after each minor version release
|
||||
flavor: |
|
||||
latest=${{ startsWith(github.ref, 'refs/tags/v4.3.') }}
|
||||
latest=false
|
||||
tags: |
|
||||
type=pep440,pattern={{raw}}
|
||||
type=pep440,pattern=v{{major}}.{{minor}}
|
||||
|
||||
4
.github/workflows/build-security.yml
vendored
4
.github/workflows/build-security.yml
vendored
@@ -23,8 +23,6 @@ jobs:
|
||||
uses: ./.github/workflows/build-container-image.yml
|
||||
with:
|
||||
file_to_build: Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
use_native_arm64_builder: false
|
||||
cache: false
|
||||
push_to_images: |
|
||||
ghcr.io/${{ github.repository_owner }}/mastodon
|
||||
@@ -44,8 +42,6 @@ jobs:
|
||||
uses: ./.github/workflows/build-container-image.yml
|
||||
with:
|
||||
file_to_build: streaming/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
use_native_arm64_builder: false
|
||||
cache: false
|
||||
push_to_images: |
|
||||
ghcr.io/${{ github.repository_owner }}/mastodon-streaming
|
||||
|
||||
70
.github/workflows/crowdin-download-stable.yml
vendored
Normal file
70
.github/workflows/crowdin-download-stable.yml
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
name: Crowdin / Download translations (stable branches)
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
download-translations-stable:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'glitch-soc/mastodon'
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Increase Git http.postBuffer
|
||||
# This is needed due to a bug in Ubuntu's cURL version?
|
||||
# See https://github.com/orgs/community/discussions/55820
|
||||
run: |
|
||||
git config --global http.version HTTP/1.1
|
||||
git config --global http.postBuffer 157286400
|
||||
|
||||
# Download the translation files from Crowdin
|
||||
- name: crowdin action
|
||||
uses: crowdin/github-action@v2
|
||||
with:
|
||||
config: crowdin-glitch.yml
|
||||
upload_sources: false
|
||||
upload_translations: false
|
||||
download_translations: true
|
||||
crowdin_branch_name: ${{ github.base_ref || github.ref_name }}
|
||||
push_translations: false
|
||||
create_pull_request: false
|
||||
env:
|
||||
CROWDIN_PROJECT_ID: ${{ vars.CROWDIN_PROJECT_ID }}
|
||||
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
||||
|
||||
# As the files are extracted from a Docker container, they belong to root:root
|
||||
# We need to fix this before the next steps
|
||||
- name: Fix file permissions
|
||||
run: sudo chown -R runner:docker .
|
||||
|
||||
# This is needed to run the normalize step
|
||||
- name: Set up Ruby environment
|
||||
uses: ./.github/actions/setup-ruby
|
||||
|
||||
- name: Run i18n normalize task
|
||||
run: bundle exec i18n-tasks normalize
|
||||
|
||||
# Create or update the pull request
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v7.0.5
|
||||
with:
|
||||
commit-message: 'New Crowdin translations'
|
||||
title: 'New Crowdin Translations for ${{ github.base_ref || github.ref_name }} (automated)'
|
||||
author: 'GitHub Actions <noreply@github.com>'
|
||||
body: |
|
||||
New Crowdin translations, automated with GitHub Actions
|
||||
|
||||
See `.github/workflows/crowdin-download.yml`
|
||||
|
||||
This PR will be updated every day with new translations.
|
||||
|
||||
Due to a limitation in GitHub Actions, checks are not running on this PR without manual action.
|
||||
If you want to run the checks, then close and re-open it.
|
||||
branch: i18n/crowdin/translations-${{ github.base_ref || github.ref_name }}
|
||||
base: ${{ github.base_ref || github.ref_name }}
|
||||
labels: i18n
|
||||
2
.github/workflows/crowdin-download.yml
vendored
2
.github/workflows/crowdin-download.yml
vendored
@@ -53,7 +53,7 @@ jobs:
|
||||
|
||||
# Create or update the pull request
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v7.0.1
|
||||
uses: peter-evans/create-pull-request@v7.0.5
|
||||
with:
|
||||
commit-message: 'New Crowdin translations'
|
||||
title: 'New Crowdin Translations (automated)'
|
||||
|
||||
3
.github/workflows/crowdin-upload.yml
vendored
3
.github/workflows/crowdin-upload.yml
vendored
@@ -1,7 +1,6 @@
|
||||
name: Crowdin / Upload translations
|
||||
|
||||
on:
|
||||
merge_group:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
@@ -32,7 +31,7 @@ jobs:
|
||||
upload_sources: true
|
||||
upload_translations: false
|
||||
download_translations: false
|
||||
crowdin_branch_name: main
|
||||
crowdin_branch_name: ${{ github.base_ref || github.ref_name }}
|
||||
|
||||
env:
|
||||
CROWDIN_PROJECT_ID: ${{ vars.CROWDIN_PROJECT_ID }}
|
||||
|
||||
2
.github/workflows/test-image-build.yml
vendored
2
.github/workflows/test-image-build.yml
vendored
@@ -20,7 +20,6 @@ jobs:
|
||||
uses: ./.github/workflows/build-container-image.yml
|
||||
with:
|
||||
file_to_build: Dockerfile
|
||||
platforms: linux/amd64 # Testing only on native platform so it is performant
|
||||
cache: true
|
||||
|
||||
build-image-streaming:
|
||||
@@ -31,5 +30,4 @@ jobs:
|
||||
uses: ./.github/workflows/build-container-image.yml
|
||||
with:
|
||||
file_to_build: streaming/Dockerfile
|
||||
platforms: linux/amd64 # Testing only on native platform so it is performant
|
||||
cache: true
|
||||
|
||||
2
.github/workflows/test-migrations.yml
vendored
2
.github/workflows/test-migrations.yml
vendored
@@ -32,6 +32,8 @@ jobs:
|
||||
postgres:
|
||||
- 14-alpine
|
||||
- 15-alpine
|
||||
- 16-alpine
|
||||
- 17-alpine
|
||||
|
||||
services:
|
||||
postgres:
|
||||
|
||||
12
.github/workflows/test-ruby.yml
vendored
12
.github/workflows/test-ruby.yml
vendored
@@ -127,6 +127,7 @@ jobs:
|
||||
- '3.1'
|
||||
- '3.2'
|
||||
- '.ruby-version'
|
||||
- '3.4'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -143,7 +144,7 @@ jobs:
|
||||
uses: ./.github/actions/setup-ruby
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby-version}}
|
||||
additional-system-dependencies: ffmpeg libpam-dev
|
||||
additional-system-dependencies: ffmpeg imagemagick libpam-dev
|
||||
|
||||
- name: Load database schema
|
||||
run: |
|
||||
@@ -229,6 +230,7 @@ jobs:
|
||||
- '3.1'
|
||||
- '3.2'
|
||||
- '.ruby-version'
|
||||
- '3.4'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -245,7 +247,7 @@ jobs:
|
||||
uses: ./.github/actions/setup-ruby
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby-version}}
|
||||
additional-system-dependencies: ffmpeg libpam-dev libyaml-dev
|
||||
additional-system-dependencies: ffmpeg libpam-dev
|
||||
|
||||
- name: Load database schema
|
||||
run: './bin/rails db:create db:schema:load db:seed'
|
||||
@@ -308,6 +310,7 @@ jobs:
|
||||
- '3.1'
|
||||
- '3.2'
|
||||
- '.ruby-version'
|
||||
- '3.4'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -325,7 +328,7 @@ jobs:
|
||||
uses: ./.github/actions/setup-ruby
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby-version}}
|
||||
additional-system-dependencies: ffmpeg
|
||||
additional-system-dependencies: ffmpeg imagemagick
|
||||
|
||||
- name: Set up Javascript environment
|
||||
uses: ./.github/actions/setup-javascript
|
||||
@@ -425,6 +428,7 @@ jobs:
|
||||
- '3.1'
|
||||
- '3.2'
|
||||
- '.ruby-version'
|
||||
- '3.4'
|
||||
search-image:
|
||||
- docker.elastic.co/elasticsearch/elasticsearch:7.17.13
|
||||
include:
|
||||
@@ -445,7 +449,7 @@ jobs:
|
||||
uses: ./.github/actions/setup-ruby
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby-version}}
|
||||
additional-system-dependencies: ffmpeg
|
||||
additional-system-dependencies: ffmpeg imagemagick
|
||||
|
||||
- name: Set up Javascript environment
|
||||
uses: ./.github/actions/setup-javascript
|
||||
|
||||
323
CHANGELOG.md
323
CHANGELOG.md
@@ -2,7 +2,300 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [4.3.0] - UNRELEASED
|
||||
## [4.3.15] - 2025-11-20
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix `tootctl upgrade storage-schema` failing with `ArgumentError` (#36914 by @shugo)
|
||||
- Fix old previously-undiscovered posts being treated as new when receiving an `Update` (#36848 by @ClearlyClaire)
|
||||
|
||||
## [4.3.14] - 2025-10-13
|
||||
|
||||
### Security
|
||||
|
||||
- Update dependencies `rack` and `uri`
|
||||
- Fix streaming server connection not being closed on user suspension (by @ThisIsMissEm, [GHSA-r2fh-jr9c-9pxh](https://github.com/mastodon/mastodon/security/advisories/GHSA-r2fh-jr9c-9pxh))
|
||||
- Fix password change through admin CLI not invalidating existing sessions and access tokens (by @ThisIsMissEm, [GHSA-f3q3-rmf7-9655](https://github.com/mastodon/mastodon/security/advisories/GHSA-f3q3-rmf7-9655))
|
||||
- Fix streaming server allowing access to public timelines even without the `read` or `read:statuses` OAuth scopes (by @ThisIsMissEm, [GHSA-7gwh-mw97-qjgp](https://github.com/mastodon/mastodon/security/advisories/GHSA-7gwh-mw97-qjgp))
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix redirect to external object when URL is missing or malformed (#36347 by @ClearlyClaire)
|
||||
|
||||
## [4.3.13] - 2025-09-23
|
||||
|
||||
### Security
|
||||
|
||||
- Update dependencies
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix processing of out-of-order `Update` as implicit updates (#36190 by @ClearlyClaire)
|
||||
- Fix getting `Create` and `Update` out of order (#36176 by @ClearlyClaire)
|
||||
|
||||
## [4.3.12] - 2025-09-16
|
||||
|
||||
### Security
|
||||
|
||||
- Update dependencies
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix processing of remote edited statuses with new media and no text (#35970 by @unfokus)
|
||||
- Fix “Edit” and “Delete & Redraft” on a poll not inserting empty option (#35892 by @ClearlyClaire)
|
||||
- Fix self-destruct scheduler behavior on some Redis setups (#35823 by @ClearlyClaire)
|
||||
|
||||
## [4.3.11] - 2025-08-05
|
||||
|
||||
### Security
|
||||
|
||||
- Update dependencies
|
||||
- Fix incorrect rate-limit handling [GHSA-84ch-6436-c7mg](https://github.com/mastodon/mastodon/security/advisories/GHSA-84ch-6436-c7mg)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix race condition caused by ActiveRecord query cache in `Create` critical path (#35662 by @ClearlyClaire)
|
||||
- Fix WebUI crashing for accounts with `null` URL (#35651 by @ClearlyClaire)
|
||||
- Fix friends-of-friends recommendations suggesting already-requested accounts (#35604 by @ClearlyClaire)
|
||||
|
||||
## [4.3.10] - 2025-07-23
|
||||
|
||||
### Security
|
||||
|
||||
- Updated dependencies
|
||||
|
||||
## [4.3.9] - 2025-07-02
|
||||
|
||||
### Changed
|
||||
|
||||
- Change passthrough video processing to emit `moov` atom at start of video (#34726 by @ClearlyClaire)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix `NoMethodError` in edge case of emoji cache handling (#34749 by @dariusk)
|
||||
- Fix error when viewing statuses to deleted replies in moderation view (#32986 by @ClearlyClaire)
|
||||
- Fix search operators sometimes getting lost (#35190 by @ClearlyClaire)
|
||||
- Fix “Alt text” button submitting form in moderation interface (#35147 by @ClearlyClaire)
|
||||
- Fix handling of remote attachments with multiple media types (#34996 by @ClearlyClaire)
|
||||
- Fix blocked accounts not being automatically removed from trending statuses (#34891 by @ClearlyClaire)
|
||||
- Fix inconsistent filtering of silenced accounts for other silenced accounts (#34863 by @ClearlyClaire)
|
||||
- Fix handling of inlined `featured` collections in ActivityPub actor objects (#34789 and #34811 by @ClearlyClaire)
|
||||
- Fix admin dashboard crash on specific Elasticsearch connection errors (#34683 by @ClearlyClaire)
|
||||
- Fix OIDC account creation failing for long display names (#34639 by @defnull)
|
||||
- Fix `/share` not using server-set characters limit (#33459 by @kescherCode)
|
||||
- Fix wrong video dimensions for some rotated videos (#33008 and #33261 by @Gargron and @tribela)
|
||||
- Fix missing autofocus on boost modal (#32953 by @tribela)
|
||||
|
||||
## [4.3.8] - 2025-05-06
|
||||
|
||||
### Security
|
||||
|
||||
- Update dependencies
|
||||
- Check scheme on account, profile, and media URLs ([GHSA-x2rc-v5wx-g3m5](https://github.com/mastodon/mastodon/security/advisories/GHSA-x2rc-v5wx-g3m5))
|
||||
|
||||
### Added
|
||||
|
||||
- Add warning for REDIS_NAMESPACE deprecation at startup (#34581 by @ClearlyClaire)
|
||||
- Add built-in context for interaction policies (#34574 by @ClearlyClaire)
|
||||
|
||||
### Changed
|
||||
|
||||
- Change activity distribution error handling to skip retrying for deleted accounts (#33617 by @ClearlyClaire)
|
||||
|
||||
### Removed
|
||||
|
||||
- Remove double-query for signed query strings (#34610 by @ClearlyClaire)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix incorrect redirect in response to unauthenticated API requests in limited federation mode (#34549 by @ClearlyClaire)
|
||||
- Fix sign-up e-mail confirmation page reloading on error or redirect (#34548 by @ClearlyClaire)
|
||||
|
||||
## [4.3.7] - 2025-04-02
|
||||
|
||||
### Added
|
||||
|
||||
- Add delay to profile updates to debounce them (#34137 by @ClearlyClaire)
|
||||
- Add support for paginating partial collections in `SynchronizeFollowersService` (#34272 and #34277 by @ClearlyClaire)
|
||||
|
||||
### Changed
|
||||
|
||||
- Change account suspensions to be federated to recently-followed accounts as well (#34294 by @ClearlyClaire)
|
||||
- Change `AccountReachFinder` to consider statuses based on suspension date (#32805 and #34291 by @ClearlyClaire and @mjankowski)
|
||||
- Change user archive signed URL TTL from 10 seconds to 1 hour (#34254 by @ClearlyClaire)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix static version of animated PNG emojis not being properly extracted (#34337 by @ClearlyClaire)
|
||||
- Fix filters not applying in detailed view, favourites and bookmarks (#34259 and #34260 by @ClearlyClaire)
|
||||
- Fix handling of malformed/unusual HTML (#34201 by @ClearlyClaire)
|
||||
- Fix `CacheBuster` being queued for missing media attachments (#34253 by @ClearlyClaire)
|
||||
- Fix incorrect URL being used when cache busting (#34189 by @ClearlyClaire)
|
||||
- Fix streaming server refusing unix socket path in `DATABASE_URL` (#34091 by @ClearlyClaire)
|
||||
- Fix “x” hotkey not working on boosted filtered posts (#33758 by @ClearlyClaire)
|
||||
|
||||
## [4.3.6] - 2025-03-13
|
||||
|
||||
### Security
|
||||
|
||||
- Update dependency `omniauth-saml`
|
||||
- Update dependency `rack`
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix Stoplight errors when using `REDIS_NAMESPACE` (#34126 by @ClearlyClaire)
|
||||
|
||||
## [4.3.5] - 2025-03-10
|
||||
|
||||
### Changed
|
||||
|
||||
- Change hashtag suggestion to prefer personal history capitalization (#34070 by @ClearlyClaire)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix processing errors for some HEIF images from iOS 18 (#34086 by @renchap)
|
||||
- Fix streaming server not filtering unknown-language posts from public timelines (#33774 by @ClearlyClaire)
|
||||
- Fix preview cards under Content Warnings not being shown in detailed statuses (#34068 by @ClearlyClaire)
|
||||
- Fix username and display name being hidden on narrow screens in moderation interface (#33064 by @ClearlyClaire)
|
||||
|
||||
## [4.3.4] - 2025-02-27
|
||||
|
||||
### Security
|
||||
|
||||
- Update dependencies
|
||||
- Change HTML sanitization to remove unusable and unused `embed` tag (#34021 by @ClearlyClaire, [GHSA-mq2m-hr29-8gqf](https://github.com/mastodon/mastodon/security/advisories/GHSA-mq2m-hr29-8gqf))
|
||||
- Fix rate-limit on sign-up email verification ([GHSA-v39f-c9jj-8w7h](https://github.com/mastodon/mastodon/security/advisories/GHSA-v39f-c9jj-8w7h))
|
||||
- Fix improper disclosure of domain blocks to unverified users ([GHSA-94h4-fj37-c825](https://github.com/mastodon/mastodon/security/advisories/GHSA-94h4-fj37-c825))
|
||||
|
||||
### Changed
|
||||
|
||||
- Change preview cards to be shown when Content Warnings are expanded (#33827 by @ClearlyClaire)
|
||||
- Change warnings against changing encryption secrets to be even more noticeable (#33631 by @ClearlyClaire)
|
||||
- Change `mastodon:setup` to prevent overwriting already-configured servers (#33603, #33616, and #33684 by @ClearlyClaire and @mjankowski)
|
||||
- Change notifications from moderators to not be filtered (#32974 and #33654 by @ClearlyClaire and @mjankowski)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix `GET /api/v2/notifications/:id` and `POST /api/v2/notifications/:id/dismiss` for ungrouped notifications (#33990 by @ClearlyClaire)
|
||||
- Fix issue with some versions of libvips on some systems (#33853 by @kleisauke)
|
||||
- Fix handling of duplicate mentions in incoming status `Update` (#33911 by @ClearlyClaire)
|
||||
- Fix inefficiencies in timeline generation (#33839 and #33842 by @ClearlyClaire)
|
||||
- Fix emoji rewrite adding unnecessary curft to the DOM for most emoji (#33818 by @ClearlyClaire)
|
||||
- Fix `tootctl feeds build` not building list timelines (#33783 by @ClearlyClaire)
|
||||
- Fix flaky test in `/api/v2/notifications` tests (#33773 by @ClearlyClaire)
|
||||
- Fix incorrect signature after HTTP redirect (#33757 and #33769 by @ClearlyClaire)
|
||||
- Fix polls not being validated on edition (#33755 by @ClearlyClaire)
|
||||
- Fix media preview height in compose form when 3 or more images are attached (#33571 by @ClearlyClaire)
|
||||
- Fix preview card sizing in “Author attribution” in profile settings (#33482 by @ClearlyClaire)
|
||||
- Fix processing of incoming notifications for unfilterable types (#33429 by @ClearlyClaire)
|
||||
- Fix featured tags for remote accounts not being kept up to date (#33372, #33406, and #33425 by @ClearlyClaire and @mjankowski)
|
||||
- Fix notification polling showing a loading bar in web UI (#32960 by @Gargron)
|
||||
- Fix accounts table long display name (#29316 by @WebCoder49)
|
||||
- Fix exclusive lists interfering with notifications (#28162 by @ShadowJonathan)
|
||||
|
||||
## [4.3.3] - 2025-01-16
|
||||
|
||||
### Security
|
||||
|
||||
- Fix insufficient validation of account URIs ([GHSA-5wxh-3p65-r4g6](https://github.com/mastodon/mastodon/security/advisories/GHSA-5wxh-3p65-r4g6))
|
||||
- Update dependencies
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix `libyaml` missing from `Dockerfile` build stage (#33591 by @vmstan)
|
||||
- Fix incorrect notification settings migration for non-followers (#33348 by @ClearlyClaire)
|
||||
- Fix down clause for notification policy v2 migrations (#33340 by @jesseplusplus)
|
||||
- Fix error decrementing status count when `FeaturedTags#last_status_at` is `nil` (#33320 by @ClearlyClaire)
|
||||
- Fix last paginated notification group only including data on a single notification (#33271 by @ClearlyClaire)
|
||||
- Fix processing of mentions for post edits with an existing corresponding silent mention (#33227 by @ClearlyClaire)
|
||||
- Fix deletion of unconfirmed users with Webauthn set (#33186 by @ClearlyClaire)
|
||||
- Fix empty authors preview card serialization (#33151, #33466 by @mjankowski and @ClearlyClaire)
|
||||
|
||||
## [4.3.2] - 2024-12-03
|
||||
|
||||
### Added
|
||||
|
||||
- Add `tootctl feeds vacuum` (#33065 by @ClearlyClaire)
|
||||
- Add error message when user tries to follow their own account (#31910 by @lenikadali)
|
||||
- Add client_secret_expires_at to OAuth Applications (#30317 by @ThisIsMissEm)
|
||||
|
||||
### Changed
|
||||
|
||||
- Change design of Content Warnings and filters (#32543 by @ClearlyClaire)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix processing incoming post edits with mentions to unresolvable accounts (#33129 by @ClearlyClaire)
|
||||
- Fix error when including multiple instances of `embed.js` (#33107 by @YKWeyer)
|
||||
- Fix inactive users' timelines being backfilled on follow and unsuspend (#33094 by @ClearlyClaire)
|
||||
- Fix direct inbox delivery pushing posts into inactive followers' timelines (#33067 by @ClearlyClaire)
|
||||
- Fix `TagFollow` records not being correctly handled in account operations (#33063 by @ClearlyClaire)
|
||||
- Fix pushing hashtag-followed posts to feeds of inactive users (#33018 by @Gargron)
|
||||
- Fix duplicate notifications in notification groups when using slow mode (#33014 by @ClearlyClaire)
|
||||
- Fix posts made in the future being allowed to trend (#32996 by @ClearlyClaire)
|
||||
- Fix uploading higher-than-wide GIF profile picture with libvips enabled (#32911 by @ClearlyClaire)
|
||||
- Fix domain attribution field having autocorrect and autocapitalize enabled (#32903 by @ClearlyClaire)
|
||||
- Fix titles being escaped twice (#32889 by @ClearlyClaire)
|
||||
- Fix list creation limit check (#32869 by @ClearlyClaire)
|
||||
- Fix error in `tootctl email_domain_blocks` when supplying `--with-dns-records` (#32863 by @mjankowski)
|
||||
- Fix `min_id` and `max_id` causing error in search API (#32857 by @Gargron)
|
||||
- Fix inefficiencies when processing removal of posts that use featured tags (#32787 by @ClearlyClaire)
|
||||
- Fix alt-text pop-in not using the translated description (#32766 by @ClearlyClaire)
|
||||
- Fix preview cards with long titles erroneously causing layout changes (#32678 by @ClearlyClaire)
|
||||
- Fix embed modal layout on mobile (#32641 by @DismalShadowX)
|
||||
- Fix and improve batch attachment deletion handling when using OpenStack Swift (#32637 by @hugogameiro)
|
||||
- Fix blocks not being applied on link timeline (#32625 by @tribela)
|
||||
- Fix follow counters being incorrectly changed (#32622 by @oneiros)
|
||||
- Fix 'unknown' media attachment type rendering (#32613 and #32713 by @ThisIsMissEm and @renatolond)
|
||||
- Fix tl language native name (#32606 by @seav)
|
||||
|
||||
### Security
|
||||
|
||||
- Update dependencies
|
||||
|
||||
## [4.3.1] - 2024-10-21
|
||||
|
||||
### Added
|
||||
|
||||
- Add more explicit explanations about author attribution and `fediverse:creator` (#32383 by @ClearlyClaire)
|
||||
- Add ability to group follow notifications in WebUI, can be disabled in the column settings (#32520 by @renchap)
|
||||
- Add back a 6 hours mute duration option (#32522 by @renchap)
|
||||
- Add note about not changing ActiveRecord encryption secrets once they are set (#32413, #32476, #32512, and #32537 by @ClearlyClaire and @mjankowski)
|
||||
|
||||
### Changed
|
||||
|
||||
- Change translation feature to translate to selected regional variant (e.g. pt-BR) if available (#32428 by @c960657)
|
||||
|
||||
### Removed
|
||||
|
||||
- Remove ability to get embed code for remote posts (#32578 by @ClearlyClaire)\
|
||||
Getting the embed code is only reliable for local posts.\
|
||||
It never worked for non-Mastodon servers, and stopped working correctly with the changes made in 4.3.0.\
|
||||
We have therefore decided to remove the menu entry while we investigate solutions.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix follow recommendation moderation page default language when using regional variant (#32580 by @ClearlyClaire)
|
||||
- Fix column-settings spacing in local timeline in advanced view (#32567 by @lindwurm)
|
||||
- Fix broken i18n in text welcome mailer tags area (#32571 by @mjankowski)
|
||||
- Fix missing or incorrect cache-control headers for Streaming server (#32551 by @ThisIsMissEm)
|
||||
- Fix only the first paragraph being displayed in some notifications (#32348 by @ClearlyClaire)
|
||||
- Fix reblog icons on account media view (#32506 by @tribela)
|
||||
- Fix Content-Security-Policy not allowing OpenStack SWIFT object storage URI (#32439 by @kenkiku1021)
|
||||
- Fix back arrow pointing to the incorrect direction in RTL languages (#32485 by @renchap)
|
||||
- Fix streaming server using `REDIS_USERNAME` instead of `REDIS_USER` (#32493 by @ThisIsMissEm)
|
||||
- Fix follow recommendation carrousel scrolling on RTL layouts (#32462 and #32505 by @ClearlyClaire)
|
||||
- Fix follow recommendation suppressions not applying immediately (#32392 by @ClearlyClaire)
|
||||
- Fix language of push notifications (#32415 by @ClearlyClaire)
|
||||
- Fix mute duration not being shown in list of muted accounts in web UI (#32388 by @ClearlyClaire)
|
||||
- Fix “Mark every notification as read” not updating the read marker if scrolled down (#32385 by @ClearlyClaire)
|
||||
- Fix “Mention” appearing for otherwise filtered posts (#32356 by @ClearlyClaire)
|
||||
- Fix notification requests from suspended accounts still being listed (#32354 by @ClearlyClaire)
|
||||
- Fix list edition modal styling (#32358 and #32367 by @ClearlyClaire and @vmstan)
|
||||
- Fix 4 columns barely not fitting on 1920px screen (#32361 by @ClearlyClaire)
|
||||
- Fix icon alignment in applications list (#32293 by @mjankowski)
|
||||
|
||||
## [4.3.0] - 2024-10-08
|
||||
|
||||
The following changelog entries focus on changes visible to users, administrators, client developers or federated software developers, but there has also been a lot of code modernization, refactoring, and tooling work, in particular by @mjankowski.
|
||||
|
||||
@@ -11,12 +304,12 @@ The following changelog entries focus on changes visible to users, administrator
|
||||
- **Add confirmation interstitial instead of silently redirecting logged-out visitors to remote resources** (#27792, #28902, and #30651 by @ClearlyClaire and @Gargron)\
|
||||
This fixes a longstanding open redirect in Mastodon, at the cost of added friction when local links to remote resources are shared.
|
||||
- Fix ReDoS vulnerability on some Ruby versions ([GHSA-jpxp-r43f-rhvx](https://github.com/mastodon/mastodon/security/advisories/GHSA-jpxp-r43f-rhvx))
|
||||
- Change `form-action` Content-Security-Policy directive to be more restrictive (#26897 by @ClearlyClaire)
|
||||
- Change `form-action` Content-Security-Policy directive to be more restrictive (#26897 and #32241 by @ClearlyClaire)
|
||||
- Update dependencies
|
||||
|
||||
### Added
|
||||
|
||||
- **Add server-side notification grouping** (#29889, #30576, #30685, #30688, #30707, #30776, #30779, #30781, #30440, #31062, #31098, #31076, #31111, #31123, #31223, #31214, #31224, #31299, #31325, #31347, #31304, #31326, #31384, #31403, #31433, #31509, #31486, #31513, #31592, #31594, #31638, #31746, #31652, #31709, #31725, #31745, #31613, #31657, #31840, #31610, #31929, #32089 and #32085 by @ClearlyClaire, @Gargron, @mgmn, and @renchap)\
|
||||
- **Add server-side notification grouping** (#29889, #30576, #30685, #30688, #30707, #30776, #30779, #30781, #30440, #31062, #31098, #31076, #31111, #31123, #31223, #31214, #31224, #31299, #31325, #31347, #31304, #31326, #31384, #31403, #31433, #31509, #31486, #31513, #31592, #31594, #31638, #31746, #31652, #31709, #31725, #31745, #31613, #31657, #31840, #31610, #31929, #32089, #32085, #32243, #32179 and #32254 by @ClearlyClaire, @Gargron, @mgmn, and @renchap)\
|
||||
Group notifications of the same type for the same target, so that your notifications no longer get cluttered by boost and favorite notifications as soon as a couple of your posts get traction.\
|
||||
This is done server-side so that clients can efficiently get relevant groups without having to go through numerous pages of individual notifications.\
|
||||
As part of this, the visual design of the entire notifications feature has been revamped.\
|
||||
@@ -28,7 +321,7 @@ The following changelog entries focus on changes visible to users, administrator
|
||||
- `GET /api/v2/notifications/:group_key/accounts`: https://docs.joinmastodon.org/methods/grouped_notifications/#get-group-accounts
|
||||
- `POST /api/v2/notifications/:group_key/dimsiss`: https://docs.joinmastodon.org/methods/grouped_notifications/#dismiss-group
|
||||
- `GET /api/v2/notifications/:unread_count`: https://docs.joinmastodon.org/methods/grouped_notifications/#unread-group-count
|
||||
- **Add notification policies, filtered notifications and notification requests** (#29366, #29529, #29433, #29565, #29567, #29572, #29575, #29588, #29646, #29652, #29658, #29666, #29693, #29699, #29737, #29706, #29570, #29752, #29810, #29826, #30114, #30251, #30559, #29868, #31008, #31011, #30996, #31149, #31220, #31222, #31225, #31242, #31262, #31250, #31273, #31310, #31316, #31322, #31329, #31324, #31331, #31343, #31342, #31309, #31358, #31378, #31406, #31256, #31456, #31419, #31457, #31508, #31540, #31541, #31723 and #32062 by @ClearlyClaire, @Gargron, @TheEssem, @mgmn, @oneiros, and @renchap)\
|
||||
- **Add notification policies, filtered notifications and notification requests** (#29366, #29529, #29433, #29565, #29567, #29572, #29575, #29588, #29646, #29652, #29658, #29666, #29693, #29699, #29737, #29706, #29570, #29752, #29810, #29826, #30114, #30251, #30559, #29868, #31008, #31011, #30996, #31149, #31220, #31222, #31225, #31242, #31262, #31250, #31273, #31310, #31316, #31322, #31329, #31324, #31331, #31343, #31342, #31309, #31358, #31378, #31406, #31256, #31456, #31419, #31457, #31508, #31540, #31541, #31723, #32062 and #32281 by @ClearlyClaire, @Gargron, @TheEssem, @mgmn, @oneiros, and @renchap)\
|
||||
The old “Block notifications from non-followers”, “Block notifications from people you don't follow” and “Block direct messages from people you don't follow” notification settings have been replaced by a new set of settings found directly in the notification column.\
|
||||
You can now separately filter or drop notifications from people you don't follow, people who don't follow you, accounts created within the past 30 days, as well as unsolicited private mentions, and accounts limited by the moderation.\
|
||||
Instead of being outright dropped, notifications that you chose to filter are put in a separate “Filtered notifications” box that you can review separately without it clogging your main notifications.\
|
||||
@@ -51,7 +344,7 @@ The following changelog entries focus on changes visible to users, administrator
|
||||
- **Add notifications of severed relationships** (#27511, #29665, #29668, #29670, #29700, #29714, #29712, and #29731 by @ClearlyClaire and @Gargron)\
|
||||
Notify local users when they lose relationships as a result of a local moderator blocking a remote account or server, allowing the affected user to retrieve the list of broken relationships.\
|
||||
Note that this does not notify remote users.\
|
||||
This adds the `severed_relationships` notification type to the REST API and streaming, with a new [`relationship_severance_event` attribute](https://docs.joinmastodon.org/entities/Notification/#relationship_severance_event).
|
||||
This adds the `severed_relationships` notification type to the REST API and streaming, with a new [`event` attribute](https://docs.joinmastodon.org/entities/Notification/#relationship_severance_event).
|
||||
- **Add hover cards in web UI** (#30754, #30864, #30850, #30879, #30928, #30949, #30948, #30931, and #31300 by @ClearlyClaire, @Gargron, and @renchap)\
|
||||
Hovering over an avatar or username will now display a hover card with the first two lines of the user's description and their first two profile fields.\
|
||||
This can be disabled in the “Animations and accessibility” section of the preferences.
|
||||
@@ -61,13 +354,13 @@ The following changelog entries focus on changes visible to users, administrator
|
||||
- **Add timeline of public posts about a trending link** (#30381 and #30840 by @Gargron)\
|
||||
You can now see public posts mentioning currently-trending articles from people who have opted into discovery features.\
|
||||
This adds a new REST API endpoint: https://docs.joinmastodon.org/methods/timelines/#link
|
||||
- **Add author highlight for news articles whose authors are on the fediverse** (#30398, #30670, #30521, #30846, #31819, and #31900 by @Gargron and @oneiros)\
|
||||
- **Add author highlight for news articles whose authors are on the fediverse** (#30398, #30670, #30521, #30846, #31819, #31900 and #32188 by @Gargron, @mjankowski and @oneiros)\
|
||||
This adds a mechanism to [highlight the author of news articles](https://blog.joinmastodon.org/2024/07/highlighting-journalism-on-mastodon/) shared on Mastodon.\
|
||||
Articles hosted outside the fediverse can indicate a fediverse author with a meta tag:
|
||||
```html
|
||||
<meta name="fediverse:creator" content="username@domain" />
|
||||
```
|
||||
On the API side, this is represented by a new `authors` attribute to the `PreviewCard` entity: https://docs.joinmastodon.org/entities/PreviewCard/#authors\
|
||||
On the API side, this is represented by a new `authors` attribute to the `PreviewCard` entity: https://docs.joinmastodon.org/entities/PreviewCard/#authors \
|
||||
Users can allow arbitrary domains to use `fediverse:creator` to credit them by visiting `/settings/verification`.\
|
||||
This is federated as a new `attributionDomains` property in the `http://joinmastodon.org/ns` namespace, containing an array of domain names: https://docs.joinmastodon.org/spec/activitypub/#properties-used-1
|
||||
- **Add in-app notifications for moderation actions and warnings** (#30065, #30082, and #30081 by @ClearlyClaire)\
|
||||
@@ -150,10 +443,12 @@ The following changelog entries focus on changes visible to users, administrator
|
||||
- Add groundwork for annual reports for accounts (#28693 by @Gargron)\
|
||||
This lays the groundwork for a “year-in-review”/“wrapped” style report for local users, but is currently not in use.
|
||||
- Add notification email on invalid second authenticator (#28822 by @ClearlyClaire)
|
||||
- Add date of account deletion in list of accounts in the admin interface (#25640 by @tribela)
|
||||
- Add new emojis from `jdecked/twemoji` 15.0 (#28404 by @TheEssem)
|
||||
- Add configurable error handling in attachment batch deletion (#28184 by @vmstan)\
|
||||
This makes the S3 batch size configurable through the `S3_BATCH_DELETE_LIMIT` environment variable (defaults to 1000), and adds some retry logic, configurable through the `S3_BATCH_DELETE_RETRY` environment variable (defaults to 3).
|
||||
- Add VAPID public key to instance serializer (#28006 by @ThisIsMissEm)
|
||||
- Add support for serving JRD `/.well-known/host-meta.json` in addition to XRD host-meta (#32206 by @c960657)
|
||||
- Add `nodeName` and `nodeDescription` to nodeinfo `metadata` (#28079 by @6543)
|
||||
- Add Thai diacritics and tone marks in `HASHTAG_INVALID_CHARS_RE` (#26576 by @ppnplus)
|
||||
- Add variable delay before link verification of remote account links (#27774 by @ClearlyClaire)
|
||||
@@ -168,7 +463,7 @@ The following changelog entries focus on changes visible to users, administrator
|
||||
|
||||
### Changed
|
||||
|
||||
- **Change icons throughout the web interface** (#27385, #27539, #27555, #27579, #27700, #27817, #28519, #28709, #28064, #28775, #28780, #27924, #29294, #29395, #29537, #29569, #29610, #29612, #29649, #29844, #27780, #30974, #30963, #30962, #30961, #31362, #31363, #31359, #31371, #31360, #31512, #31511, and #31525 by @ClearlyClaire, @Gargron, @arbolitoloco1, @mjankowski, @nclm, @renchap, @ronilaukkarinen, and @zunda)\
|
||||
- **Change icons throughout the web interface** (#27385, #27539, #27555, #27579, #27700, #27817, #28519, #28709, #28064, #28775, #28780, #27924, #29294, #29395, #29537, #29569, #29610, #29612, #29649, #29844, #27780, #30974, #30963, #30962, #30961, #31362, #31363, #31359, #31371, #31360, #31512, #31511, #31525, #32153, and #32201 by @ClearlyClaire, @Gargron, @arbolitoloco1, @mjankowski, @nclm, @renchap, @ronilaukkarinen, and @zunda)\
|
||||
This changes all the interface icons from FontAwesome to Material Symbols for a more modern look, consistent with the official Mastodon Android app.\
|
||||
In addition, better care is given to pixel alignment, and icon variants are used to better highlight active/inactive state.
|
||||
- **Change design of compose form in web UI** (#28119, #29059, #29248, #29372, #29384, #29417, #29456, #29406, #29651, #29659, #31889 and #32033 by @ClearlyClaire, @Gargron, @eai04191, @hinaloe, and @ronilaukkarinen)\
|
||||
@@ -192,9 +487,9 @@ The following changelog entries focus on changes visible to users, administrator
|
||||
Administrators may need to update their setup accordingly.
|
||||
- Change how content warnings and filters are displayed in web UI (#31365, and #31761 by @Gargron)
|
||||
- Change preview card processing to ignore `undefined` as canonical url (#31882 by @oneiros)
|
||||
- Change embedded posts to use web UI (#31766 and #32135 by @Gargron)
|
||||
- Change embedded posts to use web UI (#31766, #32135 and #32271 by @Gargron)
|
||||
- Change inner borders in media galleries in web UI (#31852 by @Gargron)
|
||||
- Change design of media attachments and profile media tab in web UI (#31807, #32048, and #31967 by @Gargron)
|
||||
- Change design of media attachments and profile media tab in web UI (#31807, #32048, #31967, #32217, #32224 and #32257 by @ClearlyClaire and @Gargron)
|
||||
- Change labels on thread indicators in web UI (#31806 by @Gargron)
|
||||
- Change label of "Data export" menu item in settings interface (#32099 by @c960657)
|
||||
- Change responsive break points on navigation panel in web UI (#32034 by @Gargron)
|
||||
@@ -284,9 +579,10 @@ The following changelog entries focus on changes visible to users, administrator
|
||||
- Fix error when accepting an appeal for sensitive posts deleted in the meantime (#32037 by @ClearlyClaire)
|
||||
- Fix error when encountering reblog of deleted post in feed rebuild (#32001 by @ClearlyClaire)
|
||||
- Fix Safari browser glitch related to horizontal scrolling (#31960 by @Gargron)
|
||||
- Fix unresolvable mentions sometimes preventing processing incoming posts (#29215 by @tribela and @ClearlyClaire)
|
||||
- Fix too many requests caused by relationship look-ups in web UI (#32042 by @Gargron)
|
||||
- Fix links for reblogs in moderation interface (#31979 by @ClearlyClaire)
|
||||
- Fix the appearance of avatars when they do not load (#31966 by @renchap)
|
||||
- Fix the appearance of avatars when they do not load (#31966 and #32270 by @Gargron and @renchap)
|
||||
- Fix spurious error notifications for aborted requests in web UI (#31952 by @c960657)
|
||||
- Fix HTTP 500 error in `/api/v1/polls/:id/votes` when required `choices` parameter is missing (#25598 by @danielmbrasil)
|
||||
- Fix security context sometimes not being added in LD-Signed activities (#31871 by @ClearlyClaire)
|
||||
@@ -309,10 +605,12 @@ The following changelog entries focus on changes visible to users, administrator
|
||||
- Fix “Redirect URI” field not being marked as required in “New application” form (#30311 by @ThisIsMissEm)
|
||||
- Fix right-to-left text in preview cards (#30930 by @ClearlyClaire)
|
||||
- Fix rack attack `match_type` value typo in logging config (#30514 by @mjankowski)
|
||||
- Fix various cases of duplicate, missing, or inconsistent borders or scrollbar styles (#31068, #31286, #31268, #31275, #31284, #31305, #31346, #31372, #31373, #31389, #31432, #31391, #31445 and #32091 by @ClearlyClaire, @valtlai and @vmstan)
|
||||
- Fix various cases of duplicate, missing, or inconsistent borders or scrollbar styles (#31068, #31286, #31268, #31275, #31284, #31305, #31346, #31372, #31373, #31389, #31432, #31391, #31445, #32091, #32147 and #32137 by @ClearlyClaire, @mjankowski, @valtlai and @vmstan)
|
||||
- Fix editing description of media uploads with custom thumbnails (#32221 by @ClearlyClaire)
|
||||
- Fix race condition in `POST /api/v1/push/subscription` (#30166 by @ClearlyClaire)
|
||||
- Fix post deletion not being delayed when those are part of an account warning (#30163 by @ClearlyClaire)
|
||||
- Fix rendering error on `/start` when not logged in (#30023 by @timothyjrogers)
|
||||
- Fix unneeded requests to blocked domains when receiving relayed signed activities from them (#31161 by @ClearlyClaire)
|
||||
- Fix logo pushing header buttons out of view on certain conditions in mobile layout (#29787 by @ClearlyClaire)
|
||||
- Fix notification-related records not being reattributed when merging accounts (#29694 by @ClearlyClaire)
|
||||
- Fix results/query in `api/v1/featured_tags/suggestions` (#29597 by @mjankowski)
|
||||
@@ -322,6 +620,7 @@ The following changelog entries focus on changes visible to users, administrator
|
||||
- Fix full date display not respecting the locale 12/24h format (#29448 by @renchap)
|
||||
- Fix filters title and keywords overflow (#29396 by @GeopJr)
|
||||
- Fix incorrect date format in “Follows and followers” (#29390 by @JasonPunyon)
|
||||
- Fix navigation item active highlight for some paths (#32159 by @mjankowski)
|
||||
- Fix “Edit media” modal sizing and layout when space-constrained (#27095 by @ronilaukkarinen)
|
||||
- Fix modal container bounds (#29185 by @nico3333fr)
|
||||
- Fix inefficient HTTP signature parsing using regexps and `StringScanner` (#29133 by @ClearlyClaire)
|
||||
|
||||
@@ -92,6 +92,9 @@ RUN \
|
||||
# Set /opt/mastodon as working directory
|
||||
WORKDIR /opt/mastodon
|
||||
|
||||
# Add backport repository for some specific packages where we need the latest version
|
||||
RUN echo 'deb http://deb.debian.org/debian bookworm-backports main' >> /etc/apt/sources.list
|
||||
|
||||
# hadolint ignore=DL3008,DL3005
|
||||
RUN \
|
||||
# Mount Apt cache and lib directories from Docker buildx caches
|
||||
@@ -150,6 +153,7 @@ RUN \
|
||||
libpq-dev \
|
||||
libssl-dev \
|
||||
libtool \
|
||||
libyaml-dev \
|
||||
meson \
|
||||
nasm \
|
||||
pkg-config \
|
||||
@@ -160,7 +164,7 @@ RUN \
|
||||
libexif-dev \
|
||||
libexpat1-dev \
|
||||
libgirepository1.0-dev \
|
||||
libheif-dev \
|
||||
libheif-dev/bookworm-backports \
|
||||
libimagequant-dev \
|
||||
libjpeg62-turbo-dev \
|
||||
liblcms2-dev \
|
||||
@@ -343,7 +347,7 @@ RUN \
|
||||
# libvips components
|
||||
libcgif0 \
|
||||
libexif12 \
|
||||
libheif1 \
|
||||
libheif1/bookworm-backports \
|
||||
libimagequant0 \
|
||||
libjpeg62-turbo \
|
||||
liblcms2-2 \
|
||||
|
||||
3
Gemfile
3
Gemfile
@@ -158,6 +158,9 @@ group :test do
|
||||
|
||||
# Stub web requests for specs
|
||||
gem 'webmock', '~> 3.18'
|
||||
|
||||
# Websocket driver for testing integration between rails/sidekiq and streaming
|
||||
gem 'websocket-driver', '~> 0.8', require: false
|
||||
end
|
||||
|
||||
group :development do
|
||||
|
||||
175
Gemfile.lock
175
Gemfile.lock
@@ -10,35 +10,35 @@ GIT
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
actioncable (7.1.4)
|
||||
actionpack (= 7.1.4)
|
||||
activesupport (= 7.1.4)
|
||||
actioncable (7.1.5.2)
|
||||
actionpack (= 7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (>= 0.6.1)
|
||||
zeitwerk (~> 2.6)
|
||||
actionmailbox (7.1.4)
|
||||
actionpack (= 7.1.4)
|
||||
activejob (= 7.1.4)
|
||||
activerecord (= 7.1.4)
|
||||
activestorage (= 7.1.4)
|
||||
activesupport (= 7.1.4)
|
||||
actionmailbox (7.1.5.2)
|
||||
actionpack (= 7.1.5.2)
|
||||
activejob (= 7.1.5.2)
|
||||
activerecord (= 7.1.5.2)
|
||||
activestorage (= 7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
mail (>= 2.7.1)
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
actionmailer (7.1.4)
|
||||
actionpack (= 7.1.4)
|
||||
actionview (= 7.1.4)
|
||||
activejob (= 7.1.4)
|
||||
activesupport (= 7.1.4)
|
||||
actionmailer (7.1.5.2)
|
||||
actionpack (= 7.1.5.2)
|
||||
actionview (= 7.1.5.2)
|
||||
activejob (= 7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
rails-dom-testing (~> 2.2)
|
||||
actionpack (7.1.4)
|
||||
actionview (= 7.1.4)
|
||||
activesupport (= 7.1.4)
|
||||
actionpack (7.1.5.2)
|
||||
actionview (= 7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
nokogiri (>= 1.8.5)
|
||||
racc
|
||||
rack (>= 2.2.4)
|
||||
@@ -46,15 +46,15 @@ GEM
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.2)
|
||||
rails-html-sanitizer (~> 1.6)
|
||||
actiontext (7.1.4)
|
||||
actionpack (= 7.1.4)
|
||||
activerecord (= 7.1.4)
|
||||
activestorage (= 7.1.4)
|
||||
activesupport (= 7.1.4)
|
||||
actiontext (7.1.5.2)
|
||||
actionpack (= 7.1.5.2)
|
||||
activerecord (= 7.1.5.2)
|
||||
activestorage (= 7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
globalid (>= 0.6.0)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (7.1.4)
|
||||
activesupport (= 7.1.4)
|
||||
actionview (7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.11)
|
||||
rails-dom-testing (~> 2.2)
|
||||
@@ -64,30 +64,33 @@ GEM
|
||||
activemodel (>= 4.1)
|
||||
case_transform (>= 0.2)
|
||||
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
|
||||
activejob (7.1.4)
|
||||
activesupport (= 7.1.4)
|
||||
activejob (7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (7.1.4)
|
||||
activesupport (= 7.1.4)
|
||||
activerecord (7.1.4)
|
||||
activemodel (= 7.1.4)
|
||||
activesupport (= 7.1.4)
|
||||
activemodel (7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
activerecord (7.1.5.2)
|
||||
activemodel (= 7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
timeout (>= 0.4.0)
|
||||
activestorage (7.1.4)
|
||||
actionpack (= 7.1.4)
|
||||
activejob (= 7.1.4)
|
||||
activerecord (= 7.1.4)
|
||||
activesupport (= 7.1.4)
|
||||
activestorage (7.1.5.2)
|
||||
actionpack (= 7.1.5.2)
|
||||
activejob (= 7.1.5.2)
|
||||
activerecord (= 7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
marcel (~> 1.0)
|
||||
activesupport (7.1.4)
|
||||
activesupport (7.1.5.2)
|
||||
base64
|
||||
benchmark (>= 0.3)
|
||||
bigdecimal
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
connection_pool (>= 2.2.5)
|
||||
drb
|
||||
i18n (>= 1.6, < 2)
|
||||
logger (>= 1.4.2)
|
||||
minitest (>= 5.1)
|
||||
mutex_m
|
||||
securerandom (>= 0.3)
|
||||
tzinfo (~> 2.0)
|
||||
addressable (2.8.7)
|
||||
public_suffix (>= 2.0.2, < 7.0)
|
||||
@@ -126,6 +129,7 @@ GEM
|
||||
base64 (0.2.0)
|
||||
bcp47_spec (0.2.1)
|
||||
bcrypt (3.1.20)
|
||||
benchmark (0.4.0)
|
||||
better_errors (2.10.1)
|
||||
erubi (>= 1.0.0)
|
||||
rack (>= 0.9.0)
|
||||
@@ -186,7 +190,7 @@ GEM
|
||||
activerecord (>= 5.a)
|
||||
database_cleaner-core (~> 2.0.0)
|
||||
database_cleaner-core (2.0.1)
|
||||
date (3.3.4)
|
||||
date (3.4.1)
|
||||
debug (1.9.2)
|
||||
irb (~> 1.10)
|
||||
reline (>= 0.3.8)
|
||||
@@ -262,15 +266,15 @@ GEM
|
||||
faraday (~> 1.0)
|
||||
fast_blank (1.0.1)
|
||||
fastimage (2.3.1)
|
||||
ffi (1.16.3)
|
||||
ffi (1.17.1)
|
||||
ffi-compiler (1.3.2)
|
||||
ffi (>= 1.15.5)
|
||||
rake
|
||||
flatware (2.3.3)
|
||||
flatware (2.3.4)
|
||||
drb
|
||||
thor (< 2.0)
|
||||
flatware-rspec (2.3.3)
|
||||
flatware (= 2.3.3)
|
||||
flatware-rspec (2.3.4)
|
||||
flatware (= 2.3.4)
|
||||
rspec (>= 3.6)
|
||||
fog-core (2.5.0)
|
||||
builder
|
||||
@@ -406,7 +410,7 @@ GEM
|
||||
llhttp-ffi (0.5.0)
|
||||
ffi-compiler (~> 1.0)
|
||||
rake (~> 13.0)
|
||||
logger (1.6.1)
|
||||
logger (1.6.6)
|
||||
lograge (0.14.0)
|
||||
actionpack (>= 4)
|
||||
activesupport (>= 4)
|
||||
@@ -433,7 +437,7 @@ GEM
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2024.0820)
|
||||
mini_mime (1.1.5)
|
||||
mini_portile2 (2.8.7)
|
||||
mini_portile2 (2.8.9)
|
||||
minitest (5.25.1)
|
||||
msgpack (1.7.2)
|
||||
multi_json (1.15.0)
|
||||
@@ -443,7 +447,7 @@ GEM
|
||||
uri
|
||||
net-http-persistent (4.0.2)
|
||||
connection_pool (~> 2.2)
|
||||
net-imap (0.4.15)
|
||||
net-imap (0.5.8)
|
||||
date
|
||||
net-protocol
|
||||
net-ldap (0.19.0)
|
||||
@@ -451,16 +455,16 @@ GEM
|
||||
net-protocol
|
||||
net-protocol (0.2.2)
|
||||
timeout
|
||||
net-smtp (0.5.0)
|
||||
net-smtp (0.5.1)
|
||||
net-protocol
|
||||
nio4r (2.7.3)
|
||||
nokogiri (1.16.7)
|
||||
nokogiri (1.18.9)
|
||||
mini_portile2 (~> 2.8.2)
|
||||
racc (~> 1.4)
|
||||
oj (3.16.6)
|
||||
bigdecimal (>= 3.0)
|
||||
ostruct (>= 0.2)
|
||||
omniauth (2.1.2)
|
||||
omniauth (2.1.3)
|
||||
hashie (>= 3.4.6)
|
||||
rack (>= 2.2.3)
|
||||
rack-protection
|
||||
@@ -471,9 +475,9 @@ GEM
|
||||
omniauth-rails_csrf_protection (1.0.2)
|
||||
actionpack (>= 4.2)
|
||||
omniauth (~> 2.0)
|
||||
omniauth-saml (2.2.1)
|
||||
omniauth-saml (2.2.3)
|
||||
omniauth (~> 2.1)
|
||||
ruby-saml (~> 1.17)
|
||||
ruby-saml (~> 1.18)
|
||||
omniauth_openid_connect (0.6.1)
|
||||
omniauth (>= 1.9, < 3)
|
||||
openid_connect (~> 1.1)
|
||||
@@ -488,7 +492,7 @@ GEM
|
||||
validate_email
|
||||
validate_url
|
||||
webfinger (~> 1.2)
|
||||
openssl (3.2.0)
|
||||
openssl (3.2.2)
|
||||
openssl-signature_algorithm (1.3.0)
|
||||
openssl (> 2.0)
|
||||
opentelemetry-api (1.4.0)
|
||||
@@ -601,7 +605,7 @@ GEM
|
||||
actionmailer (>= 3)
|
||||
net-smtp
|
||||
premailer (~> 1.7, >= 1.7.9)
|
||||
propshaft (1.0.1)
|
||||
propshaft (1.1.0)
|
||||
actionpack (>= 7.0.0)
|
||||
activesupport (>= 7.0.0)
|
||||
rack
|
||||
@@ -615,7 +619,7 @@ GEM
|
||||
activesupport (>= 3.0.0)
|
||||
raabro (1.4.0)
|
||||
racc (1.8.1)
|
||||
rack (2.2.9)
|
||||
rack (2.2.20)
|
||||
rack-attack (6.7.0)
|
||||
rack (>= 1.0, < 4)
|
||||
rack-cors (2.0.2)
|
||||
@@ -638,20 +642,20 @@ GEM
|
||||
rackup (1.0.0)
|
||||
rack (< 3)
|
||||
webrick
|
||||
rails (7.1.4)
|
||||
actioncable (= 7.1.4)
|
||||
actionmailbox (= 7.1.4)
|
||||
actionmailer (= 7.1.4)
|
||||
actionpack (= 7.1.4)
|
||||
actiontext (= 7.1.4)
|
||||
actionview (= 7.1.4)
|
||||
activejob (= 7.1.4)
|
||||
activemodel (= 7.1.4)
|
||||
activerecord (= 7.1.4)
|
||||
activestorage (= 7.1.4)
|
||||
activesupport (= 7.1.4)
|
||||
rails (7.1.5.2)
|
||||
actioncable (= 7.1.5.2)
|
||||
actionmailbox (= 7.1.5.2)
|
||||
actionmailer (= 7.1.5.2)
|
||||
actionpack (= 7.1.5.2)
|
||||
actiontext (= 7.1.5.2)
|
||||
actionview (= 7.1.5.2)
|
||||
activejob (= 7.1.5.2)
|
||||
activemodel (= 7.1.5.2)
|
||||
activerecord (= 7.1.5.2)
|
||||
activestorage (= 7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
bundler (>= 1.15.0)
|
||||
railties (= 7.1.4)
|
||||
railties (= 7.1.5.2)
|
||||
rails-controller-testing (1.0.5)
|
||||
actionpack (>= 5.0.1.rc1)
|
||||
actionview (>= 5.0.1.rc1)
|
||||
@@ -660,15 +664,15 @@ GEM
|
||||
activesupport (>= 5.0.0)
|
||||
minitest
|
||||
nokogiri (>= 1.6)
|
||||
rails-html-sanitizer (1.6.0)
|
||||
rails-html-sanitizer (1.6.2)
|
||||
loofah (~> 2.21)
|
||||
nokogiri (~> 1.14)
|
||||
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
||||
rails-i18n (7.0.9)
|
||||
i18n (>= 0.7, < 2)
|
||||
railties (>= 6.0.0, < 8)
|
||||
railties (7.1.4)
|
||||
actionpack (= 7.1.4)
|
||||
activesupport (= 7.1.4)
|
||||
railties (7.1.5.2)
|
||||
actionpack (= 7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
irb
|
||||
rackup (>= 1.0.0)
|
||||
rake (>= 12.2)
|
||||
@@ -698,7 +702,7 @@ GEM
|
||||
responders (3.1.1)
|
||||
actionpack (>= 5.2)
|
||||
railties (>= 5.2)
|
||||
rexml (3.3.7)
|
||||
rexml (3.4.4)
|
||||
rotp (6.3.0)
|
||||
rouge (4.3.0)
|
||||
rpam2 (4.0.2)
|
||||
@@ -748,25 +752,25 @@ GEM
|
||||
parser (>= 3.3.1.0)
|
||||
rubocop-capybara (2.21.0)
|
||||
rubocop (~> 1.41)
|
||||
rubocop-performance (1.21.1)
|
||||
rubocop-performance (1.22.1)
|
||||
rubocop (>= 1.48.1, < 2.0)
|
||||
rubocop-ast (>= 1.31.1, < 2.0)
|
||||
rubocop-rails (2.25.1)
|
||||
rubocop-rails (2.26.2)
|
||||
activesupport (>= 4.2.0)
|
||||
rack (>= 1.1)
|
||||
rubocop (>= 1.33.0, < 2.0)
|
||||
rubocop (>= 1.52.0, < 2.0)
|
||||
rubocop-ast (>= 1.31.1, < 2.0)
|
||||
rubocop-rspec (3.0.4)
|
||||
rubocop-rspec (3.0.5)
|
||||
rubocop (~> 1.61)
|
||||
rubocop-rspec_rails (2.30.0)
|
||||
rubocop (~> 1.61)
|
||||
rubocop-rspec (~> 3, >= 3.0.1)
|
||||
ruby-prof (1.7.0)
|
||||
ruby-progressbar (1.13.0)
|
||||
ruby-saml (1.17.0)
|
||||
ruby-saml (1.18.1)
|
||||
nokogiri (>= 1.13.10)
|
||||
rexml
|
||||
ruby-vips (2.2.2)
|
||||
ruby-vips (2.2.3)
|
||||
ffi (~> 1.12)
|
||||
logger
|
||||
ruby2_keywords (0.0.5)
|
||||
@@ -781,6 +785,7 @@ GEM
|
||||
scenic (1.8.0)
|
||||
activerecord (>= 4.0.0)
|
||||
railties (>= 4.0.0)
|
||||
securerandom (0.4.1)
|
||||
selenium-webdriver (4.25.0)
|
||||
base64 (~> 0.2)
|
||||
logger (~> 1.4)
|
||||
@@ -835,9 +840,9 @@ GEM
|
||||
terrapin (1.0.1)
|
||||
climate_control
|
||||
test-prof (1.4.2)
|
||||
thor (1.3.2)
|
||||
thor (1.4.0)
|
||||
tilt (2.4.0)
|
||||
timeout (0.4.1)
|
||||
timeout (0.4.3)
|
||||
tpm-key_attestation (0.12.1)
|
||||
bindata (~> 2.4)
|
||||
openssl (> 2.0)
|
||||
@@ -863,7 +868,7 @@ GEM
|
||||
unf_ext
|
||||
unf_ext (0.0.9.1)
|
||||
unicode-display_width (2.5.0)
|
||||
uri (0.13.1)
|
||||
uri (0.13.3)
|
||||
validate_email (0.1.6)
|
||||
activemodel (>= 3.0)
|
||||
mail (>= 2.2.5)
|
||||
@@ -884,7 +889,7 @@ GEM
|
||||
webfinger (1.2.0)
|
||||
activesupport
|
||||
httpclient (>= 2.4)
|
||||
webmock (3.23.1)
|
||||
webmock (3.24.0)
|
||||
addressable (>= 2.8.0)
|
||||
crack (>= 0.3.2)
|
||||
hashdiff (>= 0.4.0, < 2.0.0)
|
||||
@@ -895,7 +900,8 @@ GEM
|
||||
semantic_range (>= 2.3.0)
|
||||
webrick (1.8.2)
|
||||
websocket (1.2.11)
|
||||
websocket-driver (0.7.6)
|
||||
websocket-driver (0.8.0)
|
||||
base64
|
||||
websocket-extensions (>= 0.1.0)
|
||||
websocket-extensions (0.1.5)
|
||||
wisper (2.0.1)
|
||||
@@ -1054,10 +1060,11 @@ DEPENDENCIES
|
||||
webmock (~> 3.18)
|
||||
webpacker (~> 5.4)
|
||||
webpush!
|
||||
websocket-driver (~> 0.8)
|
||||
xorcist (~> 1.1)
|
||||
|
||||
RUBY VERSION
|
||||
ruby 3.3.4p94
|
||||
|
||||
BUNDLED WITH
|
||||
2.5.18
|
||||
2.6.5
|
||||
|
||||
11
SECURITY.md
11
SECURITY.md
@@ -13,8 +13,9 @@ A "vulnerability in Mastodon" is a vulnerability in the code distributed through
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | --------- |
|
||||
| 4.2.x | Yes |
|
||||
| 4.1.x | Yes |
|
||||
| < 4.1 | No |
|
||||
| Version | Supported |
|
||||
| ------- | ---------------- |
|
||||
| 4.4.x | Yes |
|
||||
| 4.3.x | Until 2026-05-06 |
|
||||
| 4.2.x | Until 2026-01-08 |
|
||||
| < 4.2 | No |
|
||||
|
||||
@@ -6,6 +6,7 @@ class Admin::AnnouncementsController < Admin::BaseController
|
||||
|
||||
def index
|
||||
authorize :announcement, :index?
|
||||
@published_announcements_count = Announcement.published.async_count
|
||||
end
|
||||
|
||||
def new
|
||||
|
||||
@@ -6,6 +6,7 @@ class Admin::Disputes::AppealsController < Admin::BaseController
|
||||
def index
|
||||
authorize :appeal, :index?
|
||||
|
||||
@pending_appeals_count = Appeal.pending.async_count
|
||||
@appeals = filtered_appeals.page(params[:page])
|
||||
end
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ class Admin::Trends::Links::PreviewCardProvidersController < Admin::BaseControll
|
||||
def index
|
||||
authorize :preview_card_provider, :review?
|
||||
|
||||
@pending_preview_card_providers_count = PreviewCardProvider.unreviewed.async_count
|
||||
@preview_card_providers = filtered_preview_card_providers.page(params[:page])
|
||||
@form = Trends::PreviewCardProviderBatch.new
|
||||
end
|
||||
|
||||
@@ -4,6 +4,7 @@ class Admin::Trends::TagsController < Admin::BaseController
|
||||
def index
|
||||
authorize :tag, :review?
|
||||
|
||||
@pending_tags_count = Tag.pending_review.async_count
|
||||
@tags = filtered_tags.page(params[:page])
|
||||
@form = Trends::TagBatch.new
|
||||
end
|
||||
|
||||
@@ -72,6 +72,13 @@ class Api::BaseController < ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
# Redefine `require_functional!` to properly output JSON instead of HTML redirects
|
||||
def require_functional!
|
||||
return if current_user.functional?
|
||||
|
||||
require_user!
|
||||
end
|
||||
|
||||
def render_empty
|
||||
render json: {}, status: 200
|
||||
end
|
||||
|
||||
@@ -14,7 +14,7 @@ class Api::V1::Accounts::CredentialsController < Api::BaseController
|
||||
@account = current_account
|
||||
UpdateAccountService.new.call(@account, account_params, raise_error: true)
|
||||
current_user.update(user_params) if user_params
|
||||
ActivityPub::UpdateDistributionWorker.perform_async(@account.id)
|
||||
ActivityPub::UpdateDistributionWorker.perform_in(ActivityPub::UpdateDistributionWorker::DEBOUNCE_DELAY, @account.id)
|
||||
render json: @account, serializer: REST::CredentialAccountSerializer
|
||||
rescue ActiveRecord::RecordInvalid => e
|
||||
render json: ValidationErrorFormatter.new(e).as_json, status: 422
|
||||
|
||||
@@ -16,6 +16,7 @@ class Api::V1::AccountsController < Api::BaseController
|
||||
before_action :check_account_confirmation, except: [:index, :create]
|
||||
before_action :check_enabled_registrations, only: [:create]
|
||||
before_action :check_accounts_limit, only: [:index]
|
||||
before_action :check_following_self, only: [:follow]
|
||||
|
||||
skip_before_action :require_authenticated_user!, only: :create
|
||||
|
||||
@@ -101,6 +102,10 @@ class Api::V1::AccountsController < Api::BaseController
|
||||
raise(Mastodon::ValidationError) if account_ids.size > DEFAULT_ACCOUNTS_LIMIT
|
||||
end
|
||||
|
||||
def check_following_self
|
||||
render json: { error: I18n.t('accounts.self_follow_error') }, status: 403 if current_user.account.id == @account.id
|
||||
end
|
||||
|
||||
def relationships(**options)
|
||||
AccountRelationshipsPresenter.new([@account], current_user.account_id, **options)
|
||||
end
|
||||
|
||||
@@ -31,7 +31,7 @@ class Api::V1::Instances::DomainBlocksController < Api::V1::Instances::BaseContr
|
||||
end
|
||||
|
||||
def show_domain_blocks_to_user?
|
||||
Setting.show_domain_blocks == 'users' && user_signed_in?
|
||||
Setting.show_domain_blocks == 'users' && user_signed_in? && current_user.functional_or_moved?
|
||||
end
|
||||
|
||||
def set_domain_blocks
|
||||
@@ -47,6 +47,6 @@ class Api::V1::Instances::DomainBlocksController < Api::V1::Instances::BaseContr
|
||||
end
|
||||
|
||||
def show_rationale_for_user?
|
||||
Setting.show_domain_blocks_rationale == 'users' && user_signed_in?
|
||||
Setting.show_domain_blocks_rationale == 'users' && user_signed_in? && current_user.functional_or_moved?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -52,7 +52,7 @@ class Api::V1::Notifications::RequestsController < Api::BaseController
|
||||
private
|
||||
|
||||
def load_requests
|
||||
requests = NotificationRequest.where(account: current_account).includes(:last_status, from_account: [:account_stat, :user]).to_a_paginated_by_id(
|
||||
requests = NotificationRequest.where(account: current_account).without_suspended.includes(:last_status, from_account: [:account_stat, :user]).to_a_paginated_by_id(
|
||||
limit_param(DEFAULT_ACCOUNTS_LIMIT),
|
||||
params_slice(:max_id, :since_id, :min_id)
|
||||
)
|
||||
|
||||
@@ -7,7 +7,7 @@ class Api::V1::Profile::AvatarsController < Api::BaseController
|
||||
def destroy
|
||||
@account = current_account
|
||||
UpdateAccountService.new.call(@account, { avatar: nil }, raise_error: true)
|
||||
ActivityPub::UpdateDistributionWorker.perform_async(@account.id)
|
||||
ActivityPub::UpdateDistributionWorker.perform_in(ActivityPub::UpdateDistributionWorker::DEBOUNCE_DELAY, @account.id)
|
||||
render json: @account, serializer: REST::CredentialAccountSerializer
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,7 +7,7 @@ class Api::V1::Profile::HeadersController < Api::BaseController
|
||||
def destroy
|
||||
@account = current_account
|
||||
UpdateAccountService.new.call(@account, { header: nil }, raise_error: true)
|
||||
ActivityPub::UpdateDistributionWorker.perform_async(@account.id)
|
||||
ActivityPub::UpdateDistributionWorker.perform_in(ActivityPub::UpdateDistributionWorker::DEBOUNCE_DELAY, @account.id)
|
||||
render json: @account, serializer: REST::CredentialAccountSerializer
|
||||
end
|
||||
end
|
||||
|
||||
@@ -23,6 +23,6 @@ class Api::V1::Statuses::TranslationsController < Api::V1::Statuses::BaseControl
|
||||
private
|
||||
|
||||
def set_translation
|
||||
@translation = TranslateStatusService.new.call(@status, content_locale)
|
||||
@translation = TranslateStatusService.new.call(@status, I18n.locale.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -46,7 +46,7 @@ class Api::V2::NotificationsController < Api::BaseController
|
||||
end
|
||||
|
||||
def show
|
||||
@notification = current_account.notifications.without_suspended.find_by!(group_key: params[:group_key])
|
||||
@notification = current_account.notifications.without_suspended.by_group_key(params[:group_key]).take!
|
||||
presenter = GroupedNotificationsPresenter.new(NotificationGroup.from_notifications([@notification]))
|
||||
render json: presenter, serializer: REST::DedupNotificationGroupSerializer
|
||||
end
|
||||
@@ -57,7 +57,7 @@ class Api::V2::NotificationsController < Api::BaseController
|
||||
end
|
||||
|
||||
def dismiss
|
||||
current_account.notifications.where(group_key: params[:group_key]).destroy_all
|
||||
current_account.notifications.by_group_key(params[:group_key]).destroy_all
|
||||
render_empty
|
||||
end
|
||||
|
||||
@@ -80,10 +80,31 @@ class Api::V2::NotificationsController < Api::BaseController
|
||||
return [] if @notifications.empty?
|
||||
|
||||
MastodonOTELTracer.in_span('Api::V2::NotificationsController#load_grouped_notifications') do
|
||||
NotificationGroup.from_notifications(@notifications, pagination_range: (@notifications.last.id)..(@notifications.first.id), grouped_types: params[:grouped_types])
|
||||
pagination_range = (@notifications.last.id)..@notifications.first.id
|
||||
|
||||
# If the page is incomplete, we know we are on the last page
|
||||
if incomplete_page?
|
||||
if paginating_up?
|
||||
pagination_range = @notifications.last.id...(params[:max_id]&.to_i)
|
||||
else
|
||||
range_start = params[:since_id]&.to_i
|
||||
range_start += 1 unless range_start.nil?
|
||||
pagination_range = range_start..(@notifications.first.id)
|
||||
end
|
||||
end
|
||||
|
||||
NotificationGroup.from_notifications(@notifications, pagination_range: pagination_range, grouped_types: params[:grouped_types])
|
||||
end
|
||||
end
|
||||
|
||||
def incomplete_page?
|
||||
@notifications.size < limit_param(DEFAULT_NOTIFICATIONS_LIMIT)
|
||||
end
|
||||
|
||||
def paginating_up?
|
||||
params[:min_id].present?
|
||||
end
|
||||
|
||||
def browserable_account_notifications
|
||||
current_account.notifications.without_suspended.browserable(
|
||||
types: Array(browserable_params[:types]),
|
||||
|
||||
@@ -74,7 +74,23 @@ class ApplicationController < ActionController::Base
|
||||
end
|
||||
|
||||
def require_functional!
|
||||
redirect_to edit_user_registration_path unless current_user.functional?
|
||||
return if current_user.functional?
|
||||
|
||||
respond_to do |format|
|
||||
format.any do
|
||||
redirect_to edit_user_registration_path
|
||||
end
|
||||
|
||||
format.json do
|
||||
if !current_user.confirmed?
|
||||
render json: { error: 'Your login is missing a confirmed e-mail address' }, status: 403
|
||||
elsif !current_user.approved?
|
||||
render json: { error: 'Your login is currently pending approval' }, status: 403
|
||||
elsif !current_user.functional?
|
||||
render json: { error: 'Your login is currently disabled' }, status: 403
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def skip_csrf_meta_tags?
|
||||
|
||||
@@ -9,13 +9,15 @@ class BackupsController < ApplicationController
|
||||
before_action :authenticate_user!
|
||||
before_action :set_backup
|
||||
|
||||
BACKUP_LINK_TIMEOUT = 1.hour.freeze
|
||||
|
||||
def download
|
||||
case Paperclip::Attachment.default_options[:storage]
|
||||
when :s3, :azure
|
||||
redirect_to @backup.dump.expiring_url(10), allow_other_host: true
|
||||
redirect_to @backup.dump.expiring_url(BACKUP_LINK_TIMEOUT.to_i), allow_other_host: true
|
||||
when :fog
|
||||
if Paperclip::Attachment.default_options.dig(:fog_credentials, :openstack_temp_url_key).present?
|
||||
redirect_to @backup.dump.expiring_url(Time.now.utc + 10), allow_other_host: true
|
||||
redirect_to @backup.dump.expiring_url(BACKUP_LINK_TIMEOUT.from_now), allow_other_host: true
|
||||
else
|
||||
redirect_to full_asset_url(@backup.dump.url), allow_other_host: true
|
||||
end
|
||||
|
||||
@@ -117,7 +117,7 @@ module SignatureVerification
|
||||
|
||||
def verify_signature_strength!
|
||||
raise SignatureVerificationError, 'Mastodon requires the Date header or (created) pseudo-header to be signed' unless signed_headers.include?('date') || signed_headers.include?('(created)')
|
||||
raise SignatureVerificationError, 'Mastodon requires the Digest header or (request-target) pseudo-header to be signed' unless signed_headers.include?(Request::REQUEST_TARGET) || signed_headers.include?('digest')
|
||||
raise SignatureVerificationError, 'Mastodon requires the Digest header or (request-target) pseudo-header to be signed' unless signed_headers.include?(HttpSignatureDraft::REQUEST_TARGET) || signed_headers.include?('digest')
|
||||
raise SignatureVerificationError, 'Mastodon requires the Host header to be signed when doing a GET request' if request.get? && !signed_headers.include?('host')
|
||||
raise SignatureVerificationError, 'Mastodon requires the Digest header to be signed when doing a POST request' if request.post? && !signed_headers.include?('digest')
|
||||
end
|
||||
@@ -155,14 +155,14 @@ module SignatureVerification
|
||||
def build_signed_string(include_query_string: true)
|
||||
signed_headers.map do |signed_header|
|
||||
case signed_header
|
||||
when Request::REQUEST_TARGET
|
||||
when HttpSignatureDraft::REQUEST_TARGET
|
||||
if include_query_string
|
||||
"#{Request::REQUEST_TARGET}: #{request.method.downcase} #{request.original_fullpath}"
|
||||
"#{HttpSignatureDraft::REQUEST_TARGET}: #{request.method.downcase} #{request.original_fullpath}"
|
||||
else
|
||||
# Current versions of Mastodon incorrectly omit the query string from the (request-target) pseudo-header.
|
||||
# Therefore, temporarily support such incorrect signatures for compatibility.
|
||||
# TODO: remove eventually some time after release of the fixed version
|
||||
"#{Request::REQUEST_TARGET}: #{request.method.downcase} #{request.path}"
|
||||
"#{HttpSignatureDraft::REQUEST_TARGET}: #{request.method.downcase} #{request.path}"
|
||||
end
|
||||
when '(created)'
|
||||
raise SignatureVerificationError, 'Invalid pseudo-header (created) for rsa-sha256' unless signature_algorithm == 'hs2019'
|
||||
|
||||
@@ -13,7 +13,7 @@ module WebAppControllerConcern
|
||||
policy = ContentSecurityPolicy.new
|
||||
|
||||
if policy.sso_host.present?
|
||||
p.form_action policy.sso_host
|
||||
p.form_action policy.sso_host, -> { "https://#{request.host}/auth/auth/" }
|
||||
else
|
||||
p.form_action :none
|
||||
end
|
||||
|
||||
@@ -8,7 +8,7 @@ module Settings
|
||||
def destroy
|
||||
if valid_picture?
|
||||
if UpdateAccountService.new.call(@account, { @picture => nil, "#{@picture}_remote_url" => '' })
|
||||
ActivityPub::UpdateDistributionWorker.perform_async(@account.id)
|
||||
ActivityPub::UpdateDistributionWorker.perform_in(ActivityPub::UpdateDistributionWorker::DEBOUNCE_DELAY, @account.id)
|
||||
redirect_to settings_profile_path, notice: I18n.t('generic.changes_saved_msg'), status: 303
|
||||
else
|
||||
redirect_to settings_profile_path
|
||||
|
||||
@@ -8,7 +8,7 @@ class Settings::PrivacyController < Settings::BaseController
|
||||
def update
|
||||
if UpdateAccountService.new.call(@account, account_params.except(:settings))
|
||||
current_user.update!(settings_attributes: account_params[:settings])
|
||||
ActivityPub::UpdateDistributionWorker.perform_async(@account.id)
|
||||
ActivityPub::UpdateDistributionWorker.perform_in(ActivityPub::UpdateDistributionWorker::DEBOUNCE_DELAY, @account.id)
|
||||
redirect_to settings_privacy_path, notice: I18n.t('generic.changes_saved_msg')
|
||||
else
|
||||
render :show
|
||||
|
||||
@@ -9,7 +9,7 @@ class Settings::ProfilesController < Settings::BaseController
|
||||
|
||||
def update
|
||||
if UpdateAccountService.new.call(@account, account_params)
|
||||
ActivityPub::UpdateDistributionWorker.perform_async(@account.id)
|
||||
ActivityPub::UpdateDistributionWorker.perform_in(ActivityPub::UpdateDistributionWorker::DEBOUNCE_DELAY, @account.id)
|
||||
redirect_to settings_profile_path, notice: I18n.t('generic.changes_saved_msg')
|
||||
else
|
||||
@account.build_fields
|
||||
|
||||
@@ -15,7 +15,7 @@ module Settings
|
||||
end
|
||||
|
||||
def create
|
||||
session[:new_otp_secret] = User.generate_otp_secret(32)
|
||||
session[:new_otp_secret] = User.generate_otp_secret
|
||||
|
||||
redirect_to new_settings_two_factor_authentication_confirmation_path
|
||||
end
|
||||
|
||||
@@ -8,7 +8,7 @@ class Settings::VerificationsController < Settings::BaseController
|
||||
|
||||
def update
|
||||
if UpdateAccountService.new.call(@account, account_params)
|
||||
ActivityPub::UpdateDistributionWorker.perform_async(@account.id)
|
||||
ActivityPub::UpdateDistributionWorker.perform_in(ActivityPub::UpdateDistributionWorker::DEBOUNCE_DELAY, @account.id)
|
||||
redirect_to settings_verification_path, notice: I18n.t('generic.changes_saved_msg')
|
||||
else
|
||||
render :show
|
||||
|
||||
@@ -7,7 +7,23 @@ module WellKnown
|
||||
def show
|
||||
@webfinger_template = "#{webfinger_url}?resource={uri}"
|
||||
expires_in 3.days, public: true
|
||||
render content_type: 'application/xrd+xml', formats: [:xml]
|
||||
|
||||
respond_to do |format|
|
||||
format.any do
|
||||
render content_type: 'application/xrd+xml', formats: [:xml]
|
||||
end
|
||||
|
||||
format.json do
|
||||
render json: {
|
||||
links: [
|
||||
{
|
||||
rel: 'lrdd',
|
||||
template: @webfinger_template,
|
||||
},
|
||||
],
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -35,4 +35,11 @@ module Admin::ActionLogsHelper
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def sorted_action_log_types
|
||||
Admin::ActionLogFilter::ACTION_TYPE_MAP
|
||||
.keys
|
||||
.map { |key| [I18n.t("admin.action_logs.action_types.#{key}"), key] }
|
||||
.sort_by(&:first)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -18,6 +18,11 @@ module Admin::DashboardHelper
|
||||
end
|
||||
end
|
||||
|
||||
def date_range(range)
|
||||
[l(range.first), l(range.last)]
|
||||
.join(' - ')
|
||||
end
|
||||
|
||||
def relevant_account_timestamp(account)
|
||||
timestamp, exact = if account.user_current_sign_in_at && account.user_current_sign_in_at < 24.hours.ago
|
||||
[account.user_current_sign_in_at, true]
|
||||
@@ -25,6 +30,8 @@ module Admin::DashboardHelper
|
||||
[account.user_current_sign_in_at, false]
|
||||
elsif account.user_pending?
|
||||
[account.user_created_at, true]
|
||||
elsif account.suspended_at.present? && account.local? && account.user.nil?
|
||||
[account.suspended_at, true]
|
||||
elsif account.last_status_at.present?
|
||||
[account.last_status_at, true]
|
||||
else
|
||||
|
||||
@@ -2,11 +2,18 @@
|
||||
|
||||
module Admin::Trends::StatusesHelper
|
||||
def one_line_preview(status)
|
||||
text = if status.local?
|
||||
status.text.split("\n").first
|
||||
else
|
||||
Nokogiri::HTML5(status.text).css('html > body > *').first&.text
|
||||
end
|
||||
text = begin
|
||||
if status.local?
|
||||
status.text.split("\n").first
|
||||
else
|
||||
Nokogiri::HTML5(status.text).css('html > body > *').first&.text
|
||||
end
|
||||
rescue ArgumentError
|
||||
# This can happen if one of the Nokogumbo limits is encountered
|
||||
# Unfortunately, it does not use a more precise error class
|
||||
# nor allows more graceful handling
|
||||
''
|
||||
end
|
||||
|
||||
return '' if text.blank?
|
||||
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module ApplicationHelper
|
||||
DANGEROUS_SCOPES = %w(
|
||||
read
|
||||
write
|
||||
follow
|
||||
).freeze
|
||||
|
||||
RTL_LOCALES = %i(
|
||||
ar
|
||||
ckb
|
||||
@@ -85,7 +79,7 @@ module ApplicationHelper
|
||||
|
||||
def html_title
|
||||
safe_join(
|
||||
[content_for(:page_title).to_s.chomp, title]
|
||||
[content_for(:page_title), title]
|
||||
.compact_blank,
|
||||
' - '
|
||||
)
|
||||
@@ -95,8 +89,11 @@ module ApplicationHelper
|
||||
Rails.env.production? ? site_title : "#{site_title} (Dev)"
|
||||
end
|
||||
|
||||
def class_for_scope(scope)
|
||||
'scope-danger' if DANGEROUS_SCOPES.include?(scope.to_s)
|
||||
def label_for_scope(scope)
|
||||
safe_join [
|
||||
tag.samp(scope, class: { 'scope-danger' => SessionActivation::DEFAULT_SCOPES.include?(scope.to_s) }),
|
||||
tag.span(t("doorkeeper.scopes.#{scope}"), class: :hint),
|
||||
]
|
||||
end
|
||||
|
||||
def can?(action, record)
|
||||
@@ -244,6 +241,15 @@ module ApplicationHelper
|
||||
full_asset_url(instance_presenter.mascot&.file&.url || frontend_asset_path('images/elephant_ui_plane.svg'))
|
||||
end
|
||||
|
||||
def copyable_input(options = {})
|
||||
tag.input(type: :text, maxlength: 999, spellcheck: false, readonly: true, **options)
|
||||
end
|
||||
|
||||
def recent_tag_usage(tag)
|
||||
people = tag.history.aggregate(2.days.ago.to_date..Time.zone.today).accounts
|
||||
I18n.t 'user_mailer.welcome.hashtags_recent_count', people: number_with_delimiter(people), count: people
|
||||
end
|
||||
|
||||
# glitch-soc addition to handle the multiple flavors
|
||||
def preload_locale_pack
|
||||
supported_locales = Themes.instance.flavour(current_flavour)['locales']
|
||||
|
||||
@@ -26,6 +26,13 @@ module ContextHelper
|
||||
voters_count: { 'toot' => 'http://joinmastodon.org/ns#', 'votersCount' => 'toot:votersCount' },
|
||||
suspended: { 'toot' => 'http://joinmastodon.org/ns#', 'suspended' => 'toot:suspended' },
|
||||
attribution_domains: { 'toot' => 'http://joinmastodon.org/ns#', 'attributionDomains' => { '@id' => 'toot:attributionDomains', '@type' => '@id' } },
|
||||
interaction_policies: {
|
||||
'gts' => 'https://gotosocial.org/ns#',
|
||||
'interactionPolicy' => { '@id' => 'gts:interactionPolicy', '@type' => '@id' },
|
||||
'canQuote' => { '@id' => 'gts:canQuote', '@type' => '@id' },
|
||||
'automaticApproval' => { '@id' => 'gts:automaticApproval', '@type' => '@id' },
|
||||
'manualApproval' => { '@id' => 'gts:manualApproval', '@type' => '@id' },
|
||||
},
|
||||
}.freeze
|
||||
|
||||
def full_context
|
||||
|
||||
@@ -26,6 +26,8 @@ module JsonLdHelper
|
||||
# The url attribute can be a string, an array of strings, or an array of objects.
|
||||
# The objects could include a mimeType. Not-included mimeType means it's text/html.
|
||||
def url_to_href(value, preferred_type = nil)
|
||||
value = [value] if value.is_a?(Hash)
|
||||
|
||||
single_value = if value.is_a?(Array) && !value.first.is_a?(String)
|
||||
value.find { |link| preferred_type.nil? || ((link['mimeType'].presence || 'text/html') == preferred_type) }
|
||||
elsif value.is_a?(Array)
|
||||
@@ -41,6 +43,15 @@ module JsonLdHelper
|
||||
end
|
||||
end
|
||||
|
||||
def url_to_media_type(value, preferred_type = nil)
|
||||
value = [value] if value.is_a?(Hash)
|
||||
return unless value.is_a?(Array) && !value.first.is_a?(String)
|
||||
|
||||
single_value = value.find { |link| preferred_type.nil? || ((link['mimeType'].presence || 'text/html') == preferred_type) }
|
||||
|
||||
single_value['mediaType'] unless single_value.nil?
|
||||
end
|
||||
|
||||
def as_array(value)
|
||||
if value.nil?
|
||||
[]
|
||||
|
||||
@@ -162,7 +162,7 @@ module LanguagesHelper
|
||||
th: ['Thai', 'ไทย'].freeze,
|
||||
ti: ['Tigrinya', 'ትግርኛ'].freeze,
|
||||
tk: ['Turkmen', 'Türkmen'].freeze,
|
||||
tl: ['Tagalog', 'Wikang Tagalog'].freeze,
|
||||
tl: ['Tagalog', 'Tagalog'].freeze,
|
||||
tn: ['Tswana', 'Setswana'].freeze,
|
||||
to: ['Tonga', 'faka Tonga'].freeze,
|
||||
tr: ['Turkish', 'Türkçe'].freeze,
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module WebfingerHelper
|
||||
def webfinger!(uri)
|
||||
Webfinger.new(uri).perform
|
||||
end
|
||||
end
|
||||
@@ -4,9 +4,12 @@ import axios from 'axios';
|
||||
import ready from '../mastodon/ready';
|
||||
|
||||
async function checkConfirmation() {
|
||||
const response = await axios.get('/api/v1/emails/check_confirmation');
|
||||
const response = await axios.get('/api/v1/emails/check_confirmation', {
|
||||
headers: { Accept: 'application/json' },
|
||||
withCredentials: true,
|
||||
});
|
||||
|
||||
if (response.data) {
|
||||
if (response.status === 200 && response.data === true) {
|
||||
window.location.href = '/start';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,12 +102,17 @@ export const ensureComposeIsVisible = (getState) => {
|
||||
};
|
||||
|
||||
export function setComposeToStatus(status, text, spoiler_text, content_type) {
|
||||
return{
|
||||
type: COMPOSE_SET_STATUS,
|
||||
status,
|
||||
text,
|
||||
spoiler_text,
|
||||
content_type,
|
||||
return (dispatch, getState) => {
|
||||
const maxOptions = getState().server.getIn(['server', 'configuration', 'polls', 'max_options']);
|
||||
|
||||
dispatch({
|
||||
type: COMPOSE_SET_STATUS,
|
||||
status,
|
||||
text,
|
||||
spoiler_text,
|
||||
content_type,
|
||||
maxOptions
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,17 @@ export function normalizeStatus(status, normalOldStatus, settings) {
|
||||
normalStatus.contentHtml = emojify(normalStatus.content, emojiMap);
|
||||
normalStatus.spoilerHtml = emojify(escapeTextContentForBrowser(spoilerText), emojiMap);
|
||||
normalStatus.hidden = (spoilerText.length > 0 || normalStatus.sensitive) && autoHideCW(settings, spoilerText);
|
||||
|
||||
if (normalStatus.url && !(normalStatus.url.startsWith('http://') || normalStatus.url.startsWith('https://'))) {
|
||||
normalStatus.url = null;
|
||||
}
|
||||
|
||||
normalStatus.url ||= normalStatus.uri;
|
||||
|
||||
normalStatus.media_attachments.forEach(item => {
|
||||
if (item.remote_url && !(item.remote_url.startsWith('http://') || item.remote_url.startsWith('https://')))
|
||||
item.remote_url = null;
|
||||
});
|
||||
}
|
||||
|
||||
if (normalOldStatus) {
|
||||
|
||||
@@ -37,8 +37,7 @@ export const synchronouslySubmitMarkers = createAppAsyncThunk(
|
||||
});
|
||||
|
||||
return;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
} else if ('navigator' && 'sendBeacon' in navigator) {
|
||||
} else if ('sendBeacon' in navigator) {
|
||||
// Failing that, we can use sendBeacon, but we have to encode the data as
|
||||
// FormData for DoorKeeper to recognize the token.
|
||||
const formData = new FormData();
|
||||
|
||||
@@ -8,6 +8,7 @@ import type { ApiAccountJSON } from 'flavours/glitch/api_types/accounts';
|
||||
import type {
|
||||
ApiNotificationGroupJSON,
|
||||
ApiNotificationJSON,
|
||||
NotificationType,
|
||||
} from 'flavours/glitch/api_types/notifications';
|
||||
import { allNotificationTypes } from 'flavours/glitch/api_types/notifications';
|
||||
import type { ApiStatusJSON } from 'flavours/glitch/api_types/statuses';
|
||||
@@ -15,6 +16,7 @@ import { usePendingItems } from 'flavours/glitch/initial_state';
|
||||
import type { NotificationGap } from 'flavours/glitch/reducers/notification_groups';
|
||||
import {
|
||||
selectSettingsNotificationsExcludedTypes,
|
||||
selectSettingsNotificationsGroupFollows,
|
||||
selectSettingsNotificationsQuickFilterActive,
|
||||
selectSettingsNotificationsShows,
|
||||
} from 'flavours/glitch/selectors/settings';
|
||||
@@ -68,13 +70,19 @@ function dispatchAssociatedRecords(
|
||||
dispatch(importFetchedStatuses(fetchedStatuses));
|
||||
}
|
||||
|
||||
const supportedGroupedNotificationTypes = ['favourite', 'reblog'];
|
||||
function selectNotificationGroupedTypes(state: RootState) {
|
||||
const types: NotificationType[] = ['favourite', 'reblog'];
|
||||
|
||||
if (selectSettingsNotificationsGroupFollows(state)) types.push('follow');
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
export const fetchNotifications = createDataLoadingThunk(
|
||||
'notificationGroups/fetch',
|
||||
async (_params, { getState }) =>
|
||||
apiFetchNotificationGroups({
|
||||
grouped_types: supportedGroupedNotificationTypes,
|
||||
grouped_types: selectNotificationGroupedTypes(getState()),
|
||||
exclude_types: getExcludedTypes(getState()),
|
||||
}),
|
||||
({ notifications, accounts, statuses }, { dispatch }) => {
|
||||
@@ -98,7 +106,7 @@ export const fetchNotificationsGap = createDataLoadingThunk(
|
||||
'notificationGroups/fetchGap',
|
||||
async (params: { gap: NotificationGap }, { getState }) =>
|
||||
apiFetchNotificationGroups({
|
||||
grouped_types: supportedGroupedNotificationTypes,
|
||||
grouped_types: selectNotificationGroupedTypes(getState()),
|
||||
max_id: params.gap.maxId,
|
||||
exclude_types: getExcludedTypes(getState()),
|
||||
}),
|
||||
@@ -115,7 +123,7 @@ export const pollRecentNotifications = createDataLoadingThunk(
|
||||
'notificationGroups/pollRecentNotifications',
|
||||
async (_params, { getState }) => {
|
||||
return apiFetchNotificationGroups({
|
||||
grouped_types: supportedGroupedNotificationTypes,
|
||||
grouped_types: selectNotificationGroupedTypes(getState()),
|
||||
max_id: undefined,
|
||||
exclude_types: getExcludedTypes(getState()),
|
||||
// In slow mode, we don't want to include notifications that duplicate the already-displayed ones
|
||||
@@ -133,6 +141,9 @@ export const pollRecentNotifications = createDataLoadingThunk(
|
||||
|
||||
return { notifications };
|
||||
},
|
||||
{
|
||||
useLoadingBar: false,
|
||||
},
|
||||
);
|
||||
|
||||
export const processNewNotificationForGroups = createAppAsyncThunk(
|
||||
@@ -164,7 +175,10 @@ export const processNewNotificationForGroups = createAppAsyncThunk(
|
||||
|
||||
dispatchAssociatedRecords(dispatch, [notification]);
|
||||
|
||||
return notification;
|
||||
return {
|
||||
notification,
|
||||
groupedTypes: selectNotificationGroupedTypes(state),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -90,11 +90,16 @@ export function fetchStatusFail(id, error, skipLoading) {
|
||||
}
|
||||
|
||||
export function redraft(status, raw_text, content_type) {
|
||||
return {
|
||||
type: REDRAFT,
|
||||
status,
|
||||
raw_text,
|
||||
content_type,
|
||||
return (dispatch, getState) => {
|
||||
const maxOptions = getState().server.getIn(['server', 'configuration', 'polls', 'max_options']);
|
||||
|
||||
dispatch({
|
||||
type: REDRAFT,
|
||||
status,
|
||||
raw_text,
|
||||
content_type,
|
||||
maxOptions,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { apiRequestPost } from 'flavours/glitch/api';
|
||||
import type { Status, StatusVisibility } from 'flavours/glitch/models/status';
|
||||
import type { ApiStatusJSON } from 'flavours/glitch/api_types/statuses';
|
||||
import type { StatusVisibility } from 'flavours/glitch/models/status';
|
||||
|
||||
export const apiReblog = (statusId: string, visibility: StatusVisibility) =>
|
||||
apiRequestPost<{ reblog: Status }>(`v1/statuses/${statusId}/reblog`, {
|
||||
apiRequestPost<{ reblog: ApiStatusJSON }>(`v1/statuses/${statusId}/reblog`, {
|
||||
visibility,
|
||||
});
|
||||
|
||||
export const apiUnreblog = (statusId: string) =>
|
||||
apiRequestPost<Status>(`v1/statuses/${statusId}/unreblog`);
|
||||
apiRequestPost<ApiStatusJSON>(`v1/statuses/${statusId}/unreblog`);
|
||||
|
||||
@@ -13,7 +13,7 @@ export interface ApiAccountRoleJSON {
|
||||
}
|
||||
|
||||
// See app/serializers/rest/account_serializer.rb
|
||||
export interface ApiAccountJSON {
|
||||
export interface BaseApiAccountJSON {
|
||||
acct: string;
|
||||
avatar: string;
|
||||
avatar_static: string;
|
||||
@@ -45,3 +45,12 @@ export interface ApiAccountJSON {
|
||||
memorial?: boolean;
|
||||
hide_collections: boolean;
|
||||
}
|
||||
|
||||
// See app/serializers/rest/muted_account_serializer.rb
|
||||
export interface ApiMutedAccountJSON extends BaseApiAccountJSON {
|
||||
mute_expires_at?: string | null;
|
||||
}
|
||||
|
||||
// For now, we have the same type representing both `Account` and `MutedAccount`
|
||||
// objects, but we should refactor this in the future.
|
||||
export type ApiAccountJSON = ApiMutedAccountJSON;
|
||||
|
||||
@@ -28,6 +28,7 @@ export const AltTextBadge: React.FC<{
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
type='button'
|
||||
ref={anchorRef}
|
||||
className='media-gallery__alt__label'
|
||||
onClick={handleClick}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { useHovering } from 'flavours/glitch/hooks/useHovering';
|
||||
import { autoPlayGif } from 'flavours/glitch/initial_state';
|
||||
import type { Account } from 'flavours/glitch/models/account';
|
||||
|
||||
import { useHovering } from '../hooks/useHovering';
|
||||
import { autoPlayGif } from '../initial_state';
|
||||
|
||||
interface Props {
|
||||
account: Account | undefined; // FIXME: remove `undefined` once we know for sure its always there
|
||||
size: number;
|
||||
@@ -25,6 +26,8 @@ export const Avatar: React.FC<Props> = ({
|
||||
counterBorderColor,
|
||||
}) => {
|
||||
const { hovering, handleMouseEnter, handleMouseLeave } = useHovering(animate);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(false);
|
||||
|
||||
const style = {
|
||||
...styleFromParent,
|
||||
@@ -37,17 +40,29 @@ export const Avatar: React.FC<Props> = ({
|
||||
? account?.get('avatar')
|
||||
: account?.get('avatar_static');
|
||||
|
||||
const handleLoad = useCallback(() => {
|
||||
setLoading(false);
|
||||
}, [setLoading]);
|
||||
|
||||
const handleError = useCallback(() => {
|
||||
setError(true);
|
||||
}, [setError]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames('account__avatar', {
|
||||
'account__avatar-inline': inline,
|
||||
'account__avatar--inline': inline,
|
||||
'account__avatar--loading': loading,
|
||||
})}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
style={style}
|
||||
data-avatar-of={account && `@${account.get('acct')}`}
|
||||
>
|
||||
{src && <img src={src} alt='' />}
|
||||
{src && !error && (
|
||||
<img src={src} alt='' onLoad={handleLoad} onError={handleError} />
|
||||
)}
|
||||
|
||||
{counter && (
|
||||
<div
|
||||
className='account__avatar__counter'
|
||||
|
||||
@@ -19,6 +19,7 @@ export const CollapseButton = ({ collapsed, setCollapsed }) => {
|
||||
if (e.button === 0) {
|
||||
setCollapsed(!collapsed);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
}, [collapsed, setCollapsed]);
|
||||
|
||||
|
||||
@@ -17,9 +17,15 @@ export const ContentWarning: React.FC<{
|
||||
aria-expanded={expanded}
|
||||
>
|
||||
{expanded ? (
|
||||
<FormattedMessage id='status.show_less' defaultMessage='Show less' />
|
||||
<FormattedMessage
|
||||
id='content_warning.hide'
|
||||
defaultMessage='Hide post'
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage id='status.show_more' defaultMessage='Show more' />
|
||||
<FormattedMessage
|
||||
id='content_warning.show_more'
|
||||
defaultMessage='Show more'
|
||||
/>
|
||||
)}
|
||||
{icons}
|
||||
</button>
|
||||
|
||||
@@ -10,13 +10,16 @@ export const FilterWarning: React.FC<{
|
||||
<StatusBanner
|
||||
expanded={expanded}
|
||||
onClick={onClick}
|
||||
variant={BannerVariant.Blue}
|
||||
variant={BannerVariant.Filter}
|
||||
>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='filter_warning.matches_filter'
|
||||
defaultMessage='Matches filter “{title}”'
|
||||
values={{ title }}
|
||||
defaultMessage='Matches filter “<span>{title}</span>”'
|
||||
values={{
|
||||
title,
|
||||
span: (chunks) => <span className='filter-name'>{chunks}</span>,
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
</StatusBanner>
|
||||
|
||||
@@ -98,12 +98,12 @@ class Item extends PureComponent {
|
||||
height = 50;
|
||||
}
|
||||
|
||||
if (attachment.get('description')?.length > 0) {
|
||||
badges.push(<AltTextBadge key='alt' description={attachment.get('description')} />);
|
||||
}
|
||||
|
||||
const description = attachment.getIn(['translation', 'description']) || attachment.get('description');
|
||||
|
||||
if (description?.length > 0) {
|
||||
badges.push(<AltTextBadge key='alt' description={description} />);
|
||||
}
|
||||
|
||||
if (attachment.get('type') === 'unknown') {
|
||||
return (
|
||||
<div className={classNames('media-gallery__item', { standalone, 'media-gallery__item--tall': height === 100, 'media-gallery__item--wide': width === 100 })} key={attachment.get('id')}>
|
||||
@@ -198,7 +198,7 @@ class Item extends PureComponent {
|
||||
|
||||
{visible && thumbnail}
|
||||
|
||||
{badges && (
|
||||
{visible && badges && (
|
||||
<div className='media-gallery__item__badges'>
|
||||
{badges}
|
||||
</div>
|
||||
@@ -356,14 +356,14 @@ class MediaGallery extends PureComponent {
|
||||
|
||||
return (
|
||||
<div className={computedClass} style={style} ref={this.handleRef}>
|
||||
{children}
|
||||
|
||||
{(!visible || uncached) && (
|
||||
<div className={classNames('spoiler-button', { 'spoiler-button--click-thru': uncached })}>
|
||||
{spoilerButton}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{children}
|
||||
|
||||
{(visible && !uncached) && (
|
||||
<div className='media-gallery__actions'>
|
||||
<button className='media-gallery__actions__pill' onClick={this.handleOpen}><FormattedMessage id='media_gallery.hide' defaultMessage='Hide' /></button>
|
||||
|
||||
@@ -372,26 +372,29 @@ class Status extends ImmutablePureComponent {
|
||||
const { isCollapsed } = this.state;
|
||||
if (!history) return;
|
||||
|
||||
if (e.button === 0 && !(e.ctrlKey || e.altKey || e.metaKey)) {
|
||||
if (isCollapsed) this.setCollapsed(false);
|
||||
else if (e.shiftKey) {
|
||||
this.setCollapsed(true);
|
||||
document.getSelection().removeAllRanges();
|
||||
} else if (this.props.onClick) {
|
||||
this.props.onClick();
|
||||
return;
|
||||
} else {
|
||||
if (destination === undefined) {
|
||||
destination = `/@${
|
||||
status.getIn(['reblog', 'account', 'acct'], status.getIn(['account', 'acct']))
|
||||
}/${
|
||||
status.getIn(['reblog', 'id'], status.get('id'))
|
||||
}`;
|
||||
}
|
||||
history.push(destination);
|
||||
}
|
||||
e.preventDefault();
|
||||
if (e.button !== 0 || e.ctrlKey || e.altKey || e.metaKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isCollapsed) this.setCollapsed(false);
|
||||
else if (e.shiftKey) {
|
||||
this.setCollapsed(true);
|
||||
document.getSelection().removeAllRanges();
|
||||
} else if (this.props.onClick) {
|
||||
this.props.onClick();
|
||||
return;
|
||||
} else {
|
||||
if (destination === undefined) {
|
||||
destination = `/@${
|
||||
status.getIn(['reblog', 'account', 'acct'], status.getIn(['account', 'acct']))
|
||||
}/${
|
||||
status.getIn(['reblog', 'id'], status.get('id'))
|
||||
}`;
|
||||
}
|
||||
history.push(destination);
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
handleToggleMediaVisibility = () => {
|
||||
@@ -648,7 +651,7 @@ class Status extends ImmutablePureComponent {
|
||||
media={status.get('media_attachments')}
|
||||
/>,
|
||||
);
|
||||
} else if (['image', 'gifv'].includes(status.getIn(['media_attachments', 0, 'type'])) || status.get('media_attachments').size > 1) {
|
||||
} else if (['image', 'gifv', 'unknown'].includes(status.getIn(['media_attachments', 0, 'type'])) || status.get('media_attachments').size > 1) {
|
||||
media.push(
|
||||
<Bundle fetchComponent={MediaGallery} loading={this.renderLoadingMediaGallery}>
|
||||
{Component => (
|
||||
@@ -806,7 +809,8 @@ class Status extends ImmutablePureComponent {
|
||||
{(connectReply || connectUp || connectToRoot) && <div className={classNames('status__line', { 'status__line--full': connectReply, 'status__line--first': !status.get('in_reply_to_id') && !connectToRoot })} />}
|
||||
|
||||
{(!muted || !isCollapsed) && (
|
||||
<header className='status__info'>
|
||||
/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */
|
||||
<header onClick={this.parseClick} className='status__info'>
|
||||
<StatusHeader
|
||||
status={status}
|
||||
friend={account}
|
||||
|
||||
@@ -233,7 +233,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||
menu.push({ text: intl.formatMessage(messages.share), action: this.handleShareClick });
|
||||
}
|
||||
|
||||
if (publicStatus && (signedIn || !isRemote)) {
|
||||
if (publicStatus && !isRemote) {
|
||||
menu.push({ text: intl.formatMessage(messages.embed), action: this.handleEmbed });
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
export enum BannerVariant {
|
||||
Yellow = 'yellow',
|
||||
Blue = 'blue',
|
||||
Warning = 'warning',
|
||||
Filter = 'filter',
|
||||
}
|
||||
|
||||
export const StatusBanner: React.FC<{
|
||||
@@ -11,9 +11,9 @@ export const StatusBanner: React.FC<{
|
||||
expanded?: boolean;
|
||||
onClick?: () => void;
|
||||
}> = ({ children, variant, expanded, onClick }) => (
|
||||
<div
|
||||
<label
|
||||
className={
|
||||
variant === BannerVariant.Yellow
|
||||
variant === BannerVariant.Warning
|
||||
? 'content-warning'
|
||||
: 'content-warning content-warning--filter'
|
||||
}
|
||||
@@ -26,6 +26,11 @@ export const StatusBanner: React.FC<{
|
||||
id='content_warning.hide'
|
||||
defaultMessage='Hide post'
|
||||
/>
|
||||
) : variant === BannerVariant.Warning ? (
|
||||
<FormattedMessage
|
||||
id='content_warning.show_more'
|
||||
defaultMessage='Show more'
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
id='content_warning.show'
|
||||
@@ -33,5 +38,5 @@ export const StatusBanner: React.FC<{
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</label>
|
||||
);
|
||||
|
||||
@@ -18,15 +18,10 @@ export default class StatusHeader extends PureComponent {
|
||||
parseClick: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
// Handles clicks on account name/image
|
||||
handleClick = (acct, e) => {
|
||||
const { parseClick } = this.props;
|
||||
parseClick(e, `/@${acct}`);
|
||||
};
|
||||
|
||||
handleAccountClick = (e) => {
|
||||
const { status } = this.props;
|
||||
this.handleClick(status.getIn(['account', 'acct']), e);
|
||||
const { status, parseClick } = this.props;
|
||||
parseClick(e, `/@${status.getIn(['account', 'acct'])}`);
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
// Rendering.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Provider } from 'react-redux';
|
||||
|
||||
import { fetchCustomEmojis } from 'flavours/glitch/actions/custom_emojis';
|
||||
import { fetchServer } from 'flavours/glitch/actions/server';
|
||||
import { hydrateStore } from 'flavours/glitch/actions/store';
|
||||
import { Router } from 'flavours/glitch/components/router';
|
||||
import Compose from 'flavours/glitch/features/standalone/compose';
|
||||
@@ -13,6 +14,7 @@ if (initialState) {
|
||||
}
|
||||
|
||||
store.dispatch(fetchCustomEmojis());
|
||||
store.dispatch(fetchServer());
|
||||
|
||||
const ComposeContainer = () => (
|
||||
<IntlProvider>
|
||||
|
||||
@@ -4,9 +4,12 @@ import axios from 'axios';
|
||||
import ready from 'flavours/glitch/ready';
|
||||
|
||||
async function checkConfirmation() {
|
||||
const response = await axios.get('/api/v1/emails/check_confirmation');
|
||||
const response = await axios.get('/api/v1/emails/check_confirmation', {
|
||||
headers: { Accept: 'application/json' },
|
||||
withCredentials: true,
|
||||
});
|
||||
|
||||
if (response.data) {
|
||||
if (response.status === 200 && response.data === true) {
|
||||
window.location.href = '/start';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +100,7 @@ class Bookmarks extends ImmutablePureComponent {
|
||||
onLoadMore={this.handleLoadMore}
|
||||
emptyMessage={emptyMessage}
|
||||
bindToDocument={!multiColumn}
|
||||
timelineId='bookmarks'
|
||||
/>
|
||||
|
||||
<Helmet>
|
||||
|
||||
@@ -27,15 +27,19 @@ class ColumnSettings extends PureComponent {
|
||||
|
||||
return (
|
||||
<div className='column-settings'>
|
||||
<div className='column-settings__row'>
|
||||
<SettingToggle settings={settings} settingPath={['other', 'onlyMedia']} onChange={onChange} label={<FormattedMessage id='community.column_settings.media_only' defaultMessage='Media only' />} />
|
||||
</div>
|
||||
<section>
|
||||
<div className='column-settings__row'>
|
||||
<SettingToggle settings={settings} settingPath={['other', 'onlyMedia']} onChange={onChange} label={<FormattedMessage id='community.column_settings.media_only' defaultMessage='Media only' />} />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<span className='column-settings__section'><FormattedMessage id='home.column_settings.advanced' defaultMessage='Advanced' /></span>
|
||||
<section>
|
||||
<span className='column-settings__section'><FormattedMessage id='home.column_settings.advanced' defaultMessage='Advanced' /></span>
|
||||
|
||||
<div className='column-settings__row'>
|
||||
<SettingText settings={settings} settingPath={['regex', 'body']} onChange={onChange} label={intl.formatMessage(messages.filter_regex)} />
|
||||
</div>
|
||||
<div className='column-settings__row'>
|
||||
<SettingText settings={settings} settingPath={['regex', 'body']} onChange={onChange} label={intl.formatMessage(messages.filter_regex)} />
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -97,30 +97,30 @@ const emojifyTextNode = (node, customEmojis) => {
|
||||
const { filename, shortCode } = unicodeMapping[unicode_emoji];
|
||||
const title = shortCode ? `:${shortCode}:` : '';
|
||||
|
||||
replacement = document.createElement('picture');
|
||||
|
||||
const isSystemTheme = !!document.body?.classList.contains('theme-system');
|
||||
|
||||
if(isSystemTheme) {
|
||||
let source = document.createElement('source');
|
||||
source.setAttribute('media', '(prefers-color-scheme: dark)');
|
||||
source.setAttribute('srcset', `${assetHost}/emoji/${emojiFilename(filename, "dark")}.svg`);
|
||||
replacement.appendChild(source);
|
||||
}
|
||||
const theme = (isSystemTheme || document.body?.classList.contains('theme-mastodon-light')) ? 'light' : 'dark';
|
||||
|
||||
let img = document.createElement('img');
|
||||
const imageFilename = emojiFilename(filename, theme);
|
||||
|
||||
const img = document.createElement('img');
|
||||
img.setAttribute('draggable', 'false');
|
||||
img.setAttribute('class', 'emojione');
|
||||
img.setAttribute('alt', unicode_emoji);
|
||||
img.setAttribute('title', title);
|
||||
img.setAttribute('src', `${assetHost}/emoji/${imageFilename}.svg`);
|
||||
|
||||
let theme = "light";
|
||||
if (isSystemTheme && imageFilename !== emojiFilename(filename, 'dark')) {
|
||||
replacement = document.createElement('picture');
|
||||
|
||||
if(!isSystemTheme && !document.body?.classList.contains('skin-mastodon-light'))
|
||||
theme = "dark";
|
||||
|
||||
img.setAttribute('src', `${assetHost}/emoji/${emojiFilename(filename, theme)}.svg`);
|
||||
replacement.appendChild(img);
|
||||
const source = document.createElement('source');
|
||||
source.setAttribute('media', '(prefers-color-scheme: dark)');
|
||||
source.setAttribute('srcset', `${assetHost}/emoji/${emojiFilename(filename, 'dark')}.svg`);
|
||||
replacement.appendChild(source);
|
||||
replacement.appendChild(img);
|
||||
} else {
|
||||
replacement = img;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the processed-up-to-now string and the emoji replacement
|
||||
@@ -135,7 +135,7 @@ const emojifyTextNode = (node, customEmojis) => {
|
||||
};
|
||||
|
||||
const emojifyNode = (node, customEmojis) => {
|
||||
for (const child of node.childNodes) {
|
||||
for (const child of Array.from(node.childNodes)) {
|
||||
switch(child.nodeType) {
|
||||
case Node.TEXT_NODE:
|
||||
emojifyTextNode(child, customEmojis);
|
||||
|
||||
@@ -100,6 +100,7 @@ class Favourites extends ImmutablePureComponent {
|
||||
onLoadMore={this.handleLoadMore}
|
||||
emptyMessage={emptyMessage}
|
||||
bindToDocument={!multiColumn}
|
||||
timelineId='favourites'
|
||||
/>
|
||||
|
||||
<Helmet>
|
||||
|
||||
@@ -129,8 +129,13 @@ export const InlineFollowSuggestions = ({ hidden }) => {
|
||||
return;
|
||||
}
|
||||
|
||||
setCanScrollLeft(bodyRef.current.scrollLeft > 0);
|
||||
setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth);
|
||||
if (getComputedStyle(bodyRef.current).direction === 'rtl') {
|
||||
setCanScrollLeft((bodyRef.current.clientWidth - bodyRef.current.scrollLeft) < bodyRef.current.scrollWidth);
|
||||
setCanScrollRight(bodyRef.current.scrollLeft < 0);
|
||||
} else {
|
||||
setCanScrollLeft(bodyRef.current.scrollLeft > 0);
|
||||
setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth);
|
||||
}
|
||||
}, [setCanScrollRight, setCanScrollLeft, bodyRef, suggestions]);
|
||||
|
||||
const handleLeftNav = useCallback(() => {
|
||||
@@ -146,8 +151,13 @@ export const InlineFollowSuggestions = ({ hidden }) => {
|
||||
return;
|
||||
}
|
||||
|
||||
setCanScrollLeft(bodyRef.current.scrollLeft > 0);
|
||||
setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth);
|
||||
if (getComputedStyle(bodyRef.current).direction === 'rtl') {
|
||||
setCanScrollLeft((bodyRef.current.clientWidth - bodyRef.current.scrollLeft) < bodyRef.current.scrollWidth);
|
||||
setCanScrollRight(bodyRef.current.scrollLeft < 0);
|
||||
} else {
|
||||
setCanScrollLeft(bodyRef.current.scrollLeft > 0);
|
||||
setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth);
|
||||
}
|
||||
}, [setCanScrollRight, setCanScrollLeft, bodyRef]);
|
||||
|
||||
const handleDismiss = useCallback(() => {
|
||||
|
||||
@@ -169,6 +169,15 @@ class LocalSettingsPage extends PureComponent {
|
||||
<FormattedMessage id='settings.wide_view' defaultMessage='Wide view (Desktop mode only)' />
|
||||
<span className='hint'><FormattedMessage id='settings.wide_view_hint' defaultMessage='Stretches columns to better fill the available space.' /></span>
|
||||
</LocalSettingsPageItem>
|
||||
<LocalSettingsPageItem
|
||||
settings={settings}
|
||||
item={['fullwidth_columns']}
|
||||
id='mastodon-settings--fullwidth_columns'
|
||||
onChange={onChange}
|
||||
>
|
||||
<FormattedMessage id='settings.fullwidth_view' defaultMessage='Stretch columns to full width (Desktop mode only)' />
|
||||
<span className='hint'><FormattedMessage id='settings.fullwidth_view_hint' defaultMessage='Stretches columns to fill all the available space.' /></span>
|
||||
</LocalSettingsPageItem>
|
||||
</section>
|
||||
</div>
|
||||
),
|
||||
|
||||
@@ -40,6 +40,7 @@ class ColumnSettings extends PureComponent {
|
||||
const alertStr = <FormattedMessage id='notifications.column_settings.alert' defaultMessage='Desktop notifications' />;
|
||||
const showStr = <FormattedMessage id='notifications.column_settings.show' defaultMessage='Show in column' />;
|
||||
const soundStr = <FormattedMessage id='notifications.column_settings.sound' defaultMessage='Play sound' />;
|
||||
const groupStr = <FormattedMessage id='notifications.column_settings.group' defaultMessage='Group' />;
|
||||
|
||||
const showPushSettings = pushSettings.get('browserSupport') && pushSettings.get('isSubscribed');
|
||||
const pushStr = showPushSettings && <FormattedMessage id='notifications.column_settings.push' defaultMessage='Push notifications' />;
|
||||
@@ -96,6 +97,10 @@ class ColumnSettings extends PureComponent {
|
||||
<PillBarButton prefix='notifications' settings={settings} settingPath={['shows', 'follow']} onChange={onChange} label={showStr} />
|
||||
<PillBarButton prefix='notifications' settings={settings} settingPath={['sounds', 'follow']} onChange={onChange} label={soundStr} />
|
||||
</div>
|
||||
|
||||
<div className='column-settings__row'>
|
||||
<SettingToggle prefix='notifications' settings={settings} settingPath={['group', 'follow']} onChange={onChange} label={groupStr} />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section role='group' aria-labelledby='notifications-follow-request'>
|
||||
|
||||
@@ -56,11 +56,12 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
} else {
|
||||
dispatch(changeSetting(['notifications', ...path], checked));
|
||||
}
|
||||
} else if(path[0] === 'groupingBeta') {
|
||||
dispatch(changeSetting(['notifications', ...path], checked));
|
||||
dispatch(initializeNotifications());
|
||||
} else {
|
||||
dispatch(changeSetting(['notifications', ...path], checked));
|
||||
|
||||
if(path[0] === 'group' && path[1] === 'follow') {
|
||||
dispatch(initializeNotifications());
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import PersonAddIcon from '@/material-icons/400-24px/person_add-fill.svg?react';
|
||||
import { FollowersCounter } from 'flavours/glitch/components/counters';
|
||||
import { FollowButton } from 'flavours/glitch/components/follow_button';
|
||||
import { ShortNumber } from 'flavours/glitch/components/short_number';
|
||||
import { me } from 'flavours/glitch/initial_state';
|
||||
import type { NotificationGroupFollow } from 'flavours/glitch/models/notification_group';
|
||||
import { useAppSelector } from 'flavours/glitch/store';
|
||||
|
||||
import type { LabelRenderer } from './notification_group_with_status';
|
||||
import { NotificationGroupWithStatus } from './notification_group_with_status';
|
||||
|
||||
const labelRenderer: LabelRenderer = (displayedName, total) => {
|
||||
const labelRenderer: LabelRenderer = (displayedName, total, seeMoreHref) => {
|
||||
if (total === 1)
|
||||
return (
|
||||
<FormattedMessage
|
||||
@@ -23,10 +26,12 @@ const labelRenderer: LabelRenderer = (displayedName, total) => {
|
||||
return (
|
||||
<FormattedMessage
|
||||
id='notification.follow.name_and_others'
|
||||
defaultMessage='{name} and {count, plural, one {# other} other {# others}} followed you'
|
||||
defaultMessage='{name} and <a>{count, plural, one {# other} other {# others}}</a> followed you'
|
||||
values={{
|
||||
name: displayedName,
|
||||
count: total - 1,
|
||||
a: (chunks) =>
|
||||
seeMoreHref ? <Link to={seeMoreHref}>{chunks}</Link> : chunks,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -46,6 +51,10 @@ export const NotificationFollow: React.FC<{
|
||||
notification: NotificationGroupFollow;
|
||||
unread: boolean;
|
||||
}> = ({ notification, unread }) => {
|
||||
const username = useAppSelector(
|
||||
(state) => state.accounts.getIn([me, 'username']) as string,
|
||||
);
|
||||
|
||||
let actions: JSX.Element | undefined;
|
||||
let additionalContent: JSX.Element | undefined;
|
||||
|
||||
@@ -68,6 +77,7 @@ export const NotificationFollow: React.FC<{
|
||||
timestamp={notification.latest_page_notification_at}
|
||||
count={notification.notifications_count}
|
||||
labelRenderer={labelRenderer}
|
||||
labelSeeMoreHref={`/@${username}/followers`}
|
||||
unread={unread}
|
||||
actions={actions}
|
||||
additionalContent={additionalContent}
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
import type { IconProp } from 'flavours/glitch/components/icon';
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import Status from 'flavours/glitch/containers/status_container';
|
||||
import { getStatusHidden } from 'flavours/glitch/selectors/filters';
|
||||
import { useAppSelector, useAppDispatch } from 'flavours/glitch/store';
|
||||
|
||||
import { DisplayedName } from './displayed_name';
|
||||
@@ -51,6 +52,12 @@ export const NotificationWithStatus: React.FC<{
|
||||
(state) => state.statuses.getIn([statusId, 'visibility']) === 'direct',
|
||||
);
|
||||
|
||||
const isFiltered = useAppSelector(
|
||||
(state) =>
|
||||
statusId &&
|
||||
getStatusHidden(state, { id: statusId, contextType: 'notifications' }),
|
||||
);
|
||||
|
||||
const handlers = useMemo(
|
||||
() => ({
|
||||
open: () => {
|
||||
@@ -77,7 +84,7 @@ export const NotificationWithStatus: React.FC<{
|
||||
[dispatch, statusId],
|
||||
);
|
||||
|
||||
if (!statusId) return null;
|
||||
if (!statusId || isFiltered) return null;
|
||||
|
||||
return (
|
||||
<HotKeys handlers={handlers}>
|
||||
|
||||
@@ -14,6 +14,7 @@ import { Icon } from 'flavours/glitch/components/icon';
|
||||
import {
|
||||
selectSettingsNotificationsQuickFilterActive,
|
||||
selectSettingsNotificationsQuickFilterAdvanced,
|
||||
selectSettingsNotificationsQuickFilterShow,
|
||||
} from 'flavours/glitch/selectors/settings';
|
||||
import { useAppDispatch, useAppSelector } from 'flavours/glitch/store';
|
||||
|
||||
@@ -65,6 +66,11 @@ export const FilterBar: React.FC = () => {
|
||||
const advancedMode = useAppSelector(
|
||||
selectSettingsNotificationsQuickFilterAdvanced,
|
||||
);
|
||||
const useFilterBar = useAppSelector(
|
||||
selectSettingsNotificationsQuickFilterShow,
|
||||
);
|
||||
|
||||
if (!useFilterBar) return null;
|
||||
|
||||
if (advancedMode)
|
||||
return (
|
||||
|
||||
@@ -14,6 +14,8 @@ import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react';
|
||||
import ReplyIcon from '@/material-icons/400-24px/reply.svg?react';
|
||||
import ReplyAllIcon from '@/material-icons/400-24px/reply_all.svg?react';
|
||||
import StarIcon from '@/material-icons/400-24px/star.svg?react';
|
||||
import RepeatDisabledIcon from '@/svg-icons/repeat_disabled.svg?react';
|
||||
import RepeatPrivateIcon from '@/svg-icons/repeat_private.svg?react';
|
||||
import { replyCompose } from 'flavours/glitch/actions/compose';
|
||||
import { toggleReblog, toggleFavourite } from 'flavours/glitch/actions/interactions';
|
||||
import { openModal } from 'flavours/glitch/actions/modal';
|
||||
@@ -161,16 +163,20 @@ class Footer extends ImmutablePureComponent {
|
||||
replyTitle = intl.formatMessage(messages.replyAll);
|
||||
}
|
||||
|
||||
let reblogTitle = '';
|
||||
let reblogTitle, reblogIconComponent;
|
||||
|
||||
if (status.get('reblogged')) {
|
||||
reblogTitle = intl.formatMessage(messages.cancel_reblog_private);
|
||||
reblogIconComponent = publicStatus ? RepeatIcon : RepeatPrivateIcon;
|
||||
} else if (publicStatus) {
|
||||
reblogTitle = intl.formatMessage(messages.reblog);
|
||||
reblogIconComponent = RepeatIcon;
|
||||
} else if (reblogPrivate) {
|
||||
reblogTitle = intl.formatMessage(messages.reblog_private);
|
||||
reblogIconComponent = RepeatPrivateIcon;
|
||||
} else {
|
||||
reblogTitle = intl.formatMessage(messages.cannot_reblog);
|
||||
reblogIconComponent = RepeatDisabledIcon;
|
||||
}
|
||||
|
||||
let replyButton = null;
|
||||
@@ -201,7 +207,7 @@ class Footer extends ImmutablePureComponent {
|
||||
return (
|
||||
<div className='picture-in-picture__footer'>
|
||||
{replyButton}
|
||||
<IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={RepeatIcon} onClick={this.handleReblogClick} counter={status.get('reblogs_count')} />
|
||||
<IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={reblogIconComponent} onClick={this.handleReblogClick} counter={status.get('reblogs_count')} />
|
||||
<IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={StarIcon} onClick={this.handleFavouriteClick} counter={status.get('favourites_count')} />
|
||||
{withOpenButton && <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.open)} icon='external-link' iconComponent={OpenInNewIcon} onClick={this.handleOpenClick} href={status.get('url')} />}
|
||||
</div>
|
||||
|
||||
@@ -14,6 +14,7 @@ import { Link } from 'react-router-dom';
|
||||
import { AnimatedNumber } from 'flavours/glitch/components/animated_number';
|
||||
import AttachmentList from 'flavours/glitch/components/attachment_list';
|
||||
import EditedTimestamp from 'flavours/glitch/components/edited_timestamp';
|
||||
import { FilterWarning } from 'flavours/glitch/components/filter_warning';
|
||||
import type { StatusLike } from 'flavours/glitch/components/hashtag_bar';
|
||||
import { getHashtagBarForStatus } from 'flavours/glitch/components/hashtag_bar';
|
||||
import { IconLogo } from 'flavours/glitch/components/logo';
|
||||
@@ -72,6 +73,7 @@ export const DetailedStatus: React.FC<{
|
||||
}) => {
|
||||
const properStatus = status?.get('reblog') ?? status;
|
||||
const [height, setHeight] = useState(0);
|
||||
const [showDespiteFilter, setShowDespiteFilter] = useState(false);
|
||||
const nodeRef = useRef<HTMLDivElement>();
|
||||
const history = useAppHistory();
|
||||
|
||||
@@ -108,6 +110,10 @@ export const DetailedStatus: React.FC<{
|
||||
[onOpenVideo, status],
|
||||
);
|
||||
|
||||
const handleFilterToggle = useCallback(() => {
|
||||
setShowDespiteFilter(!showDespiteFilter);
|
||||
}, [showDespiteFilter, setShowDespiteFilter]);
|
||||
|
||||
const _measureHeight = useCallback(
|
||||
(heightJustChanged?: boolean) => {
|
||||
if (measureHeight && nodeRef.current) {
|
||||
@@ -196,7 +202,7 @@ export const DetailedStatus: React.FC<{
|
||||
) {
|
||||
media.push(<AttachmentList media={status.get('media_attachments')} />);
|
||||
} else if (
|
||||
['image', 'gifv'].includes(
|
||||
['image', 'gifv', 'unknown'].includes(
|
||||
status.getIn(['media_attachments', 0, 'type']) as string,
|
||||
) ||
|
||||
status.get('media_attachments').size > 1
|
||||
@@ -259,6 +265,7 @@ export const DetailedStatus: React.FC<{
|
||||
src={attachment.get('url')}
|
||||
alt={description}
|
||||
lang={language}
|
||||
inline
|
||||
width={300}
|
||||
height={150}
|
||||
onOpenVideo={handleOpenVideo}
|
||||
@@ -272,12 +279,12 @@ export const DetailedStatus: React.FC<{
|
||||
);
|
||||
mediaIcons.push('video-camera');
|
||||
}
|
||||
} else if (status.get('spoiler_text').length === 0) {
|
||||
} else if (status.get('card')) {
|
||||
media.push(
|
||||
<Card
|
||||
sensitive={status.get('sensitive')}
|
||||
onOpenMedia={onOpenMedia}
|
||||
card={status.get('card', null)}
|
||||
card={status.get('card')}
|
||||
/>,
|
||||
);
|
||||
mediaIcons.push('link');
|
||||
@@ -357,6 +364,8 @@ export const DetailedStatus: React.FC<{
|
||||
);
|
||||
contentMedia.push(hashtagBar);
|
||||
|
||||
const matchedFilters = status.get('matched_filters');
|
||||
|
||||
return (
|
||||
<div style={outerStyle}>
|
||||
<div
|
||||
@@ -385,22 +394,32 @@ export const DetailedStatus: React.FC<{
|
||||
)}
|
||||
</Permalink>
|
||||
|
||||
<StatusContent
|
||||
status={status}
|
||||
media={contentMedia}
|
||||
extraMedia={extraMedia}
|
||||
mediaIcons={contentMediaIcons}
|
||||
expanded={expanded}
|
||||
collapsed={false}
|
||||
onExpandedToggle={onToggleHidden}
|
||||
onTranslate={handleTranslate}
|
||||
onUpdate={handleChildUpdate}
|
||||
tagLinks={tagMisleadingLinks}
|
||||
rewriteMentions={rewriteMentions}
|
||||
parseClick={parseClick}
|
||||
disabled
|
||||
{...(statusContentProps as any)}
|
||||
/>
|
||||
{matchedFilters && (
|
||||
<FilterWarning
|
||||
title={matchedFilters.join(', ')}
|
||||
expanded={showDespiteFilter}
|
||||
onClick={handleFilterToggle}
|
||||
/>
|
||||
)}
|
||||
|
||||
{(!matchedFilters || showDespiteFilter) && (
|
||||
<StatusContent
|
||||
status={status}
|
||||
media={contentMedia}
|
||||
extraMedia={extraMedia}
|
||||
mediaIcons={contentMediaIcons}
|
||||
expanded={expanded}
|
||||
collapsed={false}
|
||||
onExpandedToggle={onToggleHidden}
|
||||
onTranslate={handleTranslate}
|
||||
onUpdate={handleChildUpdate}
|
||||
tagLinks={tagMisleadingLinks}
|
||||
rewriteMentions={rewriteMentions}
|
||||
parseClick={parseClick}
|
||||
disabled
|
||||
{...(statusContentProps as any)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className='detailed-status__meta'>
|
||||
<div className='detailed-status__meta__line'>
|
||||
|
||||
@@ -133,7 +133,7 @@ const makeMapStateToProps = () => {
|
||||
});
|
||||
|
||||
const mapStateToProps = (state, props) => {
|
||||
const status = getStatus(state, { id: props.params.statusId });
|
||||
const status = getStatus(state, { id: props.params.statusId, contextType: 'detailed' });
|
||||
|
||||
let ancestorsIds = Immutable.List();
|
||||
let descendantsIds = Immutable.List();
|
||||
|
||||
@@ -136,6 +136,8 @@ export const BoostModal: React.FC<{
|
||||
? messages.cancel_reblog
|
||||
: messages.reblog,
|
||||
)}
|
||||
/* eslint-disable-next-line jsx-a11y/no-autofocus -- We are in the modal */
|
||||
autoFocus
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -116,6 +116,7 @@ export const MuteModal = ({ accountId, acct }) => {
|
||||
<div className='safety-action-modal__bottom__collapsible'>
|
||||
<div className='safety-action-modal__field-group'>
|
||||
<RadioButtonLabel name='duration' value='0' label={intl.formatMessage(messages.indefinite)} currentValue={muteDuration} onChange={handleChangeMuteDuration} />
|
||||
<RadioButtonLabel name='duration' value='21600' label={intl.formatMessage(messages.hours, { number: 6 })} currentValue={muteDuration} onChange={handleChangeMuteDuration} />
|
||||
<RadioButtonLabel name='duration' value='86400' label={intl.formatMessage(messages.hours, { number: 24 })} currentValue={muteDuration} onChange={handleChangeMuteDuration} />
|
||||
<RadioButtonLabel name='duration' value='604800' label={intl.formatMessage(messages.days, { number: 7 })} currentValue={muteDuration} onChange={handleChangeMuteDuration} />
|
||||
<RadioButtonLabel name='duration' value='2592000' label={intl.formatMessage(messages.days, { number: 30 })} currentValue={muteDuration} onChange={handleChangeMuteDuration} />
|
||||
|
||||
@@ -21,6 +21,7 @@ import { Permalink } from 'flavours/glitch/components/permalink';
|
||||
import { PictureInPicture } from 'flavours/glitch/features/picture_in_picture';
|
||||
import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context';
|
||||
import { layoutFromWindow } from 'flavours/glitch/is_mobile';
|
||||
import { selectUnreadNotificationGroupsCount } from 'flavours/glitch/selectors/notifications';
|
||||
import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router';
|
||||
|
||||
import { uploadCompose, resetCompose, changeComposeSpoilerness } from '../../actions/compose';
|
||||
@@ -90,7 +91,8 @@ const mapStateToProps = state => ({
|
||||
hasMediaAttachments: state.getIn(['compose', 'media_attachments']).size > 0,
|
||||
canUploadMore: !state.getIn(['compose', 'media_attachments']).some(x => ['audio', 'video'].includes(x.get('type'))) && state.getIn(['compose', 'media_attachments']).size < 4,
|
||||
isWide: state.getIn(['local_settings', 'stretch']),
|
||||
unreadNotifications: state.getIn(['notifications', 'unread']),
|
||||
fullWidthColumns: state.getIn(['local_settings', 'fullwidth_columns']),
|
||||
unreadNotifications: selectUnreadNotificationGroupsCount(state),
|
||||
showFaviconBadge: state.getIn(['local_settings', 'notifications', 'favicon_badge']),
|
||||
hicolorPrivacyIcons: state.getIn(['local_settings', 'hicolor_privacy_icons']),
|
||||
moved: state.getIn(['accounts', me, 'moved']) && state.getIn(['accounts', state.getIn(['accounts', me, 'moved'])]),
|
||||
@@ -269,6 +271,7 @@ class UI extends PureComponent {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
children: PropTypes.node,
|
||||
isWide: PropTypes.bool,
|
||||
fullWidthColumns: PropTypes.bool,
|
||||
systemFontUi: PropTypes.bool,
|
||||
isComposing: PropTypes.bool,
|
||||
hasComposingText: PropTypes.bool,
|
||||
@@ -607,6 +610,7 @@ class UI extends PureComponent {
|
||||
|
||||
const className = classNames('ui', {
|
||||
'wide': isWide,
|
||||
'fullwidth-columns': this.props.fullWidthColumns,
|
||||
'system-font': this.props.systemFontUi,
|
||||
'hicolor-privacy-icons': this.props.hicolorPrivacyIcons,
|
||||
});
|
||||
|
||||
@@ -1,17 +1,55 @@
|
||||
{
|
||||
"about.fork_disclaimer": "Glitch-soc je svobodný software s otevřeným zdrojovým kódem založený na Mastodonu.",
|
||||
"account.disclaimer_full": "Níže uvedené informace mohou popisovat uživatelský profil neúplně.",
|
||||
"account.follows": "Sleduje",
|
||||
"account.follows_you": "Sleduje vás",
|
||||
"account.suspended_disclaimer_full": "Tento uživatel byl pozastaven moderátorem.",
|
||||
"account.view_full_profile": "Zobrazit celý profil",
|
||||
"boost_modal.missing_description": "Příspěvek obsahuje obrázky bez popisků",
|
||||
"column.favourited_by": "Oblíbeno uživatelem",
|
||||
"column.heading": "Různé",
|
||||
"column.reblogged_by": "Boostnuto uživatelem",
|
||||
"column.subheading": "Různé",
|
||||
"column_header.profile": "Profil",
|
||||
"column_subheading.lists": "Seznamy",
|
||||
"column_subheading.navigation": "Navigace",
|
||||
"community.column_settings.allow_local_only": "Zobrazit pouze místní tooty",
|
||||
"compose.attach.doodle": "Nakreslete něco",
|
||||
"compose.change_federation": "Změnit nastavení federace",
|
||||
"compose.content-type.change": "Změnit pokročilé možnosti formátování",
|
||||
"compose.content-type.html": "HTML",
|
||||
"compose.content-type.html_meta": "Formátovat příspěvky pomocí HTML",
|
||||
"compose.content-type.markdown": "Markdown",
|
||||
"compose.content-type.markdown_meta": "Formátovat příspěvky pomocí Markdown",
|
||||
"compose.content-type.plain": "Prostý text",
|
||||
"compose.content-type.plain_meta": "Psát bez pokročilého formátování",
|
||||
"compose.disable_threaded_mode": "Zakázat režim vláken",
|
||||
"compose.enable_threaded_mode": "Povolit režim vláken",
|
||||
"compose_form.sensitive.hide": "{count, plural, one {Označit médium za citlivé} other {Označit média za citlivá}}",
|
||||
"compose_form.sensitive.marked": "{count, plural, one {Médium je označeno jako citlivé} other {Média jsou označena jako citlivá}}",
|
||||
"compose_form.sensitive.unmarked": "{count, plural, one {Médium není označeno za citlivé} other {Média nejsou označena za citlivá}}",
|
||||
"confirmation_modal.do_not_ask_again": "Příště se už neptat",
|
||||
"confirmations.deprecated_settings.confirm": "Použít nastavení Mastodon",
|
||||
"confirmations.deprecated_settings.message": "Některé z glitch-soc, zařízeních specifických {app_settings}, které používáte, byly nahrazeny {preferences} Mastodonu a budou přepsány:",
|
||||
"confirmations.missing_media_description.confirm": "Přesto odeslat",
|
||||
"confirmations.missing_media_description.edit": "Upravit média",
|
||||
"confirmations.missing_media_description.message": "Alespoň jedna příloha nemá popisek. Zvažte popsání všech příloh pro zrakově postižené před odesláním tootu.",
|
||||
"direct.group_by_conversations": "Seskupit do konverzací",
|
||||
"endorsed_accounts_editor.endorsed_accounts": "Vybrané účty",
|
||||
"favourite_modal.favourite": "Oblíbit si příspěvek?",
|
||||
"federation.federated.long": "Povolit tomuto příspěvku přístup na jiné servery",
|
||||
"federation.federated.short": "Federováno",
|
||||
"federation.local_only.long": "Zabránit tomuto příspěvku v přístupu k jiným serverům",
|
||||
"federation.local_only.short": "Lokální příspěvek",
|
||||
"firehose.column_settings.allow_local_only": "Zobrazit pouze lokální příspěvky ve \"Vše\"",
|
||||
"home.column_settings.advanced": "Pokročilé",
|
||||
"home.column_settings.filter_regex": "Filtrovat podle regulárních výrazů",
|
||||
"home.column_settings.show_direct": "Zobrazit přímé zprávy",
|
||||
"home.column_settings.show_direct": "Zobrazit soukromé zmínky",
|
||||
"home.settings": "Nastavení sloupců",
|
||||
"keyboard_shortcuts.bookmark": "Přidat do záložek",
|
||||
"keyboard_shortcuts.secondary_toot": "Odeslat příspěvek s druhotným nastavením soukromí",
|
||||
"keyboard_shortcuts.secondary_toot": "pro odeslání příspěvku s sekundárním nastavením soukromí",
|
||||
"keyboard_shortcuts.toggle_collapse": "Sbalit/rozbalit příspěvek",
|
||||
"moved_to_warning": "Tento účet je označen jako přesunut na {moved_to_link}, a proto nemusí přijímat nové sledování.",
|
||||
"navigation_bar.app_settings": "Nastavení aplikace",
|
||||
"navigation_bar.featured_users": "Vybraní uživatelé",
|
||||
"navigation_bar.keyboard_shortcuts": "Klávesové zkratky",
|
||||
@@ -22,11 +60,13 @@
|
||||
"notification_purge.btn_invert": "Obrátit\nvýběr",
|
||||
"notification_purge.btn_none": "Nevybrat\nnic",
|
||||
"notification_purge.start": "Čistící režim",
|
||||
"notifications.column_settings.filter_bar.show_bar": "Zobrazit panel filtrů",
|
||||
"notifications.marked_clear": "Smazat vybraná oznámení",
|
||||
"notifications.marked_clear_confirmation": "Určitě chcete trvale smazat všechna vybraná oznámení?",
|
||||
"settings.always_show_spoilers_field": "Vždy zobrazit pole pro varování o obsahu",
|
||||
"settings.auto_collapse": "Automaticky sbalit",
|
||||
"settings.auto_collapse_all": "Všechno",
|
||||
"settings.auto_collapse_height": "Výška (v pixelech) pro toot považována za dlouhou",
|
||||
"settings.auto_collapse_lengthy": "Dlouhé příspěvky",
|
||||
"settings.auto_collapse_media": "Příspěvky s přílohami",
|
||||
"settings.auto_collapse_notifications": "Oznámení",
|
||||
@@ -50,6 +90,8 @@
|
||||
"settings.enable_collapsed": "Povolit sbalené příspěvky",
|
||||
"settings.enable_collapsed_hint": "U sbalených příspěvků je část jejich obsahu skrytá, aby zabraly méně místa na obrazovce. (Tohle není stejná funkce jako varování o obsahu.)",
|
||||
"settings.enable_content_warnings_auto_unfold": "Vždy rozbalit příspěvky označené varováním o obsahu",
|
||||
"settings.fullwidth_view": "Roztáhnout sloupce na celou šířku (pouze ve verzi pro počítač)",
|
||||
"settings.fullwidth_view_hint": "Sloupce se roztáhnou, aby vyplnily veškerý dostupný prostor.",
|
||||
"settings.general": "Obecné",
|
||||
"settings.hicolor_privacy_icons": "Barevné ikony soukromí",
|
||||
"settings.hicolor_privacy_icons.hint": "Zobrazit ikony úrovně soukromí příspěvků v jasných, snadno rozlišitelných barvách",
|
||||
@@ -73,17 +115,18 @@
|
||||
"settings.pop_in_player": "Povolit plovoucí okno přehrávače",
|
||||
"settings.pop_in_position": "Pozice plovoucího okna:",
|
||||
"settings.pop_in_right": "Vpravo",
|
||||
"settings.preferences": "Předvolby",
|
||||
"settings.preferences": "Uživatelské předvolby",
|
||||
"settings.prepend_cw_re": "Při odpovídání přidat před varování o obsahu “re: ”",
|
||||
"settings.preselect_on_reply": "Při odpovědi označit uživatelská jména",
|
||||
"settings.preselect_on_reply": "Při odpovědi před-vybrat uživatelská jména",
|
||||
"settings.preselect_on_reply_hint": "Při odpovídání na konverzaci s více účastníky se jména všech kromě prvního označí, aby šla jednoduše smazat",
|
||||
"settings.rewrite_mentions": "Přepsat zmínky v zobrazených příspěvcích",
|
||||
"settings.rewrite_mentions_acct": "Přepsat uživatelským jménem a doménou (pokud je účet na jiném serveru)",
|
||||
"settings.rewrite_mentions_no": "Nepřepisovat zmínky",
|
||||
"settings.rewrite_mentions_username": "Přepsat uživatelským jménem",
|
||||
"settings.shared_settings_link": "předvolbách Mastodonu",
|
||||
"settings.shared_settings_link": "uživatelské předvolby",
|
||||
"settings.show_action_bar": "Zobrazit ve sbalených příspěvcích tlačítka s akcemi",
|
||||
"settings.show_content_type_choice": "Zobrazit volbu formátu příspěvku",
|
||||
"settings.show_published_toast": "Zobrazit gratulaci při publikování/ukládání příspěvku",
|
||||
"settings.show_reply_counter": "Zobrazit odhad počtu odpovědí",
|
||||
"settings.side_arm": "Vedlejší odesílací tlačítko:",
|
||||
"settings.side_arm.none": "Žádné",
|
||||
@@ -92,22 +135,26 @@
|
||||
"settings.side_arm_reply_mode.keep": "Použít svou nastavenou úroveň soukromí",
|
||||
"settings.side_arm_reply_mode.restrict": "Zvýšit úroveň soukromí nejméně na úroveň příspěvku, na který odpovídáte",
|
||||
"settings.status_icons": "Ikony u příspěvků",
|
||||
"settings.status_icons_language": "Indikace jazyk",
|
||||
"settings.status_icons_language": "Indikátor jazyka",
|
||||
"settings.status_icons_local_only": "Indikace lokálního příspěvku",
|
||||
"settings.status_icons_media": "Indikace obrázků a anket",
|
||||
"settings.status_icons_reply": "Indikace odpovědi",
|
||||
"settings.status_icons_visibility": "Indikace úrovně soukromí",
|
||||
"settings.swipe_to_change_columns": "Povolit změnu sloupců přejetím (pouze na mobilním telefonu)",
|
||||
"settings.tag_misleading_links": "Označit zavádějící odkazy",
|
||||
"settings.tag_misleading_links.hint": "Zobrazit skutečný cíl u každého odkazu, který ho explicitně nezmiňuje",
|
||||
"settings.wide_view": "Široké sloupce (pouze v režimu Desktop)",
|
||||
"settings.wide_view_hint": "Sloupce se roztáhnout, aby lépe vyplnily dostupný prostor.",
|
||||
"settings.wide_view_hint": "Sloupce se roztáhnou, aby lépe vyplnily dostupný prostor.",
|
||||
"status.collapse": "Sbalit",
|
||||
"status.filtered": "Filtrováno",
|
||||
"status.has_audio": "Obsahuje audio",
|
||||
"status.has_pictures": "Obsahuje obrázky",
|
||||
"status.has_preview_card": "Obsahuje náhled odkazu",
|
||||
"status.has_video": "Obsahuje video",
|
||||
"status.hide": "Skrýt příspěvek",
|
||||
"status.in_reply_to": "Tento příspěvek je odpověď",
|
||||
"status.is_poll": "Tento příspěvek je anketa",
|
||||
"status.local_only": "Viditelné pouze z vaší instance",
|
||||
"status.show_filter_reason": "Přesto zobrazit",
|
||||
"status.uncollapse": "Rozbalit"
|
||||
}
|
||||
|
||||
@@ -154,7 +154,5 @@
|
||||
"status.is_poll": "Dieser Toot ist eine Umfrage",
|
||||
"status.local_only": "Nur auf deiner Instanz sichtbar",
|
||||
"status.show_filter_reason": "Trotzdem anzeigen",
|
||||
"status.show_less": "Weniger anzeigen",
|
||||
"status.show_more": "Mehr anzeigen",
|
||||
"status.uncollapse": "Ausklappen"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,134 @@
|
||||
{
|
||||
"settings.content_warnings": "Content warnings",
|
||||
"settings.preferences": "Preferences"
|
||||
"about.fork_disclaimer": "Το Glitch-soc είναι ελεύθερο λογισμικό ανοιχτού κώδικα που είναι αντιγραφή από το Mastodon.",
|
||||
"account.disclaimer_full": "Οι παρακάτω πληροφορίες μπορεί να αντικατοπτρίζουν το προφίλ του χρήστη ελλιπώς.",
|
||||
"account.follows": "Ακολουθεί",
|
||||
"account.follows_you": "Σε ακολουθεί",
|
||||
"account.suspended_disclaimer_full": "Αυτός ο χρήστης έχει ανασταλεί από έναν συντονιστή.",
|
||||
"account.view_full_profile": "Προβολή πλήρους προφίλ",
|
||||
"boost_modal.missing_description": "Αυτό το τουτ περιέχει κάποια μέσα χωρίς περιγραφή",
|
||||
"column.favourited_by": "Αγαπήθηκε από",
|
||||
"column.heading": "Διάφορα",
|
||||
"column.reblogged_by": "Ενισχύθηκε από",
|
||||
"column.subheading": "Διάφορες επιλογές",
|
||||
"column_header.profile": "Προφίλ",
|
||||
"column_subheading.lists": "Λίστες",
|
||||
"column_subheading.navigation": "Πλοήγηση",
|
||||
"community.column_settings.allow_local_only": "Εμφάνιση τοπικών τουτ",
|
||||
"compose.attach.doodle": "Σχεδίασε κάτι",
|
||||
"compose.change_federation": "Αλλαγή ρυθμίσεων ομοσπονδίας",
|
||||
"compose.content-type.change": "Αλλαγή προηγμένων επιλογών μορφοποίησης",
|
||||
"compose.content-type.html": "HTML",
|
||||
"compose.content-type.html_meta": "Μορφοποίηση των αναρτήσεων σας με χρήση HTML",
|
||||
"compose.content-type.markdown": "Markdown",
|
||||
"compose.content-type.markdown_meta": "Μορφοποίηση των αναρτήσεων σας με χρήση Markdown",
|
||||
"compose.content-type.plain": "Απλό κείμενο",
|
||||
"compose.content-type.plain_meta": "Γράψιμο χωρίς προηγμένη μορφοποίηση",
|
||||
"compose.disable_threaded_mode": "Απενεργοποίηση λειτουργίας νημάτων",
|
||||
"compose.enable_threaded_mode": "Ενεργοποίηση λειτουργίας νημάτων",
|
||||
"compose_form.sensitive.hide": "{count, plural, one {Επισήμανση πολυμέσου ως ευαίσθητο} other {Επισήμανση πολυμέσων ως ευαίσθητα}}",
|
||||
"compose_form.sensitive.marked": "{count, plural, one {Το πολυμέσο έχει σημανθεί ως ευαίσθητο} other {Τα πολυμέσα έχουν σημανθεί ως ευαίσθητα}}",
|
||||
"compose_form.sensitive.unmarked": "{count, plural, one {Το πολυμέσο δεν έχει σημανθεί ως ευαίσθητο} other {Τα πολυμέσα δεν έχουν σημανθεί ως ευαίσθητα}}",
|
||||
"confirmation_modal.do_not_ask_again": "Να μην ζητηθεί επιβεβαίωση ξανά",
|
||||
"confirmations.deprecated_settings.confirm": "Χρήση προτιμήσεων του Mastodon",
|
||||
"confirmations.missing_media_description.confirm": "Αποστολή ούτως ή άλλως",
|
||||
"confirmations.missing_media_description.edit": "Επεξεργασία πολυμέσου",
|
||||
"confirmations.missing_media_description.message": "Τουλάχιστον ένα συνημμένο πολυμέσων δεν έχει περιγραφή. Σκεφτείτε να προσθέσετε περιγραφή σε όλα τα συνημμένα πολυμέσων για τα άτομα με προβλήματα όρασης πριν από την αποστολή του τουτ σας.",
|
||||
"direct.group_by_conversations": "Ομαδοποίηση ανά συζήτηση",
|
||||
"endorsed_accounts_editor.endorsed_accounts": "Αναδεικνυόμενοι λογαριασμοί",
|
||||
"favourite_modal.favourite": "Αγάπησε την ανάρτηση;",
|
||||
"federation.federated.long": "Επιτρέψτε σε αυτήν την ανάρτηση να φτάσει σε άλλους διακομιστές",
|
||||
"federation.local_only.long": "Αποτρέψτε αυτήν την ανάρτηση να φτάσει σε άλλους διακομιστές",
|
||||
"federation.local_only.short": "Τοπικά μόνο",
|
||||
"firehose.column_settings.allow_local_only": "Εμφάνιση τοπικών αναρτήσεων σε \"Όλα\"",
|
||||
"home.column_settings.advanced": "Για προχωρημένους",
|
||||
"home.column_settings.filter_regex": "Φιλτράρισμα βάσει των κανονικών εκφράσεων",
|
||||
"home.column_settings.show_direct": "Εμφάνιση ιδιωτικών επισημάνσεων",
|
||||
"home.settings": "Ρυθμίσεις στήλης",
|
||||
"keyboard_shortcuts.bookmark": "για να σελιδοποιήσει",
|
||||
"keyboard_shortcuts.secondary_toot": "για αποστολή τουτ χρησιμοποιώντας δευτερεύουσα ρύθμιση απορρήτου",
|
||||
"keyboard_shortcuts.toggle_collapse": "για να συμπτύξει/επεκτείνει τα τουτς",
|
||||
"moved_to_warning": "Αυτός ο λογαριασμός έχει σημανθεί ως μετακινημένος στο {moved_to_link} και έτσι δεν μπορεί να δεχτεί νέους ακολούθους.",
|
||||
"navigation_bar.app_settings": "Ρυθμίσεις εφαρμογής",
|
||||
"navigation_bar.featured_users": "Αναδεικνυόμενοι χρήστες",
|
||||
"navigation_bar.keyboard_shortcuts": "Συντομεύσεις πληκτρολογίου",
|
||||
"navigation_bar.misc": "Διάφορα",
|
||||
"notification.markForDeletion": "Σήμανση για διαγραφή",
|
||||
"notification_purge.btn_all": "Επιλογή\nόλων",
|
||||
"notification_purge.btn_apply": "Εκκαθάριση\nεπιλεγμένων",
|
||||
"notification_purge.btn_invert": "Αντιστροφή\nεπιλογής",
|
||||
"notification_purge.btn_none": "Επιλογή\nκανενός",
|
||||
"notification_purge.start": "Εισαγωγή στη λειτουργία καθαρισμού ειδοποιήσεων",
|
||||
"notifications.column_settings.filter_bar.show_bar": "Εμφάνιση μπάρας φίλτρου",
|
||||
"notifications.marked_clear": "Εκκαθάριση επιλεγμένων ειδοποιήσεων",
|
||||
"notifications.marked_clear_confirmation": "Είστε βέβαιοι ότι θέλετε να καθαρίσετε μόνιμα όλες τις επιλεγμένες ειδοποιήσεις;",
|
||||
"settings.always_show_spoilers_field": "Πάντα ενεργοποίηση του πεδίου Προειδοποίηση Περιεχομένου",
|
||||
"settings.auto_collapse": "Αυτόματη σύμπτυξη",
|
||||
"settings.auto_collapse_all": "Τα πάντα",
|
||||
"settings.auto_collapse_height": "Ύψος (σε pixels) για να θεωρηθεί ένα τουτ μακροσκελές",
|
||||
"settings.auto_collapse_lengthy": "Μακροσκελή τουτς",
|
||||
"settings.auto_collapse_media": "Τουτς με πολυμέσα",
|
||||
"settings.auto_collapse_notifications": "Ειδοποιήσεις",
|
||||
"settings.auto_collapse_reblogs": "Ενισχύσεις",
|
||||
"settings.auto_collapse_replies": "Απαντήσεις",
|
||||
"settings.close": "Κλείσιμο",
|
||||
"settings.collapsed_statuses": "Συμπτυγμένα τουτς",
|
||||
"settings.compose_box_opts": "Πλαίσιο σύνθεσης",
|
||||
"settings.confirm_missing_media_description": "Εμφάνιση διαλόγου επιβεβαίωσης πριν την αποστολή τουτς χωρίς περιγραφές πολυμέσων",
|
||||
"settings.content_warnings": "Προειδοποιήσεις περιεχομένου",
|
||||
"settings.content_warnings.regexp": "Κανονική έκφραση (regex)",
|
||||
"settings.content_warnings_filter": "Προειδοποιήσεις περιεχομένου να μην ξεδιπλώνονται αυτόματα:",
|
||||
"settings.content_warnings_media_outside": "Εμφάνιση συνημμένων πολυμέσων έξω από τις προειδοποιήσεις περιεχομένου",
|
||||
"settings.content_warnings_media_outside_hint": "Αναπαράγει την συμπεριφορά του Mastodon έχοντας την εναλλαγή προειδοποίησης περιεχομένου να μην επηρεάζει τα συνημμένα πολυμέσων",
|
||||
"settings.content_warnings_shared_state": "Εμφάνιση/απόκρυψη περιεχομένου όλων των αντιγράφων ταυτόχρονα",
|
||||
"settings.content_warnings_unfold_opts": "Επιλογές αυτόματου ξεδιπλώματος",
|
||||
"settings.deprecated_setting": "Αυτή η ρύθμιση τώρα ελέγχεται από τις {settings_page_link} του Mastodon",
|
||||
"settings.enable_collapsed": "Ενεργοποίηση συμπτυγμένων τουτς",
|
||||
"settings.enable_collapsed_hint": "Τα συμπτηγμένα τουτ έχουν τμήματα του περιεχομένου τους κρυμμένα για να καταλαμβάνουν λιγότερο χώρο στην οθόνη. Αυτό είναι διαφορετικό από τη λειτουργία Προειδοποίησης Περιεχομένου",
|
||||
"settings.enable_content_warnings_auto_unfold": "Αυτόματη ξεδίπλωμα προειδοποιήσεων περιεχομένου",
|
||||
"settings.general": "Γενικά",
|
||||
"settings.image_backgrounds": "Εικόνες φόντου",
|
||||
"settings.image_backgrounds_media": "Προεπισκόπηση συμπτυγμένων πολυμέσων τουτ",
|
||||
"settings.image_backgrounds_media_hint": "Αν η δημοσίευση έχει οποιοδήποτε συνημμένο πολυμέσων, χρησιμοποιήστε το πρώτο ως φόντο",
|
||||
"settings.image_backgrounds_users": "Δώστε στα συμπτυγμένα τουτ μια εικόνα φόντου",
|
||||
"settings.layout_opts": "Επιλογές διάταξης",
|
||||
"settings.media": "Πολυμέσα",
|
||||
"settings.notifications.tab_badge": "Σήμα μη αναγνωσμένων ειδοποιήσεων",
|
||||
"settings.notifications.tab_badge.hint": "Εμφανίζει ένα σήμα για μη αναγνωσμένες ειδοποιήσεις στα εικονίδια της στήλης όταν η στήλη ειδοποιήσεων δεν είναι ανοιχτή",
|
||||
"settings.notifications_opts": "Ρυθμίσεις ειδοποιήσεων",
|
||||
"settings.pop_in_left": "Αριστερά",
|
||||
"settings.pop_in_right": "Δεξιά",
|
||||
"settings.preferences": "Προτιμήσεις χρήστη",
|
||||
"settings.preselect_on_reply": "Προεπιλογή ονομάτων χρηστών στην απάντηση",
|
||||
"settings.preselect_on_reply_hint": "Όταν απαντάτε σε μια συνομιλία με πολλαπλούς συμμετέχοντες, προεπιλέξτε τα ονόματα χρηστών μετά τον πρώτο",
|
||||
"settings.rewrite_mentions": "Ξαναγράψε επισημάνσεις στις προβαλλόμενες καταστάσεις",
|
||||
"settings.rewrite_mentions_acct": "Ξαναγράψε με όνομα χρήστη και τομέα (όταν ο λογαριασμός είναι απομακρυσμένος)",
|
||||
"settings.rewrite_mentions_no": "Μην ξαναγράψεις επισημάνσεις",
|
||||
"settings.rewrite_mentions_username": "Ξαναγράψε με όνομα χρήστη",
|
||||
"settings.shared_settings_link": "προτιμήσεις χρήστη",
|
||||
"settings.show_action_bar": "Εμφάνιση κουμπιών ενεργειών σε συμπτυγμένα τουτ",
|
||||
"settings.side_arm": "Δευτερεύον κουμπί τουτ:",
|
||||
"settings.side_arm.none": "Κανένα",
|
||||
"settings.side_arm_reply_mode": "Όταν απαντάτε σε ένα τουτ, το κουμπί δευτερεύοντος τουτ πρέπει να:",
|
||||
"settings.side_arm_reply_mode.copy": "Αντιγράψει τη ρύθμιση απορρήτου του τουτ που απαντάται",
|
||||
"settings.side_arm_reply_mode.keep": "Διατηρήσει το καθορισμένο απόρρητο",
|
||||
"settings.side_arm_reply_mode.restrict": "Περιορίσει τη ρύθμιση απορρήτου σε εκείνη του τουτ που απαντάται",
|
||||
"settings.status_icons": "Εικονίδια τουτ",
|
||||
"settings.status_icons_language": "Ένδειξη γλώσσας",
|
||||
"settings.status_icons_local_only": "Ένδειξη τοπικό μόνο",
|
||||
"settings.status_icons_media": "Ενδείξεις μέσων και δημοσκοπήσεων",
|
||||
"settings.status_icons_reply": "Ένδειξη απαντήσεων",
|
||||
"settings.status_icons_visibility": "Ένδειξη απορρήτου τουτ",
|
||||
"settings.tag_misleading_links": "Σήμανση παραπλανητικών συνδέσμων",
|
||||
"settings.tag_misleading_links.hint": "Προσθήκη οπτικής ένδειξης με τον εξυπηρετητή στόχο του συνδέσμου σε κάθε σύνδεσμο που δεν αναφέρεται ρητά",
|
||||
"status.collapse": "Σύμπτυξη",
|
||||
"status.filtered": "Φιλτραρισμένο",
|
||||
"status.has_audio": "Διαθέτει συνημμένα αρχεία ήχου",
|
||||
"status.has_pictures": "Διαθέτει συνημμένες εικόνες",
|
||||
"status.has_preview_card": "Διαθέτει συνημμένη κάρτα προεπισκόπησης",
|
||||
"status.has_video": "Διαθέτει συνημμένα βίντεο",
|
||||
"status.hide": "Απόκρυψη ανάρτησης",
|
||||
"status.in_reply_to": "Αυτό το τουτ είναι απάντηση",
|
||||
"status.is_poll": "Αυτό το τουτ είναι δημοσκόπηση",
|
||||
"status.show_filter_reason": "Εμφάνιση ούτως ή άλλως",
|
||||
"status.uncollapse": "Επέκταση"
|
||||
}
|
||||
|
||||
@@ -90,6 +90,8 @@
|
||||
"settings.enable_collapsed": "Enable collapsed toots",
|
||||
"settings.enable_collapsed_hint": "Collapsed posts have parts of their contents hidden to take up less screen space. This is distinct from the Content Warning feature",
|
||||
"settings.enable_content_warnings_auto_unfold": "Automatically unfold content-warnings",
|
||||
"settings.fullwidth_view": "Stretch columns to full width (Desktop mode only)",
|
||||
"settings.fullwidth_view_hint": "Stretches columns to fill all the available space.",
|
||||
"settings.general": "General",
|
||||
"settings.hicolor_privacy_icons": "High color privacy icons",
|
||||
"settings.hicolor_privacy_icons.hint": "Display privacy icons in bright and easily distinguishable colors",
|
||||
@@ -154,7 +156,5 @@
|
||||
"status.is_poll": "This toot is a poll",
|
||||
"status.local_only": "Only visible from your instance",
|
||||
"status.show_filter_reason": "Show anyway",
|
||||
"status.show_less": "Show less",
|
||||
"status.show_more": "Show more",
|
||||
"status.uncollapse": "Uncollapse"
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"about.fork_disclaimer": "Glitch-soc estas libera malfermitkoda programo forkigita el Mastodon.",
|
||||
"account.disclaimer_full": "Subaj informoj povas nekomplete prezenti la profilon de la uzanto.",
|
||||
"account.follows": "Sekvatoj",
|
||||
"account.follows_you": "Sekvas vin",
|
||||
"account.suspended_disclaimer_full": "Ĉi tiu uzanto estis suspendita de moderiganto.",
|
||||
"account.view_full_profile": "Vidi plenan profilon",
|
||||
"boost_modal.missing_description": "Ĉi tiu afiŝo enhavas plurmedion, ke ne havas priskribon",
|
||||
@@ -13,37 +14,118 @@
|
||||
"column_subheading.lists": "Listoj",
|
||||
"column_subheading.navigation": "Navigado",
|
||||
"community.column_settings.allow_local_only": "Montri nur-lokajn afiŝojn",
|
||||
"compose.attach.doodle": "Skribu ion",
|
||||
"compose.change_federation": "Ŝanĝi agordojn de federacio",
|
||||
"compose.content-type.change": "Ŝanĝi altnivelajn agordojn de formatado",
|
||||
"compose.content-type.html": "HTML",
|
||||
"compose.content-type.html_meta": "Formati viajn afiŝojn per HTML",
|
||||
"compose.content-type.markdown": "Markdown",
|
||||
"compose.content-type.markdown_meta": "Formati viajn afiŝojn per Markdown",
|
||||
"compose.content-type.plain": "Plata teksto",
|
||||
"compose.content-type.plain_meta": "Skribi sen altnivela formatado",
|
||||
"compose.disable_threaded_mode": "Malŝalti treditan reĝimon",
|
||||
"compose.enable_threaded_mode": "Ŝalti treditan reĝimon",
|
||||
"compose_form.sensitive.hide": "{count, plural, one {Stampi enhavon kiel sentema} other {Stampi enhavon kiel sentema}}",
|
||||
"compose_form.sensitive.marked": "{count, plural, one {Enhavo delikatiĝis} other {Enhavo delikatiĝis}}",
|
||||
"compose_form.sensitive.unmarked": "{count, plural, one {Enhavo ne delikatiĝis} other {Enhavo ne delikatiĝis}}",
|
||||
"confirmation_modal.do_not_ask_again": "Ne peti por konfirmo plue",
|
||||
"confirmations.deprecated_settings.confirm": "Uzi la agordojn de Mastodon",
|
||||
"confirmations.deprecated_settings.message": "{preferences} de Mastodon anstataŭigis iom da ilo-nivela {app_settings} de glitch-soc, kaj superos ĝin:",
|
||||
"confirmations.missing_media_description.confirm": "Sendi ĉiuokaze",
|
||||
"confirmations.missing_media_description.edit": "Redakti aŭdovidaĵon",
|
||||
"confirmations.missing_media_description.message": "Unu aŭ pli da plurmedioj mankas priskribo. Bonvolu priskribi ĉiujn plurmediojn por la vida-malkapabluloj antaŭ ol sendi vian afiŝon.",
|
||||
"direct.group_by_conversations": "Grupu de konversado",
|
||||
"endorsed_accounts_editor.endorsed_accounts": "Prezentitaj kontoj",
|
||||
"favourite_modal.favourite": "Ĉu vi volas stelumi ĉi tiun afiŝon?",
|
||||
"federation.federated.long": "Permesu ĉi tiun afiŝon atingi aliajn servilojn",
|
||||
"federation.federated.short": "Federatita",
|
||||
"federation.local_only.long": "Malpermesu ĉi tiun afiŝon atingi aliajn servilojn",
|
||||
"federation.local_only.short": "Nurloka",
|
||||
"firehose.column_settings.allow_local_only": "Montri nurlokaj afiŝoj en \"Ĉio\"",
|
||||
"home.column_settings.advanced": "Altnivela",
|
||||
"home.column_settings.filter_regex": "Filtri per regulaj esprimoj",
|
||||
"home.column_settings.show_direct": "Montri malpublikajn menciojn",
|
||||
"home.settings": "Agordoj de rubriko",
|
||||
"keyboard_shortcuts.bookmark": "legosignigi",
|
||||
"keyboard_shortcuts.secondary_toot": "sendi afiŝon per dua agordo de privateco",
|
||||
"keyboard_shortcuts.toggle_collapse": "malmontri/montri afiŝojn",
|
||||
"moved_to_warning": "Ĉi tiun konton sigelas, kiel movinta al {moved_to_link}, kaj pro ne permesos novajn sekvantojn.",
|
||||
"navigation_bar.app_settings": "Agordoj de aplikaĵo",
|
||||
"navigation_bar.featured_users": "Prezentitaj uzantoj",
|
||||
"navigation_bar.keyboard_shortcuts": "Fulmoklavoj",
|
||||
"navigation_bar.misc": "Aliaj",
|
||||
"notification.markForDeletion": "Sigeli por forigi",
|
||||
"notification_purge.btn_all": "Selekti ĉiujn",
|
||||
"notification_purge.btn_apply": "Forigi selektajn",
|
||||
"notification_purge.btn_invert": "Inverti selekton",
|
||||
"notification_purge.btn_none": "Elekti neniun",
|
||||
"notification_purge.start": "Eniri reĝimon de la purigo de sciigojn",
|
||||
"notifications.column_settings.filter_bar.show_bar": "Montri mezuron de filtrilo",
|
||||
"notifications.marked_clear": "Forigi selektajn sciigojn",
|
||||
"notifications.marked_clear_confirmation": "Ĉu vi certas, ke vi volas forigi tutajn selektitajn sciigojn?",
|
||||
"settings.always_show_spoilers_field": "Ĉiam ŝaltiĝu la arealo de Enhava Averto",
|
||||
"settings.auto_collapse": "Aŭtomata kolapsado",
|
||||
"settings.auto_collapse_all": "Ĉiuj",
|
||||
"settings.auto_collapse_height": "Alteco (en rastrumeroj) por afiŝo konsideriĝi longa",
|
||||
"settings.auto_collapse_lengthy": "Longaj afiŝoj",
|
||||
"settings.auto_collapse_media": "Afiŝoj kun aŭdovidaĵoj",
|
||||
"settings.auto_collapse_notifications": "Sciigoj",
|
||||
"settings.auto_collapse_reblogs": "Diskonigoj",
|
||||
"settings.auto_collapse_replies": "Respondoj",
|
||||
"settings.close": "Fermi",
|
||||
"settings.collapsed_statuses": "Kolapsitaj afiŝoj",
|
||||
"settings.compose_box_opts": "Skatolo por verki",
|
||||
"settings.confirm_before_clearing_draft": "Montri dialogujon antaŭ superskribas la verkantan mesaĝon",
|
||||
"settings.confirm_boost_missing_media_description": "Montri dialogujon antaŭ stimulas afiŝojn sen prikskribaĵojn por enhavo",
|
||||
"settings.confirm_missing_media_description": "Montri dialogujon antaŭ sendas afiŝojn sen prikskribaĵojn por enhavo",
|
||||
"settings.content_warnings": "Enhavaj avertoj",
|
||||
"settings.content_warnings.regexp": "Regula esprimo",
|
||||
"settings.content_warnings_filter": "Enhavaj avertoj, kiujn ne aŭtomate malkaŝu:",
|
||||
"settings.content_warnings_media_outside": "Montri plurmediojn ekstere de enhavaj avertoj",
|
||||
"settings.content_warnings_media_outside_hint": "Fari same, kiel la originala programaro Mastodon, por ke la enhavaj avertoj ne influas plurmediojn",
|
||||
"settings.content_warnings_shared_state": "Montri/Malmontri enhavon de kopiaĵoj tuje",
|
||||
"settings.content_warnings_shared_state_hint": "Redonu normalan kondukton de Mastodon per havante la butonon por la Averto por la Enhavo rezultas tutajn kopiaĵojn tuje. Tion preventos aŭtomatan kolapsadon de kopiiaĵo de afiŝo ajn, kiu havus malkolapsan EA-on",
|
||||
"settings.content_warnings_unfold_opts": "Aŭtomat-malkolapsintaj agordoj",
|
||||
"settings.deprecated_setting": "Ĉi tiun agordon nun kontrolas de la {settings_page_link} de Mastodon",
|
||||
"settings.enable_collapsed": "Ŝaltigi kolaptsitajn afiŝojn",
|
||||
"settings.enable_collapsed_hint": "Kolapsitaj afiŝoj havas partojn de siaj enhavoj malkovritaj por uzi malpli da spacon de la ekrano. Ĉi tion estas malsama ol la Enhava Averto",
|
||||
"settings.enable_content_warnings_auto_unfold": "Aŭtomate malkovri avertojn por enhavo",
|
||||
"settings.general": "Ĝenerala",
|
||||
"settings.hicolor_privacy_icons": "Helaj piktogramoj de privateco",
|
||||
"settings.hicolor_privacy_icons.hint": "Montri piktogramojn de privateco en helaj kaj distingigeblaj koloroj",
|
||||
"settings.image_backgrounds": "Fonoj de bildoj",
|
||||
"settings.image_backgrounds_media": "Antaŭrigardi la kolapsitajn plurmediojn de afiŝoj",
|
||||
"settings.image_backgrounds_media_hint": "Se la afiŝo havas plurmediojn, uzi la unuan kiel fono",
|
||||
"settings.image_backgrounds_users": "Donu al kolapsitaj afiŝoj bildfonon",
|
||||
"settings.inline_preview_cards": "Enliniaj antaŭrigardoj por eksteraj ligiloj",
|
||||
"settings.layout_opts": "Opcioj por tekstaranĝo",
|
||||
"settings.media": "Plurenhavo",
|
||||
"settings.media_fullwidth": "Tutlarĝaj antaŭrigardoj por plurenhavoj",
|
||||
"settings.media_letterbox": "Skatoligi plurenhavojn",
|
||||
"settings.media_letterbox_hint": "Skali malsupren kaj kesti plurmediojn por plenigi la bildujojn anstataŭ streĉi kaj tondi ilin",
|
||||
"settings.media_reveal_behind_cw": "Montri sensativajn plurmediajn per AE defaŭlte",
|
||||
"settings.notifications.favicon_badge": "Favikono por nelegitaj sciigoj",
|
||||
"settings.notifications.favicon_badge.hint": "Doni insignon por nelegitaj sciigoj al la favikono",
|
||||
"settings.notifications.tab_badge": "Insigno por nelegitaj sciigoj",
|
||||
"settings.notifications.tab_badge.hint": "Montru insignon por nelegitaj sciigoj en la kolumno de piktogramoj, kiam la kolumno de sciigoj ne malfermas",
|
||||
"settings.notifications_opts": "Agordoj por sciigoj",
|
||||
"settings.pop_in_left": "Maldekstre",
|
||||
"settings.pop_in_player": "Permesu pop-ena filmspektilon",
|
||||
"settings.pop_in_position": "Posteno de la pop-ena filmspektilon:",
|
||||
"settings.pop_in_right": "Dekstre",
|
||||
"settings.preferences": "Preferences",
|
||||
"settings.prepend_cw_re": "Donu \"re:\" al avertoj de enhavo, kiam respondante",
|
||||
"settings.preselect_on_reply": "Antaŭselekti uzuantnomojn en la respondo",
|
||||
"settings.preselect_on_reply_hint": "Kiam respondas al konversacio, kiu havas multajn uzantojn, antaŭselekti uzantnomojn post la unua",
|
||||
"settings.rewrite_mentions": "Reskribu menciiojn en montritaj statusoj",
|
||||
"settings.rewrite_mentions_acct": "Reskribu kun uzantnomon kaj domajno (kiam la konto malproksimas)",
|
||||
"settings.rewrite_mentions_no": "Ne reskribu menciiojn",
|
||||
"settings.rewrite_mentions_username": "Reskribu kun uzantnomo",
|
||||
"settings.shared_settings_link": "preferoj de uzanto",
|
||||
"settings.show_action_bar": "Montri agajn butonojn en kolapsitaj afiŝoj",
|
||||
"settings.show_content_type_choice": "Montru elekton de enhava-tipo dum skribante afiŝojn",
|
||||
"settings.show_published_toast": "Montri sciigetojn dum eldonante/savante afiŝon",
|
||||
"settings.show_reply_counter": "Montri takson de la nombro da respondoj",
|
||||
"settings.side_arm": "Duaranga butono por afiŝi:",
|
||||
"settings.side_arm.none": "Neniu",
|
||||
"settings.status_icons": "Ikonoj sur la afiŝoj",
|
||||
|
||||
@@ -90,6 +90,8 @@
|
||||
"settings.enable_collapsed": "Habilitar toots colapsados",
|
||||
"settings.enable_collapsed_hint": "Las publicaciones colapsadas tienen partes de su contenido ocultas para ocupar menos espacio en pantalla. Esto es distinto de la función Advertencia de Contenido",
|
||||
"settings.enable_content_warnings_auto_unfold": "Descolapsar automáticamente advertencias de contenido",
|
||||
"settings.fullwidth_view": "Estirar columnas al ancho total (solo en Modo escritorio)",
|
||||
"settings.fullwidth_view_hint": "Estira las columnas para rellenar todo el espacio disponible.",
|
||||
"settings.general": "General",
|
||||
"settings.hicolor_privacy_icons": "Íconos de privacidad más visibles",
|
||||
"settings.hicolor_privacy_icons.hint": "Mostrar iconos de privacidad en colores brillantes y fácilmente distinguibles",
|
||||
@@ -154,7 +156,5 @@
|
||||
"status.is_poll": "Esta publicación es una encuesta",
|
||||
"status.local_only": "Sólo visible para tu instancia",
|
||||
"status.show_filter_reason": "Mostrar de todos modos",
|
||||
"status.show_less": "Mostrar menos",
|
||||
"status.show_more": "Mostrar más",
|
||||
"status.uncollapse": "Descolapsar"
|
||||
}
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
"compose.content-type.plain_meta": "Écrire sans formatage avancé",
|
||||
"compose.disable_threaded_mode": "Désactiver le mode thread",
|
||||
"compose.enable_threaded_mode": "Activer le mode thread",
|
||||
"compose_form.sensitive.hide": "{count, plural, one {Marquer le média comme sensible} other {Marquer les médias comme sensibles}}",
|
||||
"compose_form.sensitive.marked": "{count, plural, one {Le média est marqué comme sensible} other {Les médias sont marqués comme sensibles}}",
|
||||
"compose_form.sensitive.unmarked": "{count, plural, one {Le média n’est pas marqué comme sensible} other {Les médias ne sont pas marqué comme sensible}}",
|
||||
"confirmation_modal.do_not_ask_again": "Ne plus demander confirmation",
|
||||
"confirmations.deprecated_settings.confirm": "Utiliser les préférences de Mastodon",
|
||||
"confirmations.deprecated_settings.message": "Certaines {app_settings} de glitch-soc que vous utilisez ont été remplacées par les {preferences} de Mastodon et seront remplacées :",
|
||||
@@ -33,6 +36,7 @@
|
||||
"confirmations.missing_media_description.message": "Au moins un média joint manque d'une description. Pensez à décrire tous les médias attachés pour les malvoyant·e·s avant de publier votre post.",
|
||||
"direct.group_by_conversations": "Grouper par conversation",
|
||||
"endorsed_accounts_editor.endorsed_accounts": "Comptes mis en avant",
|
||||
"favourite_modal.favourite": "Ajouter le message aux favoris ?",
|
||||
"federation.federated.long": "Permettre à ce post d’atteindre d'autres serveurs",
|
||||
"federation.federated.short": "Fédéré",
|
||||
"federation.local_only.long": "Empêcher ce post d’atteindre d'autres serveurs",
|
||||
@@ -56,6 +60,7 @@
|
||||
"notification_purge.btn_invert": "Inverser\nla sélection",
|
||||
"notification_purge.btn_none": "Annuler\nla sélection",
|
||||
"notification_purge.start": "Activer le mode de nettoyage des notifications",
|
||||
"notifications.column_settings.filter_bar.show_bar": "Afficher la barre de filtre",
|
||||
"notifications.marked_clear": "Effacer les notifications sélectionnées",
|
||||
"notifications.marked_clear_confirmation": "Voulez-vous vraiment effacer de manière permanente toutes les notifications sélectionnées ?",
|
||||
"settings.always_show_spoilers_field": "Toujours activer le champ de rédaction de l'avertissement de contenu",
|
||||
@@ -85,6 +90,8 @@
|
||||
"settings.enable_collapsed": "Activer le repliement des posts",
|
||||
"settings.enable_collapsed_hint": "Les posts repliés ont une partie de leur contenu caché pour libérer de l'espace sur l'écran. C'est une option différente de l'avertissement de contenu",
|
||||
"settings.enable_content_warnings_auto_unfold": "Déplier automatiquement les avertissements de contenu",
|
||||
"settings.fullwidth_view": "Étirer les colonnes sur toute la largeur (mode bureau uniquement)",
|
||||
"settings.fullwidth_view_hint": "Étire les colonnes pour remplir tout l'espace disponible.",
|
||||
"settings.general": "Général",
|
||||
"settings.hicolor_privacy_icons": "Indicateurs de confidentialité en couleurs",
|
||||
"settings.hicolor_privacy_icons.hint": "Affiche les indicateurs de confidentialité dans des couleurs facilement distinguables",
|
||||
@@ -139,12 +146,15 @@
|
||||
"settings.wide_view": "Vue élargie (mode ordinateur uniquement)",
|
||||
"settings.wide_view_hint": "Étire les colonnes pour mieux remplir l'espace disponible.",
|
||||
"status.collapse": "Replier",
|
||||
"status.filtered": "Filtré",
|
||||
"status.has_audio": "Contient des fichiers audio attachés",
|
||||
"status.has_pictures": "Contient des images attachées",
|
||||
"status.has_preview_card": "Contient une carte de prévisualisation attachée",
|
||||
"status.has_video": "Contient des vidéos attachées",
|
||||
"status.hide": "Masquer la publication",
|
||||
"status.in_reply_to": "Ce post est une réponse",
|
||||
"status.is_poll": "Ce post est un sondage",
|
||||
"status.local_only": "Visible uniquement depuis votre instance",
|
||||
"status.show_filter_reason": "Afficher quand même",
|
||||
"status.uncollapse": "Déplier"
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"account.disclaimer_full": "Les informations ci-dessous peuvent être incomplètes.",
|
||||
"account.follows": "Abonnements",
|
||||
"account.follows_you": "Vous suit",
|
||||
"account.suspended_disclaimer_full": "Cet utilisateur a été suspendu par un modérateur.",
|
||||
"account.suspended_disclaimer_full": "Ce compte a été suspendu par un modérateur.",
|
||||
"account.view_full_profile": "Voir le profil complet",
|
||||
"boost_modal.missing_description": "Ce post contient des médias sans description",
|
||||
"column.favourited_by": "Ajouté en favori par",
|
||||
@@ -21,10 +21,13 @@
|
||||
"compose.content-type.html_meta": "Formatez vos messages en HTML",
|
||||
"compose.content-type.markdown": "Markdown",
|
||||
"compose.content-type.markdown_meta": "Formatez vos messages en Markdown",
|
||||
"compose.content-type.plain": "Text brut",
|
||||
"compose.content-type.plain": "Texte brut",
|
||||
"compose.content-type.plain_meta": "Écrire sans formatage avancé",
|
||||
"compose.disable_threaded_mode": "Désactiver le mode thread",
|
||||
"compose.enable_threaded_mode": "Activer le mode thread",
|
||||
"compose_form.sensitive.hide": "{count, plural, one {Marquer le média comme sensible} other {Marquer les médias comme sensibles}}",
|
||||
"compose_form.sensitive.marked": "{count, plural, one {Le média est marqué comme sensible} other {Les médias sont marqués comme sensibles}}",
|
||||
"compose_form.sensitive.unmarked": "{count, plural, one {Le média n’est pas marqué comme sensible} other {Les médias ne sont pas marqué comme sensible}}",
|
||||
"confirmation_modal.do_not_ask_again": "Ne plus demander confirmation",
|
||||
"confirmations.deprecated_settings.confirm": "Utiliser les préférences de Mastodon",
|
||||
"confirmations.deprecated_settings.message": "Certaines {app_settings} de glitch-soc que vous utilisez ont été remplacées par les {preferences} de Mastodon et seront remplacées :",
|
||||
@@ -33,6 +36,7 @@
|
||||
"confirmations.missing_media_description.message": "Au moins un média joint manque d'une description. Pensez à décrire tous les médias attachés pour les malvoyant·e·s avant de publier votre post.",
|
||||
"direct.group_by_conversations": "Grouper par conversation",
|
||||
"endorsed_accounts_editor.endorsed_accounts": "Comptes mis en avant",
|
||||
"favourite_modal.favourite": "Ajouter le message aux favoris ?",
|
||||
"federation.federated.long": "Permettre à ce post d’atteindre d'autres serveurs",
|
||||
"federation.federated.short": "Fédéré",
|
||||
"federation.local_only.long": "Empêcher ce post d’atteindre d'autres serveurs",
|
||||
@@ -56,6 +60,7 @@
|
||||
"notification_purge.btn_invert": "Inverser\nla sélection",
|
||||
"notification_purge.btn_none": "Annuler\nla sélection",
|
||||
"notification_purge.start": "Activer le mode de nettoyage des notifications",
|
||||
"notifications.column_settings.filter_bar.show_bar": "Afficher la barre de filtre",
|
||||
"notifications.marked_clear": "Effacer les notifications sélectionnées",
|
||||
"notifications.marked_clear_confirmation": "Voulez-vous vraiment effacer de manière permanente toutes les notifications sélectionnées ?",
|
||||
"settings.always_show_spoilers_field": "Toujours activer le champ de rédaction de l'avertissement de contenu",
|
||||
@@ -85,6 +90,8 @@
|
||||
"settings.enable_collapsed": "Activer le repliement des posts",
|
||||
"settings.enable_collapsed_hint": "Les posts repliés ont une partie de leur contenu caché pour libérer de l'espace sur l'écran. C'est une option différente de l'avertissement de contenu",
|
||||
"settings.enable_content_warnings_auto_unfold": "Déplier automatiquement les avertissements de contenu",
|
||||
"settings.fullwidth_view": "Étirer les colonnes sur toute la largeur (mode bureau uniquement)",
|
||||
"settings.fullwidth_view_hint": "Étire les colonnes pour remplir tout l'espace disponible.",
|
||||
"settings.general": "Général",
|
||||
"settings.hicolor_privacy_icons": "Indicateurs de confidentialité en couleurs",
|
||||
"settings.hicolor_privacy_icons.hint": "Affiche les indicateurs de confidentialité dans des couleurs facilement distinguables",
|
||||
@@ -108,7 +115,7 @@
|
||||
"settings.pop_in_player": "Activer le lecteur pop-in",
|
||||
"settings.pop_in_position": "Position du lecteur pop-in :",
|
||||
"settings.pop_in_right": "Droite",
|
||||
"settings.preferences": "Preferences",
|
||||
"settings.preferences": "Préferences",
|
||||
"settings.prepend_cw_re": "Préfixer les avertissements avec \"re: \" lors d'une réponse",
|
||||
"settings.preselect_on_reply": "Présélectionner les noms d’utilisateur·rices lors de la réponse",
|
||||
"settings.preselect_on_reply_hint": "Présélectionner les noms d'utilisateurs après le premier lors d'une réponse à une conversation à plusieurs participants",
|
||||
@@ -139,12 +146,15 @@
|
||||
"settings.wide_view": "Vue élargie (mode ordinateur uniquement)",
|
||||
"settings.wide_view_hint": "Étire les colonnes pour mieux remplir l'espace disponible.",
|
||||
"status.collapse": "Replier",
|
||||
"status.filtered": "Filtré",
|
||||
"status.has_audio": "Contient des fichiers audio attachés",
|
||||
"status.has_pictures": "Contient des images attachées",
|
||||
"status.has_preview_card": "Contient une carte de prévisualisation attachée",
|
||||
"status.has_video": "Contient des vidéos attachées",
|
||||
"status.hide": "Masquer la publication",
|
||||
"status.in_reply_to": "Ce post est une réponse",
|
||||
"status.is_poll": "Ce post est un sondage",
|
||||
"status.local_only": "Visible uniquement depuis votre instance",
|
||||
"status.show_filter_reason": "Afficher quand même",
|
||||
"status.uncollapse": "Déplier"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,107 @@
|
||||
{
|
||||
"about.fork_disclaimer": "Glitch-soc é software libre de código aberto derivado de Mastodon.",
|
||||
"account.disclaimer_full": "A información inferior sobre a usuaria podería estar incompleta.",
|
||||
"account.follows": "Segue",
|
||||
"account.follows_you": "Séguete",
|
||||
"account.suspended_disclaimer_full": "Usuaria suspendida pola moderación.",
|
||||
"account.view_full_profile": "Ver perfil completo",
|
||||
"boost_modal.missing_description": "Esta publicación contén multimedia sen descrición",
|
||||
"column.favourited_by": "Favorecida por",
|
||||
"column.heading": "Varios",
|
||||
"column.reblogged_by": "Promovida por",
|
||||
"column.subheading": "Opcións diversas",
|
||||
"column_header.profile": "Perfil",
|
||||
"column_subheading.lists": "Listas",
|
||||
"column_subheading.navigation": "Navegación",
|
||||
"community.column_settings.allow_local_only": "Ver só mensaxes de ámbito local",
|
||||
"compose.attach.doodle": "Debuxa algo",
|
||||
"compose.change_federation": "Cambiar axustes de federación",
|
||||
"compose.content-type.change": "Cambiar opcións avanzadas de formato",
|
||||
"compose.content-type.html": "HTML",
|
||||
"compose.content-type.html_meta": "Usar formato HTML nas publicacións",
|
||||
"compose.content-type.markdown": "Markdown",
|
||||
"compose.content-type.markdown_meta": "Usar formato Markdown nas publicacións",
|
||||
"compose.content-type.plain": "Texto plano",
|
||||
"compose.content-type.plain_meta": "Escribir sen dar formato ao texto",
|
||||
"compose.disable_threaded_mode": "Desactivar modo fiado",
|
||||
"compose.enable_threaded_mode": "Activar modo fiado",
|
||||
"compose_form.sensitive.hide": "{count, plural, one {Marcar multimedia como sensible} other {Marcar multimedia como sensible}}",
|
||||
"compose_form.sensitive.marked": "{count, plural, one {Multimedia marcado como sensible} other {Multimedia marcado como sensible}}",
|
||||
"compose_form.sensitive.unmarked": "{count, plural, one {Multimedia non marcado como sensible} other {Multimedia non marcado como sensible}}",
|
||||
"confirmation_modal.do_not_ask_again": "Non volver a pedir confirmación",
|
||||
"confirmations.deprecated_settings.confirm": "Usar preferencias de Mastodon",
|
||||
"confirmations.deprecated_settings.message": "Algunha das preferencias propias do dispositivo {app_settings} que estás a usar foron substituídas por {preferences} de Mastodon e serán substituídas:",
|
||||
"confirmations.missing_media_description.confirm": "Enviar igualmente",
|
||||
"confirmations.missing_media_description.edit": "Editar multimedia",
|
||||
"confirmations.missing_media_description.message": "Polo menos hai un multimedia ao que lle falta a descrición. Considera describir todos os anexos multimedia para axudar a persoas con deficiencias visuas.",
|
||||
"direct.group_by_conversations": "Agrupar por conversa",
|
||||
"favourite_modal.favourite": "Marcar como favorita?",
|
||||
"federation.federated.long": "Permitir que esta publicación acade outros servidores",
|
||||
"federation.federated.short": "Federada",
|
||||
"federation.local_only.long": "Evitar que esta publicación acade outros servidores",
|
||||
"federation.local_only.short": "Só local",
|
||||
"firehose.column_settings.allow_local_only": "Mostrar só publicacións locais en «Todo»",
|
||||
"home.column_settings.advanced": "Avanzado",
|
||||
"home.column_settings.filter_regex": "Filtrar usando expresións regulares",
|
||||
"home.column_settings.show_direct": "Mostrar mencións privadas",
|
||||
"home.settings": "Axustes das columnas",
|
||||
"keyboard_shortcuts.bookmark": "para marcar",
|
||||
"keyboard_shortcuts.secondary_toot": "para enviar publicación usando axuste secundario de privacidade",
|
||||
"moved_to_warning": "Esta conta moveuse a {moved_to_link}, e non acepta novos seguimentos.",
|
||||
"navigation_bar.app_settings": "Axustes da app",
|
||||
"navigation_bar.keyboard_shortcuts": "Atallos de teclado",
|
||||
"navigation_bar.misc": "Varios",
|
||||
"notifications.column_settings.filter_bar.show_bar": "Amosar barra de filtros",
|
||||
"settings.always_show_spoilers_field": "Activar sempre o campo de Aviso sobre o contido CW",
|
||||
"settings.close": "Pechar",
|
||||
"settings.compose_box_opts": "Caixa de escritura",
|
||||
"settings.confirm_before_clearing_draft": "Mostra cadro de confirmación antes de sobrescribir a mensaxe que se está a compoñer",
|
||||
"settings.confirm_boost_missing_media_description": "Mostra cadro de confirmación antes de promover mensaxes que non describen o multimedia",
|
||||
"settings.confirm_missing_media_description": "Mostra cadro de confirmación antes de enviar mensaxes sen descrición do multimedia",
|
||||
"settings.content_warnings": "Content warnings",
|
||||
"settings.preferences": "Preferences"
|
||||
"settings.content_warnings.regexp": "Expresión regular",
|
||||
"settings.content_warnings_filter": "Non despregar automáticamente os CW que:",
|
||||
"settings.content_warnings_shared_state": "Mostra/oculta contido de todas as copias á vez",
|
||||
"settings.content_warnings_shared_state_hint": "Imita o comportamento do propio Mastodon facendo que o botón de CW afecte a todas a copias dunha publicación á vez. Isto evita pregar automáticamente calquera copia dunha publicación con CW despregrado",
|
||||
"settings.content_warnings_unfold_opts": "Opcións despregamento automático",
|
||||
"settings.deprecated_setting": "O axuste está xestionado directamente desde os {settings_page_link} de Mastodon",
|
||||
"settings.enable_content_warnings_auto_unfold": "Despregar automáticamente os avisos de contido",
|
||||
"settings.general": "Xeral",
|
||||
"settings.hicolor_privacy_icons": "Cores destacadas na icona de privacidade",
|
||||
"settings.hicolor_privacy_icons.hint": "Mostra con cores brillantes e visibles as iconas co nivel de privacidade",
|
||||
"settings.inline_preview_cards": "Vista previa local en tarxeta para ligazóns externas",
|
||||
"settings.layout_opts": "Opcións da disposición",
|
||||
"settings.media": "Multimedia",
|
||||
"settings.media_fullwidth": "Vistra previa co ancho completo",
|
||||
"settings.media_letterbox": "Multimedia nun rectángulo",
|
||||
"settings.media_letterbox_hint": "Reducir a escala a un rectángulo que conteña a imaxe no lugar de estirala e recortala",
|
||||
"settings.media_reveal_behind_cw": "Mostrar contido sensible con CW de xeito predeterminado",
|
||||
"settings.notifications.favicon_badge": "Marca no favicon para notificacións non lidas",
|
||||
"settings.notifications.favicon_badge.hint": "Mostra unha insignia no favicon cando hai notificacións non lidas",
|
||||
"settings.notifications.tab_badge": "Insignia para notificacións non lidas",
|
||||
"settings.notifications.tab_badge.hint": "Mostra unha insignia para as notificacións non lidas na columna de iconas cando a columna non está aberta",
|
||||
"settings.notifications_opts": "Opcións das notificacións",
|
||||
"settings.pop_in_left": "Esquerda",
|
||||
"settings.pop_in_right": "Dereita",
|
||||
"settings.preferences": "Preferences",
|
||||
"settings.prepend_cw_re": "Engadir \"re:\" aos avisos sobre o contido nas respostas",
|
||||
"settings.preselect_on_reply": "Preseleccionar identificadores ao responder",
|
||||
"settings.preselect_on_reply_hint": "Preseleccionar os identificadores ao responder nunha conversa con varias persoas participantes",
|
||||
"settings.rewrite_mentions": "Rescribe as mencións nos estados mostrados",
|
||||
"settings.rewrite_mentions_acct": "Rescribir con identificador e dominio (para contas remotas)",
|
||||
"settings.rewrite_mentions_no": "Non rescribir mencións",
|
||||
"settings.rewrite_mentions_username": "Rescribir con identificador",
|
||||
"settings.shared_settings_link": "preferencias da usuaria",
|
||||
"settings.side_arm": "Botón secundario de publicación:",
|
||||
"settings.side_arm.none": "Ningún",
|
||||
"settings.side_arm_reply_mode": "Ao responder, o botón secundario de publicación debería:",
|
||||
"settings.side_arm_reply_mode.copy": "Copiar a privacidade da publicación á que se responde",
|
||||
"settings.side_arm_reply_mode.keep": "Manter a privacidade establecida",
|
||||
"settings.side_arm_reply_mode.restrict": "Limita o nivel de privacidade a aquel que teña a publicación á que se responde",
|
||||
"settings.status_icons": "Iconas das publicacións",
|
||||
"settings.status_icons_language": "Indicador de idioma",
|
||||
"settings.status_icons_local_only": "Indicador de só-local",
|
||||
"settings.status_icons_media": "Indicadores multimedia e enquisas",
|
||||
"settings.status_icons_reply": "Indicador de resposta",
|
||||
"settings.status_icons_visibility": "Indicador de nivel de privacidade"
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@
|
||||
"settings.content_warnings_media_outside": "Tampilkan lampiran media di luar peringatan konten",
|
||||
"settings.content_warnings_media_outside_hint": "Reproduksi perilaku Mastodon upstream dengan membuat tombol Peringatan Konten tidak memengaruhi lampiran media",
|
||||
"settings.content_warnings_shared_state": "Tampilkan/sembunyikan konten semua salinan sekaligus",
|
||||
"settings.pop_in_right": "Kanan",
|
||||
"settings.preferences": "Preferences",
|
||||
"settings.status_icons_reply": "Indikator balasan",
|
||||
"settings.status_icons_visibility": "Indikator privasi toot",
|
||||
|
||||
@@ -75,9 +75,9 @@
|
||||
"settings.close": "닫기",
|
||||
"settings.collapsed_statuses": "접힌 글",
|
||||
"settings.compose_box_opts": "작성 상자",
|
||||
"settings.confirm_before_clearing_draft": "작성 중인 메시지를 덮어씌우기 전에 확인창을 보여주기",
|
||||
"settings.confirm_boost_missing_media_description": "미디어 설명이 없는 글을 부스트하려 할 때 확인창을 보여주기",
|
||||
"settings.confirm_missing_media_description": "미디어 설명이 없는 글을 작성하려 할 때 확인창을 보여주기",
|
||||
"settings.confirm_before_clearing_draft": "작성 중인 메시지를 덮어씌우기 전에 확인창을 띄웁니다",
|
||||
"settings.confirm_boost_missing_media_description": "미디어 설명이 없는 글을 부스트하려 할 때 확인창을 띄웁니다",
|
||||
"settings.confirm_missing_media_description": "미디어 설명이 없는 글을 작성하려 할 때 확인창을 띄웁니다",
|
||||
"settings.content_warnings": "열람주의",
|
||||
"settings.content_warnings.regexp": "정규표현식",
|
||||
"settings.content_warnings_filter": "자동으로 펼치지 않을 열람주의 문구:",
|
||||
@@ -154,7 +154,5 @@
|
||||
"status.is_poll": "이 글은 설문입니다",
|
||||
"status.local_only": "당신의 서버에서만 보입니다",
|
||||
"status.show_filter_reason": "그냥 표시하기",
|
||||
"status.show_less": "접기",
|
||||
"status.show_more": "더보기",
|
||||
"status.uncollapse": "펼치기"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,160 @@
|
||||
{
|
||||
"settings.content_warnings": "Content warnings",
|
||||
"settings.preferences": "Preferences"
|
||||
"about.fork_disclaimer": "„Glitch-soc“ – tai nemokama atvirojo kodo programinė įranga, atšakota iš „Mastodon“.",
|
||||
"account.disclaimer_full": "Žemiau pateikta informacija gali nevisiškai atitikti naudotojo profilį.",
|
||||
"account.follows": "Sekimai",
|
||||
"account.follows_you": "Seka jus",
|
||||
"account.suspended_disclaimer_full": "Šį naudotoją pristabdė prižiūrėtojas.",
|
||||
"account.view_full_profile": "Peržiūrėti visą profilį",
|
||||
"boost_modal.missing_description": "Šis įrašas turi šiek tiek medijų be aprašų.",
|
||||
"column.favourited_by": "Pamėgo",
|
||||
"column.heading": "Įvairūs",
|
||||
"column.reblogged_by": "Pasidalino",
|
||||
"column.subheading": "Įvairios parinktys",
|
||||
"column_header.profile": "Profilis",
|
||||
"column_subheading.lists": "Sąrašai",
|
||||
"column_subheading.navigation": "Naršymas",
|
||||
"community.column_settings.allow_local_only": "Rodyti tik vietinius įrašus",
|
||||
"compose.attach.doodle": "Nupiešti kažką",
|
||||
"compose.change_federation": "Keisti federacijos nustatymus",
|
||||
"compose.content-type.change": "Keisti papildomas formatavimo parinktis",
|
||||
"compose.content-type.html": "HTML",
|
||||
"compose.content-type.html_meta": "Formatuokite įrašus naudojant HTML",
|
||||
"compose.content-type.markdown": "Ženklinimas",
|
||||
"compose.content-type.markdown_meta": "Formatuokite įrašus naudojant ženklinimą",
|
||||
"compose.content-type.plain": "Grynasis tekstas",
|
||||
"compose.content-type.plain_meta": "Rašykite be papildomo formatavimo",
|
||||
"compose.disable_threaded_mode": "Išjungti gijimo režimą",
|
||||
"compose.enable_threaded_mode": "Įjungti gijimo režimą",
|
||||
"compose_form.sensitive.hide": "{count, plural, one {Žymėti mediją kaip jautrią} few {Žymėti medijas kaip jautrias} many {Žymėti medijos kaip jautrios} other {Žymėti medijų kaip jautrių}}",
|
||||
"compose_form.sensitive.marked": "{count, plural, one {Medija pažymėta kaip jautri} few {Medijos pažymėtos kaip jautrios} many {Medijos pažymėta kaip jautrios} other {Medijų pažymėtų kaip jautrių}}",
|
||||
"compose_form.sensitive.unmarked": "{count, plural, one {Medija nepažymėta kaip jautri} few {Medijos nepažymėtos kaip jautrios} many {Medijos nepažymėta kaip jautrios} other {Medijų nepažymėtų kaip jautrių}}",
|
||||
"confirmation_modal.do_not_ask_again": "Neklausti patvirtinimo vėl",
|
||||
"confirmations.deprecated_settings.confirm": "Naudoti „Mastodon“ nuostatas",
|
||||
"confirmations.deprecated_settings.message": "Kai kurios „glitch-soc“ įrenginiui būdingos {app_settings}, kurias naudojate, pakeistos į „Mastodon“ {preferences} ir bus perrašytos:",
|
||||
"confirmations.missing_media_description.confirm": "Vis tiek siųsti",
|
||||
"confirmations.missing_media_description.edit": "Redaguoti mediją",
|
||||
"confirmations.missing_media_description.message": "Bent vienam medijos priedui trūksta aprašo. Prieš siųsdami savo įrašą apsvarstykite galimybę aprašyti visus medijų priedus silpnaregiams.",
|
||||
"direct.group_by_conversations": "Grupuoti pagal pokalbį",
|
||||
"endorsed_accounts_editor.endorsed_accounts": "Rekomenduojamos paskyros",
|
||||
"favourite_modal.favourite": "Pamėgti įrašą?",
|
||||
"federation.federated.long": "Leiskite šiam įrašui pasiekti kitus serverius",
|
||||
"federation.federated.short": "Federuotas",
|
||||
"federation.local_only.long": "Neleiskite šiam įrašui pasiekti kitus serverius",
|
||||
"federation.local_only.short": "Tik vietinis",
|
||||
"firehose.column_settings.allow_local_only": "Rodyti tik vietinius įrašus skiltyje „Visi“",
|
||||
"home.column_settings.advanced": "Išplėstiniai",
|
||||
"home.column_settings.filter_regex": "Filtruokite pagal paieškos reiškiniais",
|
||||
"home.column_settings.show_direct": "Rodyti privačius paminėjimus",
|
||||
"home.settings": "Stulpelio nustatymai",
|
||||
"keyboard_shortcuts.bookmark": "pridėti prie žymių",
|
||||
"keyboard_shortcuts.secondary_toot": "siųsti įrašą naudojant antrinį privatumo nustatymą",
|
||||
"keyboard_shortcuts.toggle_collapse": "suskleisti / išskleisti įrašus",
|
||||
"moved_to_warning": "Ši paskyra pažymėta kaip perkelta į {moved_to_link}, todėl negali priimti naujų sekimų.",
|
||||
"navigation_bar.app_settings": "Programėlės nustatymai",
|
||||
"navigation_bar.featured_users": "Rekomenduojami naudotojai",
|
||||
"navigation_bar.keyboard_shortcuts": "Spartieji klavišai",
|
||||
"navigation_bar.misc": "Įvairūs",
|
||||
"notification.markForDeletion": "Žymėti ištrynimui",
|
||||
"notification_purge.btn_all": "Pasirinkti\nviską",
|
||||
"notification_purge.btn_apply": "Valyti\npasirinktus",
|
||||
"notification_purge.btn_invert": "Apversti\npasirinkimą",
|
||||
"notification_purge.btn_none": "Pasirinkti\nnieko",
|
||||
"notification_purge.start": "Įeiti į pranešimų valymo režimą",
|
||||
"notifications.column_settings.filter_bar.show_bar": "Rodyti filtro juostą",
|
||||
"notifications.marked_clear": "Valyti pasirinktus pranešimus",
|
||||
"notifications.marked_clear_confirmation": "Ar tikrai norite negrįžtamai išvalyti visus pasirinktus pranešimus?",
|
||||
"settings.always_show_spoilers_field": "Visada įjungti turinio įspėjimo lauką",
|
||||
"settings.auto_collapse": "Automatinis suskleidimas",
|
||||
"settings.auto_collapse_all": "Viskas",
|
||||
"settings.auto_collapse_height": "Aukštis (taškais), kad įrašas būtų laikomas ilgu",
|
||||
"settings.auto_collapse_lengthy": "Ilgi įrašai",
|
||||
"settings.auto_collapse_media": "Įrašai su medija",
|
||||
"settings.auto_collapse_notifications": "Pranešimai",
|
||||
"settings.auto_collapse_reblogs": "Pasidalinimai",
|
||||
"settings.auto_collapse_replies": "Atsakymai",
|
||||
"settings.close": "Užverti",
|
||||
"settings.collapsed_statuses": "Suskleisti įrašai",
|
||||
"settings.compose_box_opts": "Sukūrimo langelis",
|
||||
"settings.confirm_before_clearing_draft": "Rodyti patvirtinimo dialogo langą prieš perrašant kuriamą įrašą",
|
||||
"settings.confirm_boost_missing_media_description": "Rodyti patvirtinimo dialogo langą prieš pasidalinant įrašus, kuriems trūksta medijos aprašų",
|
||||
"settings.confirm_missing_media_description": "Rodyti patvirtinimo dialogo langą prieš siunčiant įrašus, kuriems trūksta medijos aprašų",
|
||||
"settings.content_warnings": "Turinio įspėjimai",
|
||||
"settings.content_warnings.regexp": "Reguliarusis reiškinys",
|
||||
"settings.content_warnings_filter": "Turinio įspėjimai automatiškai neišskleidžiami:",
|
||||
"settings.content_warnings_media_outside": "Rodyti medijos priedus už turinio įspėjimų ribų",
|
||||
"settings.content_warnings_media_outside_hint": "Atkurkite „Mastodon“ išsiuntimo srauto elgseną, nustačius, kad turinio įspėjimo perjungiklis nepaveiktų medijos priedų.",
|
||||
"settings.content_warnings_shared_state": "Rodyti / slėpti visų kopijų turinį vienu metu",
|
||||
"settings.content_warnings_shared_state_hint": "Atkurkite „Mastodon“ elgseną, nustatčius, kad turinio įspėjimo mygtukas vienu metu paveiktų visas įrašo kopijas. Tai neleis automatiškai suskleisti bet kurios įrašo kopijos su išskleistu TĮ.",
|
||||
"settings.content_warnings_unfold_opts": "Automatinio atskleidžiamojo parinktys",
|
||||
"settings.deprecated_setting": "Šis nustatymas dabar valdomas iš „Mastodon“ {settings_page_link}.",
|
||||
"settings.enable_collapsed": "Įjungti suskleistus įrašus",
|
||||
"settings.enable_collapsed_hint": "Suskleisti įrašai turi kai kurias turinio dalis paslėptas, kad užimtų mažiau vietos ekrane. Tai skiriasi nuo turinio įspėjimo funkcijos.",
|
||||
"settings.enable_content_warnings_auto_unfold": "Automatiškai atskleisti turinio įspėjimus",
|
||||
"settings.fullwidth_view": "Ištempti stulpelius į visą plotį (tik darbalaukio režime)",
|
||||
"settings.fullwidth_view_hint": "Ištempia stulpelius, kad užpildytų visą laisvą vietą.",
|
||||
"settings.general": "Bendrieji",
|
||||
"settings.hicolor_privacy_icons": "Didelės spalvos privatumo piktogramos",
|
||||
"settings.hicolor_privacy_icons.hint": "Rodyti privatumo piktogramas ryškiomis ir lengvai atskiriamomis spalvomis.",
|
||||
"settings.image_backgrounds": "Vaizdo fonai",
|
||||
"settings.image_backgrounds_media": "Peržiūrėti suskleistą įrašo mediją",
|
||||
"settings.image_backgrounds_media_hint": "Jei įrašas turi kokių nors medijos priedų, kaip foną naudoti pirmąjį.",
|
||||
"settings.image_backgrounds_users": "Suteikti suskleistiems įrašams vaizdo foną",
|
||||
"settings.inline_preview_cards": "Įterptinės peržiūros kortelės išorinėms nuorodoms",
|
||||
"settings.layout_opts": "Išdėstymo parinktys",
|
||||
"settings.media": "Medija",
|
||||
"settings.media_fullwidth": "Viso pločio medijos peržiūros",
|
||||
"settings.media_letterbox": "Raidžių langelio medija",
|
||||
"settings.media_letterbox_hint": "Mažinti mastelį ir raidžių langelio mediją, kad ji užpildytų vaizdo podėlius, vietoj to juos ištempti ir apkarpyti.",
|
||||
"settings.media_reveal_behind_cw": "Atskleisti jautrią mediją po TĮ pagal numatytąjį",
|
||||
"settings.notifications.favicon_badge": "Neskaitytų pranešimų svetainės piktogramos ženklelis",
|
||||
"settings.notifications.favicon_badge.hint": "Pridėti neskaitytų pranešimų ženklelį prie svetainės piktogramos",
|
||||
"settings.notifications.tab_badge": "Neskaitytų pranešimų ženklelis",
|
||||
"settings.notifications.tab_badge.hint": "Rodyti neskaitytų pranešimų ženklelį stulpelio piktogramose, kai pranešimų stulpelis nėra atvertas.",
|
||||
"settings.notifications_opts": "Pranešimų parinktys",
|
||||
"settings.pop_in_left": "kairėje",
|
||||
"settings.pop_in_player": "Įjungti iškylančiąją leistuvę",
|
||||
"settings.pop_in_position": "Iškylančio leistuvės vieta:",
|
||||
"settings.pop_in_right": "dešinėje",
|
||||
"settings.preferences": "Naudotojo nuostatos",
|
||||
"settings.prepend_cw_re": "Pridėti „re:“ prie turinio įspėjimų, kai atsakoma",
|
||||
"settings.preselect_on_reply": "Iš anksto parinkti naudotojų vardus atsakant",
|
||||
"settings.preselect_on_reply_hint": "Atsakant į pokalbį su daugeliu dalyvių, iš anksto pasirinkti naudotojų vardus po pirmojo.",
|
||||
"settings.rewrite_mentions": "Perrašyti paminėjimus rodomose būsenose",
|
||||
"settings.rewrite_mentions_acct": "Perrašyti su naudotojo vardu ir domenu (kai paskyra nuotolinė)",
|
||||
"settings.rewrite_mentions_no": "Neperrašyti paminėjimų",
|
||||
"settings.rewrite_mentions_username": "Perrašyti su naudotojo vardu",
|
||||
"settings.shared_settings_link": "naudotojo nuostatos",
|
||||
"settings.show_action_bar": "Rodyti veiksmo mygtukus suskleistuose įrašuose",
|
||||
"settings.show_content_type_choice": "Rodyti turinio tipo pasirinkimą, kai kuriami įrašai",
|
||||
"settings.show_published_toast": "Rodyti tostą, kai skelbiant / išsaugant įrašą",
|
||||
"settings.show_reply_counter": "Rodyti apytikslį atsakymų skaičių",
|
||||
"settings.side_arm": "Antrinio įrašo mygtukas:",
|
||||
"settings.side_arm.none": "Jokio",
|
||||
"settings.side_arm_reply_mode": "Atsakant į įrašą, antrinis įrašo mygtukas turėtų:",
|
||||
"settings.side_arm_reply_mode.copy": "Nukopijuoti įrašo privatumo nustatymą, į kurį atsakoma",
|
||||
"settings.side_arm_reply_mode.keep": "Išlaikyti nustatytą privatumą",
|
||||
"settings.side_arm_reply_mode.restrict": "Apriboti privatumo nustatymą iki to įrašo, į kurį atsakoma",
|
||||
"settings.status_icons": "Įrašo piktogramos",
|
||||
"settings.status_icons_language": "Kalbos indikatorius",
|
||||
"settings.status_icons_local_only": "Tik vietinis indikatorius",
|
||||
"settings.status_icons_media": "Medijos ir apklausos indikatoriai",
|
||||
"settings.status_icons_reply": "Atsakymo indikatorius",
|
||||
"settings.status_icons_visibility": "Įrašo privatumo indikatorius",
|
||||
"settings.swipe_to_change_columns": "Leisti keisti stulpelius perbraukiant (tik mobiliesiems)",
|
||||
"settings.tag_misleading_links": "Žymėti klaidinančias nuorodas",
|
||||
"settings.tag_misleading_links.hint": "Pridėkite vizualinį indikatorių su nuorodos paskirties serveriu prie kiekvienos nuorodos, kurioje ji nėra aiškiai paminėta.",
|
||||
"settings.wide_view": "Platusis vaizdas (tik darbalaukio režimu)",
|
||||
"settings.wide_view_hint": "Ištempia stulpelius, kad geriau užimtų laisvą vietą.",
|
||||
"status.collapse": "Suskleisti",
|
||||
"status.filtered": "Filtruota",
|
||||
"status.has_audio": "Turi pridėtų garso įrašų failų",
|
||||
"status.has_pictures": "Turi pridėtų nuotraukų",
|
||||
"status.has_preview_card": "Turi pridėtą peržiūros kortelę",
|
||||
"status.has_video": "Turi pridėtų vaizdo įrašų",
|
||||
"status.hide": "Slėpti įrašą",
|
||||
"status.in_reply_to": "Šis įrašas yra atsakymas",
|
||||
"status.is_poll": "Šis įrašas yra apklausa",
|
||||
"status.local_only": "Matomas tik iš jūsų serverio",
|
||||
"status.show_filter_reason": "Rodyti vis tiek",
|
||||
"status.uncollapse": "Išskleisti"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,113 @@
|
||||
{
|
||||
"about.fork_disclaimer": "Glitch-soc - это бесплатное программное обеспечение с открытым исходным кодом, обращенное от Mastodon.",
|
||||
"about.fork_disclaimer": "Glitch-soc — это свободное программное обеспечение с открытым исходным кодом, ответвлённое от Mastodon.",
|
||||
"account.disclaimer_full": "Приведённые ниже сведения могут не полностью соответствовать профилю пользователя.",
|
||||
"account.follows": "Подписки",
|
||||
"account.follows_you": "Подписан(а) на вас",
|
||||
"account.suspended_disclaimer_full": "Этот пользователь был заблокирован модератором.",
|
||||
"account.view_full_profile": "Открыть полный профиль",
|
||||
"boost_modal.missing_description": "Этот пост содержит медиафайлы без описания",
|
||||
"column.favourited_by": "Добавили в избранное",
|
||||
"column.heading": "Прочее",
|
||||
"column.reblogged_by": "Продвинули",
|
||||
"column.subheading": "Прочие разделы",
|
||||
"column_header.profile": "Профиль",
|
||||
"column_subheading.lists": "Списки",
|
||||
"column_subheading.navigation": "Навигация",
|
||||
"community.column_settings.allow_local_only": "Показывать нефедерируемые посты",
|
||||
"compose.attach.doodle": "Нарисовать что-нибудь",
|
||||
"compose.change_federation": "Изменить настройки федерации",
|
||||
"compose.content-type.change": "Изменить настройки форматирования",
|
||||
"compose.content-type.html": "HTML",
|
||||
"compose.content-type.html_meta": "Использовать HTML для написания постов",
|
||||
"compose.content-type.markdown": "Markdown",
|
||||
"compose.content-type.markdown_meta": "Использовать Markdown для написания постов",
|
||||
"compose.content-type.plain": "Простой текст",
|
||||
"compose.content-type.plain_meta": "Не использовать продвинутое форматирование",
|
||||
"compose.disable_threaded_mode": "Отключить режим треда",
|
||||
"compose.enable_threaded_mode": "Включить режим треда",
|
||||
"confirmation_modal.do_not_ask_again": "Больше не спрашивать подтверждение",
|
||||
"confirmations.deprecated_settings.confirm": "Использовать настройки Mastodon",
|
||||
"confirmations.missing_media_description.confirm": "Всё равно опубликовать",
|
||||
"direct.group_by_conversations": "Группировать по перепискам",
|
||||
"endorsed_accounts_editor.endorsed_accounts": "Рекомендованные аккаунты",
|
||||
"favourite_modal.favourite": "Добавить пост в избранное?",
|
||||
"federation.federated.long": "Разрешить делиться этим постом с другими серверами",
|
||||
"federation.federated.short": "Федерация",
|
||||
"federation.local_only.long": "Запретить делиться этим постом с другими серверами",
|
||||
"federation.local_only.short": "Без федерации",
|
||||
"firehose.column_settings.allow_local_only": "Показывать нефедерируемые посты по вкладке «Все»",
|
||||
"home.column_settings.advanced": "Продвинутые настройки",
|
||||
"home.column_settings.filter_regex": "Фильтр по регулярным выражениям",
|
||||
"home.column_settings.show_direct": "Показывать личные упоминания",
|
||||
"keyboard_shortcuts.bookmark": "добавить закладку",
|
||||
"keyboard_shortcuts.toggle_collapse": "свернуть/развернуть пост",
|
||||
"moved_to_warning": "Этот аккаунт переехал на {moved_to_link}, и скорее всего не принимает новых подписчиков.",
|
||||
"navigation_bar.app_settings": "Настройки приложения",
|
||||
"navigation_bar.keyboard_shortcuts": "Сочетания клавиш",
|
||||
"navigation_bar.misc": "Прочее",
|
||||
"notification.markForDeletion": "Отметить для удаления",
|
||||
"notification_purge.btn_all": "Выбрать все",
|
||||
"notification_purge.btn_apply": "Удалить выбранное",
|
||||
"notification_purge.btn_invert": "Инвертировать выбор",
|
||||
"notification_purge.btn_none": "Отменить выбор",
|
||||
"notification_purge.start": "Войти в режим очистки уведомлений",
|
||||
"notifications.column_settings.filter_bar.show_bar": "Показать панель фильтров",
|
||||
"notifications.marked_clear": "Удалить выбранные уведомления",
|
||||
"notifications.marked_clear_confirmation": "Вы уверены, что хотите безвозвратно удалить все выбранные уведомления?",
|
||||
"settings.always_show_spoilers_field": "Всегда ставить предупреждение о содержании",
|
||||
"settings.auto_collapse": "Сворачивать автоматически",
|
||||
"settings.auto_collapse_all": "Всё",
|
||||
"settings.auto_collapse_height": "Высота (в пикселях) для того, чтобы пост считался длинным",
|
||||
"settings.auto_collapse_lengthy": "Длинные посты",
|
||||
"settings.auto_collapse_media": "Посты с медиафайлами",
|
||||
"settings.auto_collapse_notifications": "Уведомления",
|
||||
"settings.auto_collapse_reblogs": "Продвижения",
|
||||
"settings.auto_collapse_replies": "Ответы",
|
||||
"settings.close": "Закрыть",
|
||||
"settings.collapsed_statuses": "Сворачивание постов",
|
||||
"settings.compose_box_opts": "Форма постинга",
|
||||
"settings.content_warnings": "Content warnings",
|
||||
"settings.preferences": "Preferences"
|
||||
"settings.content_warnings.regexp": "Регулярное выражение",
|
||||
"settings.content_warnings_filter": "Предупреждения о содержании, к которым автоматическое разворачивание не применяется:",
|
||||
"settings.content_warnings_media_outside": "Показывать медиафайлы внизу под предупреждением о содержании",
|
||||
"settings.content_warnings_media_outside_hint": "Воспроизводить исходное поведение Mastodon, когда предупреждение о содержании сворачивает только текст поста",
|
||||
"settings.content_warnings_shared_state": "Показывать/скрывать содержимое всех копий вместе",
|
||||
"settings.content_warnings_shared_state_hint": "Воспроизводить исходное поведение Mastodon, когда раскрывание и закрывание предупреждения о содержимом охватывает все копии поста сразу. Это предотвращает автоматическое сворачивание копий поста с уже однажды раскрытым CW",
|
||||
"settings.content_warnings_unfold_opts": "Автоматическое раскрытие",
|
||||
"settings.deprecated_setting": "Эта опция теперь может быть включена в {settings_page_link} Mastodon",
|
||||
"settings.enable_collapsed": "Включить сворачивание постов",
|
||||
"settings.enable_collapsed_hint": "Свёрнутые посты отображаются частично скрытыми, чтобы занимать меньше места на экране. Эту функцию не следует путать с предупреждением о содержании",
|
||||
"settings.enable_content_warnings_auto_unfold": "Автоматически раскрывать предупреждения о содержании",
|
||||
"settings.general": "Общие",
|
||||
"settings.hicolor_privacy_icons": "Цветные значки публичности поста",
|
||||
"settings.hicolor_privacy_icons.hint": "Отображать значки публичности поста в ярких и различимых цветах",
|
||||
"settings.media": "Медиафайлы",
|
||||
"settings.notifications.favicon_badge": "Индикатор уведомлений на иконке сайта",
|
||||
"settings.notifications.favicon_badge.hint": "Добавить индикатор непрочитанных уведомлений на иконку вкладки",
|
||||
"settings.notifications.tab_badge": "Индикатор непрочитанных уведомлений",
|
||||
"settings.notifications_opts": "Опции уведомлений",
|
||||
"settings.pop_in_left": "Слева",
|
||||
"settings.pop_in_player": "Включить плавающий плеер",
|
||||
"settings.pop_in_position": "Расположение плавающего плеера:",
|
||||
"settings.pop_in_right": "Справа",
|
||||
"settings.preferences": "Preferences",
|
||||
"settings.prepend_cw_re": "Добавлять «re: » перед предупреждением о содержании при ответе",
|
||||
"settings.shared_settings_link": "настройках пользователя",
|
||||
"settings.show_reply_counter": "Показывать приблизительное число ответов",
|
||||
"settings.side_arm": "Дополнительная кнопка постинга:",
|
||||
"settings.side_arm.none": "Нет",
|
||||
"settings.side_arm_reply_mode": "При ответе на пост дополнительная кнопка постинга должна:",
|
||||
"settings.status_icons": "Значки постов",
|
||||
"settings.status_icons_language": "Индикатор языка",
|
||||
"settings.status_icons_local_only": "Индикатор нефедерируемого поста",
|
||||
"settings.status_icons_media": "Индикаторы медиафайлов и опросов",
|
||||
"settings.status_icons_reply": "Индикатор ответа",
|
||||
"settings.status_icons_visibility": "Индикатор публичности поста",
|
||||
"settings.tag_misleading_links": "Помечать обманчивые ссылки",
|
||||
"status.collapse": "Свернуть",
|
||||
"status.hide": "Скрыть пост",
|
||||
"status.in_reply_to": "Этот пост является ответом",
|
||||
"status.is_poll": "Этот пост содержит опрос",
|
||||
"status.show_filter_reason": "Всё равно показать",
|
||||
"status.uncollapse": "Развернуть"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,87 @@
|
||||
{
|
||||
"about.fork_disclaimer": "Glitch-soc is free open source software forked fae Mastodon.",
|
||||
"account.disclaimer_full": "Information below may reflect the user's profile incompletely",
|
||||
"account.follows": "Follows",
|
||||
"account.suspended_disclaimer_full": "This user has been suspendit by a moderator.",
|
||||
"account.view_full_profile": "View full profile",
|
||||
"boost_modal.missing_description": "This post contains some media withoot description",
|
||||
"column.favourited_by": "Favouritit by",
|
||||
"column.heading": "Misc",
|
||||
"column.reblogged_by": "Boosted by",
|
||||
"column.subheading": "Miscellaneous options",
|
||||
"column_header.profile": "Profile",
|
||||
"column_subheading.lists": "Lists",
|
||||
"column_subheading.navigation": "Navigation",
|
||||
"community.column_settings.allow_local_only": "Show local-only posts",
|
||||
"compose.attach.doodle": "Draw something",
|
||||
"compose.change_federation": "Change federation settins",
|
||||
"compose.content-type.change": "Change advanced formatting options",
|
||||
"compose.content-type.html": "HTML",
|
||||
"compose.content-type.html_meta": "Format yer posts using HTML",
|
||||
"compose.content-type.markdown": "Markdoon",
|
||||
"compose.content-type.markdown_meta": "Format yer posts using Markdoon",
|
||||
"compose.content-type.plain": "Plain text",
|
||||
"compose.content-type.plain_meta": "Write with no advanced formatting",
|
||||
"compose.disable_threaded_mode": "Disable threaded mode",
|
||||
"compose.enable_threaded_mode": "Enable threaded mode",
|
||||
"compose_form.sensitive.hide": "{count, plural, one {Mark media as sensitive} other {Mark media as sensitive}}",
|
||||
"compose_form.sensitive.marked": "{count, plural, one {Media is marked as sensitive} other {Media is marked as sensitive}}",
|
||||
"compose_form.sensitive.unmarked": "{count, plural, one {Media isnae marked as sensitive} other {Media isnae marked as sensitive}}",
|
||||
"confirmation_modal.do_not_ask_again": "Dinnae ask for confirmation again",
|
||||
"confirmations.deprecated_settings.confirm": "Use Mastodon preferences",
|
||||
"confirmations.deprecated_settings.message": "Some of the glitch-soc device-specific {app_settings} yer using hae been replaced by Mastodon {preferences} and will be overriden:",
|
||||
"direct.group_by_conversations": "Group by conversation",
|
||||
"favourite_modal.favourite": "Favourite post?",
|
||||
"federation.federated.long": "Allow this post to reach other servers",
|
||||
"federation.federated.short": "Federated",
|
||||
"federation.local_only.long": "Prevent this post from reaching other servers",
|
||||
"federation.local_only.short": "Local-only",
|
||||
"firehose.column_settings.allow_local_only": "Show local-only posts in \"All\"",
|
||||
"home.column_settings.advanced": "Advanced",
|
||||
"home.column_settings.filter_regex": "Filter oot by regular expressions",
|
||||
"home.column_settings.show_direct": "Show private mentions",
|
||||
"home.settings": "Column settins",
|
||||
"keyboard_shortcuts.bookmark": "tae bookmark",
|
||||
"keyboard_shortcuts.secondary_toot": "tae send post using secondary privacy settin",
|
||||
"moved_to_warning": "This account is marked as moved tae {moved_to_link}, an' may not accept new follows.",
|
||||
"navigation_bar.app_settings": "App settins",
|
||||
"navigation_bar.keyboard_shortcuts": "Keyboard shortcuts",
|
||||
"navigation_bar.misc": "Misc",
|
||||
"notifications.column_settings.filter_bar.show_bar": "Show filter bar",
|
||||
"settings.always_show_spoilers_field": "Always enable the Content Warning field",
|
||||
"settings.close": "Close",
|
||||
"settings.compose_box_opts": "Compose box",
|
||||
"settings.confirm_before_clearing_draft": "Show confirmation dialog before overwriting the message being composed",
|
||||
"settings.confirm_boost_missing_media_description": "Show confirmation dialog before boosting posts lacking media descriptions",
|
||||
"settings.content_warnings": "Content warnings",
|
||||
"settings.preferences": "Preferences"
|
||||
"settings.content_warnings.regexp": "Regular expression",
|
||||
"settings.content_warnings_filter": "Content warnings tae not automatically unfold:",
|
||||
"settings.content_warnings_shared_state": "Show/hide content fae all copies at once",
|
||||
"settings.content_warnings_shared_state_hint": "Reproduce upstream Mastodon behavior by having the Content Warning button affect all copies of a post at once. This will prevent automatic collapsing of any copy of a post wi' unfolded CW",
|
||||
"settings.content_warnings_unfold_opts": "Auto-unfolding options",
|
||||
"settings.deprecated_setting": "This settin is now controlled fae Mastodon's {settings_page_link}",
|
||||
"settings.enable_content_warnings_auto_unfold": "Automatically unfold content-warnings",
|
||||
"settings.fullwidth_view": "Stretch columns tae full width (Desktop mode only)",
|
||||
"settings.fullwidth_view_hint": "Stretches columns tae fill all the available space.",
|
||||
"settings.general": "General",
|
||||
"settings.hicolor_privacy_icons": "High color privacy icons",
|
||||
"settings.hicolor_privacy_icons.hint": "Display privacy icons in bright an' easily distinguishable colors",
|
||||
"settings.inline_preview_cards": "Inline preview cards fae external links",
|
||||
"settings.layout_opts": "Layout options",
|
||||
"settings.media": "Media",
|
||||
"settings.media_fullwidth": "Full-width media previews",
|
||||
"settings.media_letterbox": "Letterbox media",
|
||||
"settings.media_letterbox_hint": "Scale doon an' letterbox media tae fill the image containers instead of stretching an' cropping them",
|
||||
"settings.media_reveal_behind_cw": "Reveal sensitive media behind a CW by default",
|
||||
"settings.notifications.favicon_badge": "Unread notifications favicon badge",
|
||||
"settings.notifications.favicon_badge.hint": "Add a badge fae unread notifications to the favicon",
|
||||
"settings.notifications.tab_badge": "Unread notifications badge",
|
||||
"settings.notifications.tab_badge.hint": "Display a badge fae unread notifications in the column icons when the notifications column isnae open",
|
||||
"settings.notifications_opts": "Notifications options",
|
||||
"settings.pop_in_left": "Left",
|
||||
"settings.pop_in_player": "Enable pop-in player",
|
||||
"settings.pop_in_position": "Pop-in player position:",
|
||||
"settings.pop_in_right": "Right",
|
||||
"settings.preferences": "Preferences",
|
||||
"settings.prepend_cw_re": "Prepend “re: ” to content warnings when replying"
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user