mirror of
https://github.com/glitch-soc/mastodon.git
synced 2025-12-11 14:30:35 +00:00
Compare commits
211 Commits
v4.3.3
...
eeadda0e71
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eeadda0e71 | ||
|
|
96a5d173f1 | ||
|
|
5057735a54 | ||
|
|
27b74ba7b8 | ||
|
|
770cf42085 | ||
|
|
ef1af11956 | ||
|
|
140e011e73 | ||
|
|
43f8760c95 | ||
|
|
473c112dae | ||
|
|
821e735524 | ||
|
|
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 |
@@ -78,7 +78,7 @@ OTP_SECRET=
|
||||
# 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
|
||||
# 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=
|
||||
|
||||
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
|
||||
|
||||
4
.github/workflows/build-push-pr.yml
vendored
4
.github/workflows/build-push-pr.yml
vendored
@@ -32,8 +32,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
|
||||
version_metadata: ${{ needs.compute-suffix.outputs.metadata }}
|
||||
@@ -49,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 }}
|
||||
|
||||
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.3.') }}
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
4
.github/workflows/test-ruby.yml
vendored
4
.github/workflows/test-ruby.yml
vendored
@@ -127,6 +127,7 @@ jobs:
|
||||
- '3.1'
|
||||
- '3.2'
|
||||
- '.ruby-version'
|
||||
- '3.4'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -229,6 +230,7 @@ jobs:
|
||||
- '3.1'
|
||||
- '3.2'
|
||||
- '.ruby-version'
|
||||
- '3.4'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -308,6 +310,7 @@ jobs:
|
||||
- '3.1'
|
||||
- '3.2'
|
||||
- '.ruby-version'
|
||||
- '3.4'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -425,6 +428,7 @@ jobs:
|
||||
- '3.1'
|
||||
- '3.2'
|
||||
- '.ruby-version'
|
||||
- '3.4'
|
||||
search-image:
|
||||
- docker.elastic.co/elasticsearch/elasticsearch:7.17.13
|
||||
include:
|
||||
|
||||
203
CHANGELOG.md
203
CHANGELOG.md
@@ -2,6 +2,209 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [4.3.16] - 2025-12-08
|
||||
|
||||
### Security
|
||||
|
||||
- Fix inconsistent error handling leaking information on existence of private posts ([GHSA-gwhw-gcjx-72v8](https://github.com/mastodon/mastodon/security/advisories/GHSA-gwhw-gcjx-72v8))
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix YouTube embeds by sending referer (#37126 by @ChaosExAnima)
|
||||
- Fix YouTube iframe not being able to start at a defined time (#26584 by @BrunoViveiros)
|
||||
- Fix known expensive S3 batch delete operation failing because of short timeouts (#37004 by @ClearlyClaire)
|
||||
|
||||
## [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
|
||||
|
||||
@@ -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
|
||||
@@ -161,7 +164,7 @@ RUN \
|
||||
libexif-dev \
|
||||
libexpat1-dev \
|
||||
libgirepository1.0-dev \
|
||||
libheif-dev \
|
||||
libheif-dev/bookworm-backports \
|
||||
libimagequant-dev \
|
||||
libjpeg62-turbo-dev \
|
||||
liblcms2-dev \
|
||||
@@ -344,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
|
||||
|
||||
154
Gemfile.lock
154
Gemfile.lock
@@ -10,35 +10,35 @@ GIT
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
actioncable (7.1.5.1)
|
||||
actionpack (= 7.1.5.1)
|
||||
activesupport (= 7.1.5.1)
|
||||
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.5.1)
|
||||
actionpack (= 7.1.5.1)
|
||||
activejob (= 7.1.5.1)
|
||||
activerecord (= 7.1.5.1)
|
||||
activestorage (= 7.1.5.1)
|
||||
activesupport (= 7.1.5.1)
|
||||
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.5.1)
|
||||
actionpack (= 7.1.5.1)
|
||||
actionview (= 7.1.5.1)
|
||||
activejob (= 7.1.5.1)
|
||||
activesupport (= 7.1.5.1)
|
||||
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.5.1)
|
||||
actionview (= 7.1.5.1)
|
||||
activesupport (= 7.1.5.1)
|
||||
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.5.1)
|
||||
actionpack (= 7.1.5.1)
|
||||
activerecord (= 7.1.5.1)
|
||||
activestorage (= 7.1.5.1)
|
||||
activesupport (= 7.1.5.1)
|
||||
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.5.1)
|
||||
activesupport (= 7.1.5.1)
|
||||
actionview (7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.11)
|
||||
rails-dom-testing (~> 2.2)
|
||||
@@ -64,22 +64,22 @@ GEM
|
||||
activemodel (>= 4.1)
|
||||
case_transform (>= 0.2)
|
||||
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
|
||||
activejob (7.1.5.1)
|
||||
activesupport (= 7.1.5.1)
|
||||
activejob (7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (7.1.5.1)
|
||||
activesupport (= 7.1.5.1)
|
||||
activerecord (7.1.5.1)
|
||||
activemodel (= 7.1.5.1)
|
||||
activesupport (= 7.1.5.1)
|
||||
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.5.1)
|
||||
actionpack (= 7.1.5.1)
|
||||
activejob (= 7.1.5.1)
|
||||
activerecord (= 7.1.5.1)
|
||||
activesupport (= 7.1.5.1)
|
||||
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.5.1)
|
||||
activesupport (7.1.5.2)
|
||||
base64
|
||||
benchmark (>= 0.3)
|
||||
bigdecimal
|
||||
@@ -190,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)
|
||||
@@ -266,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
|
||||
@@ -410,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)
|
||||
@@ -437,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)
|
||||
@@ -447,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)
|
||||
@@ -455,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.8)
|
||||
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
|
||||
@@ -475,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)
|
||||
@@ -492,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)
|
||||
@@ -619,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)
|
||||
@@ -642,20 +642,20 @@ GEM
|
||||
rackup (1.0.0)
|
||||
rack (< 3)
|
||||
webrick
|
||||
rails (7.1.5.1)
|
||||
actioncable (= 7.1.5.1)
|
||||
actionmailbox (= 7.1.5.1)
|
||||
actionmailer (= 7.1.5.1)
|
||||
actionpack (= 7.1.5.1)
|
||||
actiontext (= 7.1.5.1)
|
||||
actionview (= 7.1.5.1)
|
||||
activejob (= 7.1.5.1)
|
||||
activemodel (= 7.1.5.1)
|
||||
activerecord (= 7.1.5.1)
|
||||
activestorage (= 7.1.5.1)
|
||||
activesupport (= 7.1.5.1)
|
||||
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.5.1)
|
||||
railties (= 7.1.5.2)
|
||||
rails-controller-testing (1.0.5)
|
||||
actionpack (>= 5.0.1.rc1)
|
||||
actionview (>= 5.0.1.rc1)
|
||||
@@ -670,9 +670,9 @@ GEM
|
||||
rails-i18n (7.0.9)
|
||||
i18n (>= 0.7, < 2)
|
||||
railties (>= 6.0.0, < 8)
|
||||
railties (7.1.5.1)
|
||||
actionpack (= 7.1.5.1)
|
||||
activesupport (= 7.1.5.1)
|
||||
railties (7.1.5.2)
|
||||
actionpack (= 7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
irb
|
||||
rackup (>= 1.0.0)
|
||||
rake (>= 12.2)
|
||||
@@ -702,7 +702,7 @@ GEM
|
||||
responders (3.1.1)
|
||||
actionpack (>= 5.2)
|
||||
railties (>= 5.2)
|
||||
rexml (3.3.9)
|
||||
rexml (3.4.4)
|
||||
rotp (6.3.0)
|
||||
rouge (4.3.0)
|
||||
rpam2 (4.0.2)
|
||||
@@ -767,10 +767,10 @@ GEM
|
||||
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)
|
||||
@@ -840,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)
|
||||
@@ -868,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)
|
||||
@@ -900,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)
|
||||
@@ -1059,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
|
||||
|
||||
@@ -15,7 +15,7 @@ A "vulnerability in Mastodon" is a vulnerability in the code distributed through
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ---------------- |
|
||||
| 4.3.x | Yes |
|
||||
| 4.2.x | Yes |
|
||||
| 4.1.x | Until 2025-04-08 |
|
||||
| < 4.1 | No |
|
||||
| 4.4.x | Yes |
|
||||
| 4.3.x | Until 2026-05-06 |
|
||||
| 4.2.x | Until 2026-01-08 |
|
||||
| < 4.2 | No |
|
||||
|
||||
@@ -22,7 +22,7 @@ class ActivityPub::LikesController < ActivityPub::BaseController
|
||||
def set_status
|
||||
@status = @account.statuses.find(params[:status_id])
|
||||
authorize @status, :show?
|
||||
rescue Mastodon::NotPermittedError
|
||||
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
|
||||
not_found
|
||||
end
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ class ActivityPub::RepliesController < ActivityPub::BaseController
|
||||
def set_status
|
||||
@status = @account.statuses.find(params[:status_id])
|
||||
authorize @status, :show?
|
||||
rescue Mastodon::NotPermittedError
|
||||
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
|
||||
not_found
|
||||
end
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ class ActivityPub::SharesController < ActivityPub::BaseController
|
||||
def set_status
|
||||
@status = @account.statuses.find(params[:status_id])
|
||||
authorize @status, :show?
|
||||
rescue Mastodon::NotPermittedError
|
||||
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
|
||||
not_found
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -17,7 +17,7 @@ class Api::V1::Polls::VotesController < Api::BaseController
|
||||
def set_poll
|
||||
@poll = Poll.attached.find(params[:poll_id])
|
||||
authorize @poll.status, :show?
|
||||
rescue Mastodon::NotPermittedError
|
||||
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
|
||||
not_found
|
||||
end
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ class Api::V1::PollsController < Api::BaseController
|
||||
def set_poll
|
||||
@poll = Poll.attached.find(params[:id])
|
||||
authorize @poll.status, :show?
|
||||
rescue Mastodon::NotPermittedError
|
||||
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
|
||||
not_found
|
||||
end
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -10,7 +10,7 @@ class Api::V1::Statuses::BaseController < Api::BaseController
|
||||
def set_status
|
||||
@status = Status.find(params[:status_id])
|
||||
authorize @status, :show?
|
||||
rescue Mastodon::NotPermittedError
|
||||
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
|
||||
not_found
|
||||
end
|
||||
end
|
||||
|
||||
@@ -23,7 +23,7 @@ class Api::V1::Statuses::BookmarksController < Api::V1::Statuses::BaseController
|
||||
bookmark&.destroy!
|
||||
|
||||
render json: @status, serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new([@status], current_account.id, bookmarks_map: { @status.id => false })
|
||||
rescue Mastodon::NotPermittedError
|
||||
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
|
||||
not_found
|
||||
end
|
||||
end
|
||||
|
||||
@@ -25,7 +25,7 @@ class Api::V1::Statuses::FavouritesController < Api::V1::Statuses::BaseControlle
|
||||
|
||||
relationships = StatusRelationshipsPresenter.new([@status], current_account.id, favourites_map: { @status.id => false }, attributes_map: { @status.id => { favourites_count: count } })
|
||||
render json: @status, serializer: REST::StatusSerializer, relationships: relationships
|
||||
rescue Mastodon::NotPermittedError
|
||||
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
|
||||
not_found
|
||||
end
|
||||
end
|
||||
|
||||
@@ -36,7 +36,7 @@ class Api::V1::Statuses::ReblogsController < Api::V1::Statuses::BaseController
|
||||
|
||||
relationships = StatusRelationshipsPresenter.new([@status], current_account.id, reblogs_map: { @reblog.id => false }, attributes_map: { @reblog.id => { reblogs_count: count } })
|
||||
render json: @reblog, serializer: REST::StatusSerializer, relationships: relationships
|
||||
rescue Mastodon::NotPermittedError
|
||||
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
|
||||
not_found
|
||||
end
|
||||
|
||||
@@ -45,7 +45,7 @@ class Api::V1::Statuses::ReblogsController < Api::V1::Statuses::BaseController
|
||||
def set_reblog
|
||||
@reblog = Status.find(params[:status_id])
|
||||
authorize @reblog, :show?
|
||||
rescue Mastodon::NotPermittedError
|
||||
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
|
||||
not_found
|
||||
end
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ class Api::V1::StatusesController < Api::BaseController
|
||||
def set_status
|
||||
@status = Status.find(params[:id])
|
||||
authorize @status, :show?
|
||||
rescue Mastodon::NotPermittedError
|
||||
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
|
||||
not_found
|
||||
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
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ class Api::Web::EmbedsController < Api::Web::BaseController
|
||||
def set_status
|
||||
@status = Status.find(params[:id])
|
||||
authorize @status, :show?
|
||||
rescue Mastodon::NotPermittedError
|
||||
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
|
||||
not_found
|
||||
end
|
||||
end
|
||||
|
||||
@@ -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?
|
||||
|
||||
@@ -21,7 +21,7 @@ class AuthorizeInteractionsController < ApplicationController
|
||||
def set_resource
|
||||
@resource = located_resource
|
||||
authorize(@resource, :show?) if @resource.is_a?(Status)
|
||||
rescue Mastodon::NotPermittedError
|
||||
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
|
||||
not_found
|
||||
end
|
||||
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -34,7 +34,7 @@ class MediaController < ApplicationController
|
||||
|
||||
def verify_permitted_status!
|
||||
authorize @media_attachment.status, :show?
|
||||
rescue Mastodon::NotPermittedError
|
||||
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
|
||||
not_found
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -59,7 +59,7 @@ class StatusesController < ApplicationController
|
||||
def set_status
|
||||
@status = @account.statuses.find(params[:id])
|
||||
authorize @status, :show?
|
||||
rescue Mastodon::NotPermittedError
|
||||
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
|
||||
not_found
|
||||
end
|
||||
|
||||
|
||||
@@ -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?
|
||||
|
||||
|
||||
@@ -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?
|
||||
[]
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -141,6 +141,9 @@ export const pollRecentNotifications = createDataLoadingThunk(
|
||||
|
||||
return { notifications };
|
||||
},
|
||||
{
|
||||
useLoadingBar: false,
|
||||
},
|
||||
);
|
||||
|
||||
export const processNewNotificationForGroups = createAppAsyncThunk(
|
||||
|
||||
@@ -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`);
|
||||
|
||||
@@ -28,6 +28,7 @@ export const AltTextBadge: React.FC<{
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
type='button'
|
||||
ref={anchorRef}
|
||||
className='media-gallery__alt__label'
|
||||
onClick={handleClick}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
),
|
||||
|
||||
@@ -26,18 +26,23 @@ const getHostname = url => {
|
||||
|
||||
const domParser = new DOMParser();
|
||||
|
||||
const addAutoPlay = html => {
|
||||
const handleIframeUrl = (html, url, providerName) => {
|
||||
const document = domParser.parseFromString(html, 'text/html').documentElement;
|
||||
const iframe = document.querySelector('iframe');
|
||||
const startTime = new URL(url).searchParams.get('t');
|
||||
|
||||
if (iframe) {
|
||||
if (iframe.src.indexOf('?') !== -1) {
|
||||
iframe.src += '&';
|
||||
} else {
|
||||
iframe.src += '?';
|
||||
const iframeUrl = new URL(iframe.src);
|
||||
|
||||
iframeUrl.searchParams.set('autoplay', 1);
|
||||
iframeUrl.searchParams.set('auto_play', 1);
|
||||
|
||||
if (providerName === 'YouTube') {
|
||||
iframeUrl.searchParams.set('start', startTime || '');
|
||||
iframe.referrerPolicy = 'strict-origin-when-cross-origin';
|
||||
}
|
||||
|
||||
iframe.src += 'autoplay=1&auto_play=1';
|
||||
iframe.src = iframeUrl.href;
|
||||
|
||||
// DOM parser creates html/body elements around original HTML fragment,
|
||||
// so we need to get innerHTML out of the body and not the entire document
|
||||
@@ -103,7 +108,7 @@ export default class Card extends PureComponent {
|
||||
|
||||
renderVideo () {
|
||||
const { card } = this.props;
|
||||
const content = { __html: addAutoPlay(card.get('html')) };
|
||||
const content = { __html: handleIframeUrl(card.get('html'), card.get('url'), card.get('provider_name')) };
|
||||
|
||||
return (
|
||||
<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) {
|
||||
@@ -273,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');
|
||||
@@ -358,6 +364,8 @@ export const DetailedStatus: React.FC<{
|
||||
);
|
||||
contentMedia.push(hashtagBar);
|
||||
|
||||
const matchedFilters = status.get('matched_filters');
|
||||
|
||||
return (
|
||||
<div style={outerStyle}>
|
||||
<div
|
||||
@@ -386,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>
|
||||
|
||||
@@ -91,6 +91,7 @@ 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']),
|
||||
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']),
|
||||
@@ -270,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,
|
||||
@@ -608,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",
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"account.follows": "ติดตาม",
|
||||
"settings.content_warnings": "Content warnings",
|
||||
"settings.preferences": "Preferences"
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
"confirmations.missing_media_description.message": "你没有为一个或多个媒体撰写描述。请考虑为视障人士添加描述。",
|
||||
"direct.group_by_conversations": "按对话分组",
|
||||
"endorsed_accounts_editor.endorsed_accounts": "精选账户",
|
||||
"favourite_modal.favourite": "点赞嘟文?",
|
||||
"federation.federated.long": "允许此嘟文到达其它服务器",
|
||||
"federation.federated.short": "联动",
|
||||
"federation.local_only.long": "阻止此嘟文到达其它服务器",
|
||||
@@ -89,6 +90,8 @@
|
||||
"settings.enable_collapsed": "启用折叠嘟文",
|
||||
"settings.enable_collapsed_hint": "让折叠的帖子隐藏部分内容以占用较少的屏幕空间。这与“内容警告”功能不同。",
|
||||
"settings.enable_content_warnings_auto_unfold": "自动展开内容警告",
|
||||
"settings.fullwidth_view": "将列拉伸至全宽 (仅桌面模式)",
|
||||
"settings.fullwidth_view_hint": "拉伸列以利用所有可用空间。",
|
||||
"settings.general": "一般",
|
||||
"settings.hicolor_privacy_icons": "彩色隐私图标 ",
|
||||
"settings.hicolor_privacy_icons.hint": "以明亮且易于区分的颜色显示隐私图标",
|
||||
@@ -153,7 +156,5 @@
|
||||
"status.is_poll": "此嘟文是投票",
|
||||
"status.local_only": "此嘟文仅本站可见",
|
||||
"status.show_filter_reason": "仍然显示",
|
||||
"status.show_less": "部分显示",
|
||||
"status.show_more": "完全显示",
|
||||
"status.uncollapse": "展开"
|
||||
}
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
"compose.content-type.plain_meta": "不使用進階格式撰寫",
|
||||
"compose.disable_threaded_mode": "停用貼文串模式",
|
||||
"compose.enable_threaded_mode": "啟用貼文串模式",
|
||||
"compose_form.sensitive.hide": "{count, plural, other {將媒體標記為敏感內容}}",
|
||||
"compose_form.sensitive.marked": "{count, plural, other {媒體已被標記為敏感內容}}",
|
||||
"compose_form.sensitive.unmarked": "{count, plural, other {媒體未被標記為敏感內容}}",
|
||||
"confirmation_modal.do_not_ask_again": "不要再顯示確認訊息",
|
||||
"confirmations.deprecated_settings.confirm": "使用 Mastodon 偏好",
|
||||
"confirmations.deprecated_settings.message": "您正在使用的某些特定於 glitch-soc 設備的 {app_settings} 已被 Mastodon {preferences} 所取代,並將被覆蓋:",
|
||||
@@ -33,6 +36,7 @@
|
||||
"confirmations.missing_media_description.message": "至少有一個媒體附件缺少說明。 在發送貼文之前,請考慮為視障人士在所有媒體附件加上說明。",
|
||||
"direct.group_by_conversations": "以對話分組",
|
||||
"endorsed_accounts_editor.endorsed_accounts": "受推薦帳號",
|
||||
"favourite_modal.favourite": "將貼文加入最愛?",
|
||||
"federation.federated.long": "允許此貼文發布到其他伺服器",
|
||||
"federation.federated.short": "聯邦",
|
||||
"federation.local_only.long": "避免此貼文發布到其他伺服器",
|
||||
@@ -86,6 +90,8 @@
|
||||
"settings.enable_collapsed": "啟用折疊的貼文",
|
||||
"settings.enable_collapsed_hint": "折疊的貼文隱藏了部分內容,以佔用更少的螢幕空間。這與內容警告功能不同",
|
||||
"settings.enable_content_warnings_auto_unfold": "自動展開內容警告",
|
||||
"settings.fullwidth_view": "將欄位延展至全寬(僅限桌面模式)",
|
||||
"settings.fullwidth_view_hint": "將欄位延展以填滿所有可用空間。",
|
||||
"settings.general": "一般設定",
|
||||
"settings.hicolor_privacy_icons": "隱私圖示使用對比色",
|
||||
"settings.hicolor_privacy_icons.hint": "用明亮且易於區分的顏色顯示隱私圖示",
|
||||
@@ -140,12 +146,15 @@
|
||||
"settings.wide_view": "寬廣模式(僅限桌面模式)",
|
||||
"settings.wide_view_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.local_only": "只在此實例可見",
|
||||
"status.show_filter_reason": "仍要顯示",
|
||||
"status.uncollapse": "展開"
|
||||
}
|
||||
|
||||
@@ -150,5 +150,10 @@ export function createAccountFromServerJSON(serverJSON: ApiAccountJSON) {
|
||||
),
|
||||
note_emojified: emojify(accountJSON.note, emojiMap),
|
||||
note_plain: unescapeHTML(accountJSON.note),
|
||||
url:
|
||||
accountJSON.url.startsWith('http://') ||
|
||||
accountJSON.url.startsWith('https://')
|
||||
? accountJSON.url
|
||||
: accountJSON.uri,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,11 +4,10 @@ import { ACCOUNT_LOOKUP_FAIL } from '../actions/accounts';
|
||||
import { importAccounts } from '../actions/accounts_typed';
|
||||
import { domain } from '../initial_state';
|
||||
|
||||
export const normalizeForLookup = str => {
|
||||
str = str.toLowerCase();
|
||||
const trailingIndex = str.indexOf(`@${domain.toLowerCase()}`);
|
||||
return (trailingIndex > 0) ? str.slice(0, trailingIndex) : str;
|
||||
};
|
||||
const pattern = new RegExp(`@${domain}$`, 'gi');
|
||||
|
||||
export const normalizeForLookup = str =>
|
||||
str.toLowerCase().replace(pattern, '');
|
||||
|
||||
const initialState = ImmutableMap();
|
||||
|
||||
|
||||
@@ -330,12 +330,26 @@ const expiresInFromExpiresAt = expires_at => {
|
||||
|
||||
const mergeLocalHashtagResults = (suggestions, prefix, tagHistory) => {
|
||||
prefix = prefix.toLowerCase();
|
||||
|
||||
if (suggestions.length < 4) {
|
||||
const localTags = tagHistory.filter(tag => tag.toLowerCase().startsWith(prefix) && !suggestions.some(suggestion => suggestion.type === 'hashtag' && suggestion.name.toLowerCase() === tag.toLowerCase()));
|
||||
return suggestions.concat(localTags.slice(0, 4 - suggestions.length).toJS().map(tag => ({ type: 'hashtag', name: tag })));
|
||||
} else {
|
||||
return suggestions;
|
||||
suggestions = suggestions.concat(localTags.slice(0, 4 - suggestions.length).toJS().map(tag => ({ type: 'hashtag', name: tag })));
|
||||
}
|
||||
|
||||
// Prefer capitalization from personal history, unless personal history is all lower-case
|
||||
const fixSuggestionCapitalization = (suggestion) => {
|
||||
if (suggestion.type !== 'hashtag')
|
||||
return suggestion;
|
||||
|
||||
const tagFromHistory = tagHistory.find((tag) => tag.localeCompare(suggestion.name, undefined, { sensitivity: 'accent' }) === 0);
|
||||
|
||||
if (!tagFromHistory || tagFromHistory.toLowerCase() === tagFromHistory)
|
||||
return suggestion;
|
||||
|
||||
return { ...suggestion, name: tagFromHistory };
|
||||
};
|
||||
|
||||
return suggestions.map(fixSuggestionCapitalization);
|
||||
};
|
||||
|
||||
const normalizeSuggestions = (state, { accounts, emojis, tags, token }) => {
|
||||
@@ -609,8 +623,13 @@ export default function compose(state = initialState, action) {
|
||||
}
|
||||
|
||||
if (action.status.get('poll')) {
|
||||
let options = action.status.getIn(['poll', 'options']).map(x => x.get('title'));
|
||||
if (options.size < action.maxOptions) {
|
||||
options = options.push('');
|
||||
}
|
||||
|
||||
map.set('poll', ImmutableMap({
|
||||
options: action.status.getIn(['poll', 'options']).map(x => x.get('title')),
|
||||
options: options,
|
||||
multiple: action.status.getIn(['poll', 'multiple']),
|
||||
expires_in: expiresInFromExpiresAt(action.status.getIn(['poll', 'expires_at'])),
|
||||
}));
|
||||
@@ -639,8 +658,13 @@ export default function compose(state = initialState, action) {
|
||||
}
|
||||
|
||||
if (action.status.get('poll')) {
|
||||
let options = action.status.getIn(['poll', 'options']).map(x => x.get('title'));
|
||||
if (options.size < action.maxOptions) {
|
||||
options = options.push('');
|
||||
}
|
||||
|
||||
map.set('poll', ImmutableMap({
|
||||
options: action.status.getIn(['poll', 'options']).map(x => x.get('title')),
|
||||
options: options,
|
||||
multiple: action.status.getIn(['poll', 'multiple']),
|
||||
expires_in: expiresInFromExpiresAt(action.status.getIn(['poll', 'expires_at'])),
|
||||
}));
|
||||
|
||||
@@ -6,6 +6,7 @@ import { LOCAL_SETTING_CHANGE, LOCAL_SETTING_DELETE } from 'flavours/glitch/acti
|
||||
import { STORE_HYDRATE } from 'flavours/glitch/actions/store';
|
||||
|
||||
const initialState = ImmutableMap({
|
||||
fullwidth_columns: false,
|
||||
stretch : true,
|
||||
side_arm : 'none',
|
||||
side_arm_reply_mode : 'keep',
|
||||
|
||||
@@ -15,9 +15,10 @@ export const makeGetStatus = () => {
|
||||
(state, { id }) => state.getIn(['accounts', state.getIn(['statuses', id, 'account'])]),
|
||||
(state, { id }) => state.getIn(['accounts', state.getIn(['statuses', state.getIn(['statuses', id, 'reblog']), 'account'])]),
|
||||
getFilters,
|
||||
(_, { contextType }) => ['detailed', 'bookmarks', 'favourites'].includes(contextType),
|
||||
],
|
||||
|
||||
(statusBase, statusReblog, accountBase, accountReblog, filters) => {
|
||||
(statusBase, statusReblog, accountBase, accountReblog, filters, warnInsteadOfHide) => {
|
||||
if (!statusBase || statusBase.get('isLoading')) {
|
||||
return null;
|
||||
}
|
||||
@@ -25,7 +26,7 @@ export const makeGetStatus = () => {
|
||||
let filtered = false;
|
||||
if ((accountReblog || accountBase).get('id') !== me && filters) {
|
||||
let filterResults = statusReblog?.get('filtered') || statusBase.get('filtered') || ImmutableList();
|
||||
if (filterResults.some((result) => filters.getIn([result.get('filter'), 'filter_action']) === 'hide')) {
|
||||
if (!warnInsteadOfHide && filterResults.some((result) => filters.getIn([result.get('filter'), 'filter_action']) === 'hide')) {
|
||||
return null;
|
||||
}
|
||||
filterResults = filterResults.filter(result => filters.has(result.get('filter')));
|
||||
|
||||
@@ -817,6 +817,10 @@ body > [data-popper-placement] {
|
||||
flex: 0 1 auto;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
|
||||
.icon {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7473,6 +7477,13 @@ img.modal-warning {
|
||||
}
|
||||
}
|
||||
|
||||
.fullwidth-columns .columns-area:not(.columns-area--mobile) {
|
||||
.column {
|
||||
flex: auto;
|
||||
max-width: unset;
|
||||
}
|
||||
}
|
||||
|
||||
.media-gallery__actions {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
@@ -7640,6 +7651,8 @@ img.modal-warning {
|
||||
}
|
||||
|
||||
&--layout-3 {
|
||||
min-height: calc(64px * 2 + 8px);
|
||||
|
||||
& > .media-gallery__item:nth-child(1) {
|
||||
border-end-end-radius: 0;
|
||||
border-start-end-radius: 0;
|
||||
@@ -7659,6 +7672,8 @@ img.modal-warning {
|
||||
}
|
||||
|
||||
&--layout-4 {
|
||||
min-height: calc(64px * 2 + 8px);
|
||||
|
||||
& > .media-gallery__item:nth-child(1) {
|
||||
border-end-end-radius: 0;
|
||||
border-start-end-radius: 0;
|
||||
|
||||
@@ -668,6 +668,10 @@ code {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.status-card {
|
||||
contain: unset;
|
||||
}
|
||||
}
|
||||
|
||||
.block-icon {
|
||||
|
||||
@@ -84,6 +84,7 @@
|
||||
width: 100%;
|
||||
|
||||
.account {
|
||||
max-width: calc(56px + 30ch);
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,11 @@ export const toServerSideType = (columnType: string) => {
|
||||
case 'thread':
|
||||
case 'account':
|
||||
return columnType;
|
||||
case 'detailed':
|
||||
return 'thread';
|
||||
case 'bookmarks':
|
||||
case 'favourites':
|
||||
return 'home';
|
||||
default:
|
||||
if (columnType.includes('list:')) {
|
||||
return 'home';
|
||||
|
||||
@@ -96,11 +96,16 @@ export const ensureComposeIsVisible = (getState) => {
|
||||
};
|
||||
|
||||
export function setComposeToStatus(status, text, spoiler_text) {
|
||||
return{
|
||||
type: COMPOSE_SET_STATUS,
|
||||
status,
|
||||
text,
|
||||
spoiler_text,
|
||||
return (dispatch, getState) => {
|
||||
const maxOptions = getState().server.getIn(['server', 'configuration', 'polls', 'max_options']);
|
||||
|
||||
dispatch({
|
||||
type: COMPOSE_SET_STATUS,
|
||||
status,
|
||||
text,
|
||||
spoiler_text,
|
||||
maxOptions,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -80,6 +80,17 @@ export function normalizeStatus(status, normalOldStatus) {
|
||||
normalStatus.contentHtml = emojify(normalStatus.content, emojiMap);
|
||||
normalStatus.spoilerHtml = emojify(escapeTextContentForBrowser(spoilerText), emojiMap);
|
||||
normalStatus.hidden = expandSpoilers ? false : spoilerText.length > 0 || normalStatus.sensitive;
|
||||
|
||||
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) {
|
||||
|
||||
@@ -141,6 +141,9 @@ export const pollRecentNotifications = createDataLoadingThunk(
|
||||
|
||||
return { notifications };
|
||||
},
|
||||
{
|
||||
useLoadingBar: false,
|
||||
},
|
||||
);
|
||||
|
||||
export const processNewNotificationForGroups = createAppAsyncThunk(
|
||||
@@ -152,7 +155,7 @@ export const processNewNotificationForGroups = createAppAsyncThunk(
|
||||
|
||||
const showInColumn =
|
||||
activeFilter === 'all'
|
||||
? notificationShows[notification.type]
|
||||
? notificationShows[notification.type] !== false
|
||||
: activeFilter === notification.type;
|
||||
|
||||
if (!showInColumn) return;
|
||||
|
||||
@@ -90,10 +90,15 @@ export function fetchStatusFail(id, error, skipLoading) {
|
||||
}
|
||||
|
||||
export function redraft(status, raw_text) {
|
||||
return {
|
||||
type: REDRAFT,
|
||||
status,
|
||||
raw_text,
|
||||
return (dispatch, getState) => {
|
||||
const maxOptions = getState().server.getIn(['server', 'configuration', 'polls', 'max_options']);
|
||||
|
||||
dispatch({
|
||||
type: REDRAFT,
|
||||
status,
|
||||
raw_text,
|
||||
maxOptions,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { apiRequestPost } from 'mastodon/api';
|
||||
import type { Status, StatusVisibility } from 'mastodon/models/status';
|
||||
import type { ApiStatusJSON } from 'mastodon/api_types/statuses';
|
||||
import type { StatusVisibility } from 'mastodon/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`);
|
||||
|
||||
@@ -37,7 +37,7 @@ export interface BaseApiAccountJSON {
|
||||
roles?: ApiAccountJSON[];
|
||||
statuses_count: number;
|
||||
uri: string;
|
||||
url: string;
|
||||
url?: string;
|
||||
username: string;
|
||||
moved?: ApiAccountJSON;
|
||||
suspended?: boolean;
|
||||
|
||||
@@ -28,6 +28,7 @@ export const AltTextBadge: React.FC<{
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
type='button'
|
||||
ref={anchorRef}
|
||||
className='media-gallery__alt__label'
|
||||
onClick={handleClick}
|
||||
|
||||
@@ -330,7 +330,7 @@ class Status extends ImmutablePureComponent {
|
||||
const { onToggleHidden } = this.props;
|
||||
const status = this._properStatus();
|
||||
|
||||
if (status.get('matched_filters')) {
|
||||
if (this.props.status.get('matched_filters')) {
|
||||
const expandedBecauseOfCW = !status.get('hidden') || status.get('spoiler_text').length === 0;
|
||||
const expandedBecauseOfFilter = this.state.showDespiteFilter;
|
||||
|
||||
@@ -520,7 +520,7 @@ class Status extends ImmutablePureComponent {
|
||||
</Bundle>
|
||||
);
|
||||
}
|
||||
} else if (status.get('spoiler_text').length === 0 && status.get('card')) {
|
||||
} else if (status.get('card')) {
|
||||
media = (
|
||||
<Card
|
||||
onOpenMedia={this.handleOpenMedia}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Provider } from 'react-redux';
|
||||
|
||||
import { fetchCustomEmojis } from 'mastodon/actions/custom_emojis';
|
||||
import { fetchServer } from 'mastodon/actions/server';
|
||||
import { hydrateStore } from 'mastodon/actions/store';
|
||||
import { Router } from 'mastodon/components/router';
|
||||
import Compose from 'mastodon/features/standalone/compose';
|
||||
@@ -13,6 +14,7 @@ if (initialState) {
|
||||
}
|
||||
|
||||
store.dispatch(fetchCustomEmojis());
|
||||
store.dispatch(fetchServer());
|
||||
|
||||
const ComposeContainer = () => (
|
||||
<IntlProvider>
|
||||
|
||||
@@ -99,6 +99,7 @@ class Bookmarks extends ImmutablePureComponent {
|
||||
onLoadMore={this.handleLoadMore}
|
||||
emptyMessage={emptyMessage}
|
||||
bindToDocument={!multiColumn}
|
||||
timelineId='bookmarks'
|
||||
/>
|
||||
|
||||
<Helmet>
|
||||
|
||||
@@ -22,23 +22,23 @@ describe('emoji', () => {
|
||||
|
||||
it('does unicode', () => {
|
||||
expect(emojify('\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66')).toEqual(
|
||||
'<picture><img draggable="false" class="emojione" alt="👩👩👦👦" title=":woman-woman-boy-boy:" src="/emoji/1f469-200d-1f469-200d-1f466-200d-1f466.svg"></picture>');
|
||||
'<img draggable="false" class="emojione" alt="👩👩👦👦" title=":woman-woman-boy-boy:" src="/emoji/1f469-200d-1f469-200d-1f466-200d-1f466.svg">');
|
||||
expect(emojify('👨👩👧👧')).toEqual(
|
||||
'<picture><img draggable="false" class="emojione" alt="👨👩👧👧" title=":man-woman-girl-girl:" src="/emoji/1f468-200d-1f469-200d-1f467-200d-1f467.svg"></picture>');
|
||||
expect(emojify('👩👩👦')).toEqual('<picture><img draggable="false" class="emojione" alt="👩👩👦" title=":woman-woman-boy:" src="/emoji/1f469-200d-1f469-200d-1f466.svg"></picture>');
|
||||
'<img draggable="false" class="emojione" alt="👨👩👧👧" title=":man-woman-girl-girl:" src="/emoji/1f468-200d-1f469-200d-1f467-200d-1f467.svg">');
|
||||
expect(emojify('👩👩👦')).toEqual('<img draggable="false" class="emojione" alt="👩👩👦" title=":woman-woman-boy:" src="/emoji/1f469-200d-1f469-200d-1f466.svg">');
|
||||
expect(emojify('\u2757')).toEqual(
|
||||
'<picture><img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg"></picture>');
|
||||
'<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg">');
|
||||
});
|
||||
|
||||
it('does multiple unicode', () => {
|
||||
expect(emojify('\u2757 #\uFE0F\u20E3')).toEqual(
|
||||
'<picture><img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg"></picture> <picture><img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg"></picture>');
|
||||
'<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg"> <img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg">');
|
||||
expect(emojify('\u2757#\uFE0F\u20E3')).toEqual(
|
||||
'<picture><img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg"></picture><picture><img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg"></picture>');
|
||||
'<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg"><img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg">');
|
||||
expect(emojify('\u2757 #\uFE0F\u20E3 \u2757')).toEqual(
|
||||
'<picture><img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg"></picture> <picture><img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg"></picture> <picture><img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg"></picture>');
|
||||
'<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg"> <img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg"> <img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg">');
|
||||
expect(emojify('foo \u2757 #\uFE0F\u20E3 bar')).toEqual(
|
||||
'foo <picture><img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg"></picture> <picture><img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg"></picture> bar');
|
||||
'foo <img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg"> <img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg"> bar');
|
||||
});
|
||||
|
||||
it('ignores unicode inside of tags', () => {
|
||||
@@ -46,16 +46,16 @@ describe('emoji', () => {
|
||||
});
|
||||
|
||||
it('does multiple emoji properly (issue 5188)', () => {
|
||||
expect(emojify('👌🌈💕')).toEqual('<picture><img draggable="false" class="emojione" alt="👌" title=":ok_hand:" src="/emoji/1f44c.svg"></picture><picture><img draggable="false" class="emojione" alt="🌈" title=":rainbow:" src="/emoji/1f308.svg"></picture><picture><img draggable="false" class="emojione" alt="💕" title=":two_hearts:" src="/emoji/1f495.svg"></picture>');
|
||||
expect(emojify('👌 🌈 💕')).toEqual('<picture><img draggable="false" class="emojione" alt="👌" title=":ok_hand:" src="/emoji/1f44c.svg"></picture> <picture><img draggable="false" class="emojione" alt="🌈" title=":rainbow:" src="/emoji/1f308.svg"></picture> <picture><img draggable="false" class="emojione" alt="💕" title=":two_hearts:" src="/emoji/1f495.svg"></picture>');
|
||||
expect(emojify('👌🌈💕')).toEqual('<img draggable="false" class="emojione" alt="👌" title=":ok_hand:" src="/emoji/1f44c.svg"><img draggable="false" class="emojione" alt="🌈" title=":rainbow:" src="/emoji/1f308.svg"><img draggable="false" class="emojione" alt="💕" title=":two_hearts:" src="/emoji/1f495.svg">');
|
||||
expect(emojify('👌 🌈 💕')).toEqual('<img draggable="false" class="emojione" alt="👌" title=":ok_hand:" src="/emoji/1f44c.svg"> <img draggable="false" class="emojione" alt="🌈" title=":rainbow:" src="/emoji/1f308.svg"> <img draggable="false" class="emojione" alt="💕" title=":two_hearts:" src="/emoji/1f495.svg">');
|
||||
});
|
||||
|
||||
it('does an emoji that has no shortcode', () => {
|
||||
expect(emojify('👁🗨')).toEqual('<picture><img draggable="false" class="emojione" alt="👁🗨" title="" src="/emoji/1f441-200d-1f5e8.svg"></picture>');
|
||||
expect(emojify('👁🗨')).toEqual('<img draggable="false" class="emojione" alt="👁🗨" title="" src="/emoji/1f441-200d-1f5e8.svg">');
|
||||
});
|
||||
|
||||
it('does an emoji whose filename is irregular', () => {
|
||||
expect(emojify('↙️')).toEqual('<picture><img draggable="false" class="emojione" alt="↙️" title=":arrow_lower_left:" src="/emoji/2199.svg"></picture>');
|
||||
expect(emojify('↙️')).toEqual('<img draggable="false" class="emojione" alt="↙️" title=":arrow_lower_left:" src="/emoji/2199.svg">');
|
||||
});
|
||||
|
||||
it('avoid emojifying on invisible text', () => {
|
||||
@@ -67,11 +67,11 @@ describe('emoji', () => {
|
||||
|
||||
it('avoid emojifying on invisible text with nested tags', () => {
|
||||
expect(emojify('<span class="invisible">😄<span class="foo">bar</span>😴</span>😇'))
|
||||
.toEqual('<span class="invisible">😄<span class="foo">bar</span>😴</span><picture><img draggable="false" class="emojione" alt="😇" title=":innocent:" src="/emoji/1f607.svg"></picture>');
|
||||
.toEqual('<span class="invisible">😄<span class="foo">bar</span>😴</span><img draggable="false" class="emojione" alt="😇" title=":innocent:" src="/emoji/1f607.svg">');
|
||||
expect(emojify('<span class="invisible">😄<span class="invisible">😕</span>😴</span>😇'))
|
||||
.toEqual('<span class="invisible">😄<span class="invisible">😕</span>😴</span><picture><img draggable="false" class="emojione" alt="😇" title=":innocent:" src="/emoji/1f607.svg"></picture>');
|
||||
.toEqual('<span class="invisible">😄<span class="invisible">😕</span>😴</span><img draggable="false" class="emojione" alt="😇" title=":innocent:" src="/emoji/1f607.svg">');
|
||||
expect(emojify('<span class="invisible">😄<br>😴</span>😇'))
|
||||
.toEqual('<span class="invisible">😄<br>😴</span><picture><img draggable="false" class="emojione" alt="😇" title=":innocent:" src="/emoji/1f607.svg"></picture>');
|
||||
.toEqual('<span class="invisible">😄<br>😴</span><img draggable="false" class="emojione" alt="😇" title=":innocent:" src="/emoji/1f607.svg">');
|
||||
});
|
||||
|
||||
it('does not emojify emojis with textual presentation VS15 character', () => {
|
||||
@@ -81,17 +81,17 @@ describe('emoji', () => {
|
||||
|
||||
it('does a simple emoji properly', () => {
|
||||
expect(emojify('♀♂'))
|
||||
.toEqual('<picture><img draggable="false" class="emojione" alt="♀" title=":female_sign:" src="/emoji/2640.svg"></picture><picture><img draggable="false" class="emojione" alt="♂" title=":male_sign:" src="/emoji/2642.svg"></picture>');
|
||||
.toEqual('<img draggable="false" class="emojione" alt="♀" title=":female_sign:" src="/emoji/2640.svg"><img draggable="false" class="emojione" alt="♂" title=":male_sign:" src="/emoji/2642.svg">');
|
||||
});
|
||||
|
||||
it('does an emoji containing ZWJ properly', () => {
|
||||
expect(emojify('💂♀️💂♂️'))
|
||||
.toEqual('<picture><img draggable="false" class="emojione" alt="💂\u200D♀️" title=":female-guard:" src="/emoji/1f482-200d-2640-fe0f_border.svg"></picture><picture><img draggable="false" class="emojione" alt="💂\u200D♂️" title=":male-guard:" src="/emoji/1f482-200d-2642-fe0f_border.svg"></picture>');
|
||||
.toEqual('<img draggable="false" class="emojione" alt="💂\u200D♀️" title=":female-guard:" src="/emoji/1f482-200d-2640-fe0f_border.svg"><img draggable="false" class="emojione" alt="💂\u200D♂️" title=":male-guard:" src="/emoji/1f482-200d-2642-fe0f_border.svg">');
|
||||
});
|
||||
|
||||
it('keeps ordering as expected (issue fixed by PR 20677)', () => {
|
||||
expect(emojify('<p>💕 <a class="hashtag" href="https://example.com/tags/foo" rel="nofollow noopener noreferrer" target="_blank">#<span>foo</span></a> test: foo.</p>'))
|
||||
.toEqual('<p><picture><img draggable="false" class="emojione" alt="💕" title=":two_hearts:" src="/emoji/1f495.svg"></picture> <a class="hashtag" href="https://example.com/tags/foo" rel="nofollow noopener noreferrer" target="_blank">#<span>foo</span></a> test: foo.</p>');
|
||||
expect(emojify('<p>💕 <a class="hashtag" href="https://example.com/tags/foo" rel="nofollow noopener" target="_blank">#<span>foo</span></a> test: foo.</p>'))
|
||||
.toEqual('<p><img draggable="false" class="emojione" alt="💕" title=":two_hearts:" src="/emoji/1f495.svg"> <a class="hashtag" href="https://example.com/tags/foo" rel="nofollow noopener" target="_blank">#<span>foo</span></a> test: foo.</p>');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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('theme-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);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user