mirror of
https://github.com/mastodon/mastodon.git
synced 2025-03-25 03:52:18 +01:00
Merge branch 'main' into search-warnings
This commit is contained in:
commit
5577bb5526
697 changed files with 10597 additions and 6201 deletions
|
@ -45,6 +45,17 @@ ES_PASS=password
|
||||||
SECRET_KEY_BASE=
|
SECRET_KEY_BASE=
|
||||||
OTP_SECRET=
|
OTP_SECRET=
|
||||||
|
|
||||||
|
# Encryption secrets
|
||||||
|
# ------------------
|
||||||
|
# Must be available (and set to same values) for all server processes
|
||||||
|
# These are private/secret values, do not share outside hosting environment
|
||||||
|
# Use `bin/rails db:encryption:init` to generate fresh secrets
|
||||||
|
# Do not change these secrets once in use, as this would cause data loss and other issues
|
||||||
|
# ------------------
|
||||||
|
# ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=
|
||||||
|
# ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=
|
||||||
|
# ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=
|
||||||
|
|
||||||
# Web Push
|
# Web Push
|
||||||
# --------
|
# --------
|
||||||
# Generate with `bundle exec rails mastodon:webpush:generate_vapid_key`
|
# Generate with `bundle exec rails mastodon:webpush:generate_vapid_key`
|
||||||
|
|
|
@ -64,7 +64,6 @@ module.exports = defineConfig({
|
||||||
'indent': ['error', 2],
|
'indent': ['error', 2],
|
||||||
'jsx-quotes': ['error', 'prefer-single'],
|
'jsx-quotes': ['error', 'prefer-single'],
|
||||||
'semi': ['error', 'always'],
|
'semi': ['error', 'always'],
|
||||||
'no-case-declarations': 'off',
|
|
||||||
'no-catch-shadow': 'error',
|
'no-catch-shadow': 'error',
|
||||||
'no-console': [
|
'no-console': [
|
||||||
'warn',
|
'warn',
|
||||||
|
|
13
.github/ISSUE_TEMPLATE/1.web_bug_report.yml
vendored
13
.github/ISSUE_TEMPLATE/1.web_bug_report.yml
vendored
|
@ -1,6 +1,7 @@
|
||||||
name: Bug Report (Web Interface)
|
name: Bug Report (Web Interface)
|
||||||
description: If you are using Mastodon's web interface and something is not working as expected
|
description: There is a problem using Mastodon's web interface.
|
||||||
labels: [bug, 'status/to triage', 'area/web interface']
|
labels: ['status/to triage', 'area/web interface']
|
||||||
|
type: Bug
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
|
@ -47,8 +48,8 @@ body:
|
||||||
attributes:
|
attributes:
|
||||||
label: Mastodon version
|
label: Mastodon version
|
||||||
description: |
|
description: |
|
||||||
This is displayed at the bottom of the About page, eg. `v4.1.2+nightly-20230627`
|
This is displayed at the bottom of the About page, eg. `v4.4.0-alpha.1`
|
||||||
placeholder: v4.1.2
|
placeholder: v4.3.0
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: input
|
- type: input
|
||||||
|
@ -56,7 +57,7 @@ body:
|
||||||
label: Browser name and version
|
label: Browser name and version
|
||||||
description: |
|
description: |
|
||||||
What browser are you using when getting this bug? Please specify the version as well.
|
What browser are you using when getting this bug? Please specify the version as well.
|
||||||
placeholder: Firefox 105.0.3
|
placeholder: Firefox 131.0.0
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: input
|
- type: input
|
||||||
|
@ -64,7 +65,7 @@ body:
|
||||||
label: Operating system
|
label: Operating system
|
||||||
description: |
|
description: |
|
||||||
What OS are you running? Please specify the version as well.
|
What OS are you running? Please specify the version as well.
|
||||||
placeholder: macOS 13.4.1
|
placeholder: macOS 15.0.1
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
|
13
.github/ISSUE_TEMPLATE/2.server_bug_report.yml
vendored
13
.github/ISSUE_TEMPLATE/2.server_bug_report.yml
vendored
|
@ -1,7 +1,8 @@
|
||||||
name: Bug Report (server / API)
|
name: Bug Report (server / API)
|
||||||
description: |
|
description: |
|
||||||
If something is not working as expected, but is not from using the web interface.
|
There is a problem with the HTTP server, REST API, ActivityPub interaction, etc.
|
||||||
labels: [bug, 'status/to triage']
|
labels: ['status/to triage']
|
||||||
|
type: 'Bug'
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
|
@ -48,8 +49,8 @@ body:
|
||||||
attributes:
|
attributes:
|
||||||
label: Mastodon version
|
label: Mastodon version
|
||||||
description: |
|
description: |
|
||||||
This is displayed at the bottom of the About page, eg. `v4.1.2+nightly-20230627`
|
This is displayed at the bottom of the About page, eg. `v4.4.0-alpha.1`
|
||||||
placeholder: v4.1.2
|
placeholder: v4.3.0
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
@ -59,7 +60,7 @@ body:
|
||||||
Any additional technical details you may have, like logs or error traces
|
Any additional technical details you may have, like logs or error traces
|
||||||
value: |
|
value: |
|
||||||
If this is happening on your own Mastodon server, please fill out those:
|
If this is happening on your own Mastodon server, please fill out those:
|
||||||
- Ruby version: (from `ruby --version`, eg. v3.1.2)
|
- Ruby version: (from `ruby --version`, eg. v3.3.5)
|
||||||
- Node.js version: (from `node --version`, eg. v18.16.0)
|
- Node.js version: (from `node --version`, eg. v20.18.0)
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
|
|
74
.github/ISSUE_TEMPLATE/3.troubleshooting.yml
vendored
Normal file
74
.github/ISSUE_TEMPLATE/3.troubleshooting.yml
vendored
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
name: Deployment troubleshooting
|
||||||
|
description: |
|
||||||
|
You are a server administrator and you are encountering a technical issue during installation, upgrade or operations of Mastodon.
|
||||||
|
labels: ['status/to triage']
|
||||||
|
type: 'Troubleshooting'
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Make sure that you are submitting a new bug that was not previously reported or already fixed.
|
||||||
|
|
||||||
|
Please use a concise and distinct title for the issue.
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Steps to reproduce the problem
|
||||||
|
description: What were you trying to do?
|
||||||
|
value: |
|
||||||
|
1.
|
||||||
|
2.
|
||||||
|
3.
|
||||||
|
...
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: Expected behaviour
|
||||||
|
description: What should have happened?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: Actual behaviour
|
||||||
|
description: What happened?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Detailed description
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: Mastodon instance
|
||||||
|
description: The address of the Mastodon instance where you experienced the issue
|
||||||
|
placeholder: mastodon.social
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: Mastodon version
|
||||||
|
description: |
|
||||||
|
This is displayed at the bottom of the About page, eg. `v4.4.0-alpha.1`
|
||||||
|
placeholder: v4.3.0
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Environment
|
||||||
|
description: |
|
||||||
|
Details about your environment, like how Mastodon is deployed, if containers are used, version numbers, etc.
|
||||||
|
value: |
|
||||||
|
Please at least include those informations:
|
||||||
|
- Operating system: (eg. Ubuntu 22.04)
|
||||||
|
- Ruby version: (from `ruby --version`, eg. v3.3.5)
|
||||||
|
- Node.js version: (from `node --version`, eg. v20.18.0)
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Technical details
|
||||||
|
description: |
|
||||||
|
Any additional technical details you may have, like logs or error traces
|
||||||
|
validations:
|
||||||
|
required: false
|
|
@ -1,6 +1,6 @@
|
||||||
name: Feature Request
|
name: Feature Request
|
||||||
description: I have a suggestion
|
description: I have a suggestion
|
||||||
labels: [suggestion]
|
type: Suggestion
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
6
.github/workflows/build-push-pr.yml
vendored
6
.github/workflows/build-push-pr.yml
vendored
|
@ -21,9 +21,11 @@ jobs:
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- id: version_vars
|
- id: version_vars
|
||||||
run: |
|
run: |
|
||||||
echo mastodon_version_metadata=pr-${{ github.event.pull_request.number }}-$(git rev-parse --short HEAD) >> $GITHUB_OUTPUT
|
echo mastodon_version_metadata=pr-${{ github.event.pull_request.number }}-$(git rev-parse --short ${{github.event.pull_request.head.sha}}) >> $GITHUB_OUTPUT
|
||||||
|
echo mastodon_short_sha=$(git rev-parse --short ${{github.event.pull_request.head.sha}}) >> $GITHUB_OUTPUT
|
||||||
outputs:
|
outputs:
|
||||||
metadata: ${{ steps.version_vars.outputs.mastodon_version_metadata }}
|
metadata: ${{ steps.version_vars.outputs.mastodon_version_metadata }}
|
||||||
|
short_sha: ${{ steps.version_vars.outputs.mastodon_short_sha }}
|
||||||
|
|
||||||
build-image:
|
build-image:
|
||||||
needs: compute-suffix
|
needs: compute-suffix
|
||||||
|
@ -39,6 +41,7 @@ jobs:
|
||||||
latest=auto
|
latest=auto
|
||||||
tags: |
|
tags: |
|
||||||
type=ref,event=pr
|
type=ref,event=pr
|
||||||
|
type=ref,event=pr,suffix=-${{ needs.compute-suffix.outputs.short_sha }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
build-image-streaming:
|
build-image-streaming:
|
||||||
|
@ -55,4 +58,5 @@ jobs:
|
||||||
latest=auto
|
latest=auto
|
||||||
tags: |
|
tags: |
|
||||||
type=ref,event=pr
|
type=ref,event=pr
|
||||||
|
type=ref,event=pr,suffix=-${{ needs.compute-suffix.outputs.short_sha }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
2
.github/workflows/build-releases.yml
vendored
2
.github/workflows/build-releases.yml
vendored
|
@ -23,7 +23,7 @@ jobs:
|
||||||
# Only tag with latest when ran against the latest stable branch
|
# Only tag with latest when ran against the latest stable branch
|
||||||
# This needs to be updated after each minor version release
|
# This needs to be updated after each minor version release
|
||||||
flavor: |
|
flavor: |
|
||||||
latest=${{ startsWith(github.ref, 'refs/tags/v4.2.') }}
|
latest=${{ startsWith(github.ref, 'refs/tags/v4.3.') }}
|
||||||
tags: |
|
tags: |
|
||||||
type=pep440,pattern={{raw}}
|
type=pep440,pattern={{raw}}
|
||||||
type=pep440,pattern=v{{major}}.{{minor}}
|
type=pep440,pattern=v{{major}}.{{minor}}
|
||||||
|
|
2
.github/workflows/check-i18n.yml
vendored
2
.github/workflows/check-i18n.yml
vendored
|
@ -18,7 +18,7 @@ permissions:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check-i18n:
|
check-i18n:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-24.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
69
.github/workflows/crowdin-download-stable.yml
vendored
Normal file
69
.github/workflows/crowdin-download-stable.yml
vendored
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
name: Crowdin / Download translations (stable branches)
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
download-translations-stable:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.repository == 'mastodon/mastodon'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Increase Git http.postBuffer
|
||||||
|
# This is needed due to a bug in Ubuntu's cURL version?
|
||||||
|
# See https://github.com/orgs/community/discussions/55820
|
||||||
|
run: |
|
||||||
|
git config --global http.version HTTP/1.1
|
||||||
|
git config --global http.postBuffer 157286400
|
||||||
|
|
||||||
|
# Download the translation files from Crowdin
|
||||||
|
- name: crowdin action
|
||||||
|
uses: crowdin/github-action@v2
|
||||||
|
with:
|
||||||
|
upload_sources: false
|
||||||
|
upload_translations: false
|
||||||
|
download_translations: true
|
||||||
|
crowdin_branch_name: ${{ github.base_ref || github.ref_name }}
|
||||||
|
push_translations: false
|
||||||
|
create_pull_request: false
|
||||||
|
env:
|
||||||
|
CROWDIN_PROJECT_ID: ${{ vars.CROWDIN_PROJECT_ID }}
|
||||||
|
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
|
||||||
|
|
||||||
|
# As the files are extracted from a Docker container, they belong to root:root
|
||||||
|
# We need to fix this before the next steps
|
||||||
|
- name: Fix file permissions
|
||||||
|
run: sudo chown -R runner:docker .
|
||||||
|
|
||||||
|
# This is needed to run the normalize step
|
||||||
|
- name: Set up Ruby environment
|
||||||
|
uses: ./.github/actions/setup-ruby
|
||||||
|
|
||||||
|
- name: Run i18n normalize task
|
||||||
|
run: bundle exec i18n-tasks normalize
|
||||||
|
|
||||||
|
# Create or update the pull request
|
||||||
|
- name: Create Pull Request
|
||||||
|
uses: peter-evans/create-pull-request@v7.0.5
|
||||||
|
with:
|
||||||
|
commit-message: 'New Crowdin translations'
|
||||||
|
title: 'New Crowdin Translations for ${{ github.base_ref || github.ref_name }} (automated)'
|
||||||
|
author: 'GitHub Actions <noreply@github.com>'
|
||||||
|
body: |
|
||||||
|
New Crowdin translations, automated with GitHub Actions
|
||||||
|
|
||||||
|
See `.github/workflows/crowdin-download.yml`
|
||||||
|
|
||||||
|
This PR will be updated every day with new translations.
|
||||||
|
|
||||||
|
Due to a limitation in GitHub Actions, checks are not running on this PR without manual action.
|
||||||
|
If you want to run the checks, then close and re-open it.
|
||||||
|
branch: i18n/crowdin/translations-${{ github.base_ref || github.ref_name }}
|
||||||
|
base: ${{ github.base_ref || github.ref_name }}
|
||||||
|
labels: i18n
|
2
.github/workflows/crowdin-download.yml
vendored
2
.github/workflows/crowdin-download.yml
vendored
|
@ -52,7 +52,7 @@ jobs:
|
||||||
|
|
||||||
# Create or update the pull request
|
# Create or update the pull request
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
uses: peter-evans/create-pull-request@v7.0.1
|
uses: peter-evans/create-pull-request@v7.0.5
|
||||||
with:
|
with:
|
||||||
commit-message: 'New Crowdin translations'
|
commit-message: 'New Crowdin translations'
|
||||||
title: 'New Crowdin Translations (automated)'
|
title: 'New Crowdin Translations (automated)'
|
||||||
|
|
3
.github/workflows/crowdin-upload.yml
vendored
3
.github/workflows/crowdin-upload.yml
vendored
|
@ -1,7 +1,6 @@
|
||||||
name: Crowdin / Upload translations
|
name: Crowdin / Upload translations
|
||||||
|
|
||||||
on:
|
on:
|
||||||
merge_group:
|
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- 'main'
|
- 'main'
|
||||||
|
@ -31,7 +30,7 @@ jobs:
|
||||||
upload_sources: true
|
upload_sources: true
|
||||||
upload_translations: false
|
upload_translations: false
|
||||||
download_translations: false
|
download_translations: false
|
||||||
crowdin_branch_name: main
|
crowdin_branch_name: ${{ github.base_ref || github.ref_name }}
|
||||||
|
|
||||||
env:
|
env:
|
||||||
CROWDIN_PROJECT_ID: ${{ vars.CROWDIN_PROJECT_ID }}
|
CROWDIN_PROJECT_ID: ${{ vars.CROWDIN_PROJECT_ID }}
|
||||||
|
|
2
.github/workflows/test-migrations.yml
vendored
2
.github/workflows/test-migrations.yml
vendored
|
@ -32,6 +32,8 @@ jobs:
|
||||||
postgres:
|
postgres:
|
||||||
- 14-alpine
|
- 14-alpine
|
||||||
- 15-alpine
|
- 15-alpine
|
||||||
|
- 16-alpine
|
||||||
|
- 17-alpine
|
||||||
|
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
|
|
12
.github/workflows/test-ruby.yml
vendored
12
.github/workflows/test-ruby.yml
vendored
|
@ -124,7 +124,6 @@ jobs:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
ruby-version:
|
ruby-version:
|
||||||
- '3.1'
|
|
||||||
- '3.2'
|
- '3.2'
|
||||||
- '.ruby-version'
|
- '.ruby-version'
|
||||||
steps:
|
steps:
|
||||||
|
@ -143,7 +142,7 @@ jobs:
|
||||||
uses: ./.github/actions/setup-ruby
|
uses: ./.github/actions/setup-ruby
|
||||||
with:
|
with:
|
||||||
ruby-version: ${{ matrix.ruby-version}}
|
ruby-version: ${{ matrix.ruby-version}}
|
||||||
additional-system-dependencies: ffmpeg libpam-dev
|
additional-system-dependencies: ffmpeg imagemagick libpam-dev
|
||||||
|
|
||||||
- name: Load database schema
|
- name: Load database schema
|
||||||
run: |
|
run: |
|
||||||
|
@ -226,7 +225,6 @@ jobs:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
ruby-version:
|
ruby-version:
|
||||||
- '3.1'
|
|
||||||
- '3.2'
|
- '3.2'
|
||||||
- '.ruby-version'
|
- '.ruby-version'
|
||||||
steps:
|
steps:
|
||||||
|
@ -245,7 +243,7 @@ jobs:
|
||||||
uses: ./.github/actions/setup-ruby
|
uses: ./.github/actions/setup-ruby
|
||||||
with:
|
with:
|
||||||
ruby-version: ${{ matrix.ruby-version}}
|
ruby-version: ${{ matrix.ruby-version}}
|
||||||
additional-system-dependencies: ffmpeg libpam-dev libyaml-dev
|
additional-system-dependencies: ffmpeg libpam-dev
|
||||||
|
|
||||||
- name: Load database schema
|
- name: Load database schema
|
||||||
run: './bin/rails db:create db:schema:load db:seed'
|
run: './bin/rails db:create db:schema:load db:seed'
|
||||||
|
@ -305,7 +303,6 @@ jobs:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
ruby-version:
|
ruby-version:
|
||||||
- '3.1'
|
|
||||||
- '3.2'
|
- '3.2'
|
||||||
- '.ruby-version'
|
- '.ruby-version'
|
||||||
|
|
||||||
|
@ -325,7 +322,7 @@ jobs:
|
||||||
uses: ./.github/actions/setup-ruby
|
uses: ./.github/actions/setup-ruby
|
||||||
with:
|
with:
|
||||||
ruby-version: ${{ matrix.ruby-version}}
|
ruby-version: ${{ matrix.ruby-version}}
|
||||||
additional-system-dependencies: ffmpeg
|
additional-system-dependencies: ffmpeg imagemagick
|
||||||
|
|
||||||
- name: Set up Javascript environment
|
- name: Set up Javascript environment
|
||||||
uses: ./.github/actions/setup-javascript
|
uses: ./.github/actions/setup-javascript
|
||||||
|
@ -422,7 +419,6 @@ jobs:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
ruby-version:
|
ruby-version:
|
||||||
- '3.1'
|
|
||||||
- '3.2'
|
- '3.2'
|
||||||
- '.ruby-version'
|
- '.ruby-version'
|
||||||
search-image:
|
search-image:
|
||||||
|
@ -445,7 +441,7 @@ jobs:
|
||||||
uses: ./.github/actions/setup-ruby
|
uses: ./.github/actions/setup-ruby
|
||||||
with:
|
with:
|
||||||
ruby-version: ${{ matrix.ruby-version}}
|
ruby-version: ${{ matrix.ruby-version}}
|
||||||
additional-system-dependencies: ffmpeg
|
additional-system-dependencies: ffmpeg imagemagick
|
||||||
|
|
||||||
- name: Set up Javascript environment
|
- name: Set up Javascript environment
|
||||||
uses: ./.github/actions/setup-javascript
|
uses: ./.github/actions/setup-javascript
|
||||||
|
|
2
.nvmrc
2
.nvmrc
|
@ -1 +1 @@
|
||||||
20.17
|
22.11
|
||||||
|
|
|
@ -8,7 +8,7 @@ AllCops:
|
||||||
- lib/mastodon/migration_helpers.rb
|
- lib/mastodon/migration_helpers.rb
|
||||||
ExtraDetails: true
|
ExtraDetails: true
|
||||||
NewCops: enable
|
NewCops: enable
|
||||||
TargetRubyVersion: 3.1 # Oldest supported ruby version
|
TargetRubyVersion: 3.2 # Oldest supported ruby version
|
||||||
|
|
||||||
inherit_from:
|
inherit_from:
|
||||||
- .rubocop/layout.yml
|
- .rubocop/layout.yml
|
||||||
|
|
64
CHANGELOG.md
64
CHANGELOG.md
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
## [4.3.0] - UNRELEASED
|
## [4.3.0] - 2024-10-08
|
||||||
|
|
||||||
The following changelog entries focus on changes visible to users, administrators, client developers or federated software developers, but there has also been a lot of code modernization, refactoring, and tooling work, in particular by @mjankowski.
|
The following changelog entries focus on changes visible to users, administrators, client developers or federated software developers, but there has also been a lot of code modernization, refactoring, and tooling work, in particular by @mjankowski.
|
||||||
|
|
||||||
|
@ -10,12 +10,13 @@ The following changelog entries focus on changes visible to users, administrator
|
||||||
|
|
||||||
- **Add confirmation interstitial instead of silently redirecting logged-out visitors to remote resources** (#27792, #28902, and #30651 by @ClearlyClaire and @Gargron)\
|
- **Add confirmation interstitial instead of silently redirecting logged-out visitors to remote resources** (#27792, #28902, and #30651 by @ClearlyClaire and @Gargron)\
|
||||||
This fixes a longstanding open redirect in Mastodon, at the cost of added friction when local links to remote resources are shared.
|
This fixes a longstanding open redirect in Mastodon, at the cost of added friction when local links to remote resources are shared.
|
||||||
- Change `form-action` Content-Security-Policy directive to be more restrictive (#26897 by @ClearlyClaire)
|
- Fix ReDoS vulnerability on some Ruby versions ([GHSA-jpxp-r43f-rhvx](https://github.com/mastodon/mastodon/security/advisories/GHSA-jpxp-r43f-rhvx))
|
||||||
|
- Change `form-action` Content-Security-Policy directive to be more restrictive (#26897 and #32241 by @ClearlyClaire)
|
||||||
- Update dependencies
|
- Update dependencies
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- **Add server-side notification grouping** (#29889, #30576, #30685, #30688, #30707, #30776, #30779, #30781, #30440, #31062, #31098, #31076, #31111, #31123, #31223, #31214, #31224, #31299, #31325, #31347, #31304, #31326, #31384, #31403, #31433, #31509, #31486, #31513, #31592, #31594, #31638, #31746, #31652, #31709, #31725, #31745, #31613, #31657, #31840, #31610 and #31929 by @ClearlyClaire, @Gargron, @mgmn, and @renchap)\
|
- **Add server-side notification grouping** (#29889, #30576, #30685, #30688, #30707, #30776, #30779, #30781, #30440, #31062, #31098, #31076, #31111, #31123, #31223, #31214, #31224, #31299, #31325, #31347, #31304, #31326, #31384, #31403, #31433, #31509, #31486, #31513, #31592, #31594, #31638, #31746, #31652, #31709, #31725, #31745, #31613, #31657, #31840, #31610, #31929, #32089, #32085, #32243, #32179 and #32254 by @ClearlyClaire, @Gargron, @mgmn, and @renchap)\
|
||||||
Group notifications of the same type for the same target, so that your notifications no longer get cluttered by boost and favorite notifications as soon as a couple of your posts get traction.\
|
Group notifications of the same type for the same target, so that your notifications no longer get cluttered by boost and favorite notifications as soon as a couple of your posts get traction.\
|
||||||
This is done server-side so that clients can efficiently get relevant groups without having to go through numerous pages of individual notifications.\
|
This is done server-side so that clients can efficiently get relevant groups without having to go through numerous pages of individual notifications.\
|
||||||
As part of this, the visual design of the entire notifications feature has been revamped.\
|
As part of this, the visual design of the entire notifications feature has been revamped.\
|
||||||
|
@ -27,7 +28,7 @@ The following changelog entries focus on changes visible to users, administrator
|
||||||
- `GET /api/v2/notifications/:group_key/accounts`: https://docs.joinmastodon.org/methods/grouped_notifications/#get-group-accounts
|
- `GET /api/v2/notifications/:group_key/accounts`: https://docs.joinmastodon.org/methods/grouped_notifications/#get-group-accounts
|
||||||
- `POST /api/v2/notifications/:group_key/dimsiss`: https://docs.joinmastodon.org/methods/grouped_notifications/#dismiss-group
|
- `POST /api/v2/notifications/:group_key/dimsiss`: https://docs.joinmastodon.org/methods/grouped_notifications/#dismiss-group
|
||||||
- `GET /api/v2/notifications/:unread_count`: https://docs.joinmastodon.org/methods/grouped_notifications/#unread-group-count
|
- `GET /api/v2/notifications/:unread_count`: https://docs.joinmastodon.org/methods/grouped_notifications/#unread-group-count
|
||||||
- **Add notification policies, filtered notifications and notification requests** (#29366, #29529, #29433, #29565, #29567, #29572, #29575, #29588, #29646, #29652, #29658, #29666, #29693, #29699, #29737, #29706, #29570, #29752, #29810, #29826, #30114, #30251, #30559, #29868, #31008, #31011, #30996, #31149, #31220, #31222, #31225, #31242, #31262, #31250, #31273, #31310, #31316, #31322, #31329, #31324, #31331, #31343, #31342, #31309, #31358, #31378, #31406, #31256, #31456, #31419, #31457, #31508, #31540, #31541, and #31723 by @ClearlyClaire, @Gargron, @TheEssem, @mgmn, @oneiros, and @renchap)\
|
- **Add notification policies, filtered notifications and notification requests** (#29366, #29529, #29433, #29565, #29567, #29572, #29575, #29588, #29646, #29652, #29658, #29666, #29693, #29699, #29737, #29706, #29570, #29752, #29810, #29826, #30114, #30251, #30559, #29868, #31008, #31011, #30996, #31149, #31220, #31222, #31225, #31242, #31262, #31250, #31273, #31310, #31316, #31322, #31329, #31324, #31331, #31343, #31342, #31309, #31358, #31378, #31406, #31256, #31456, #31419, #31457, #31508, #31540, #31541, #31723, #32062 and #32281 by @ClearlyClaire, @Gargron, @TheEssem, @mgmn, @oneiros, and @renchap)\
|
||||||
The old “Block notifications from non-followers”, “Block notifications from people you don't follow” and “Block direct messages from people you don't follow” notification settings have been replaced by a new set of settings found directly in the notification column.\
|
The old “Block notifications from non-followers”, “Block notifications from people you don't follow” and “Block direct messages from people you don't follow” notification settings have been replaced by a new set of settings found directly in the notification column.\
|
||||||
You can now separately filter or drop notifications from people you don't follow, people who don't follow you, accounts created within the past 30 days, as well as unsolicited private mentions, and accounts limited by the moderation.\
|
You can now separately filter or drop notifications from people you don't follow, people who don't follow you, accounts created within the past 30 days, as well as unsolicited private mentions, and accounts limited by the moderation.\
|
||||||
Instead of being outright dropped, notifications that you chose to filter are put in a separate “Filtered notifications” box that you can review separately without it clogging your main notifications.\
|
Instead of being outright dropped, notifications that you chose to filter are put in a separate “Filtered notifications” box that you can review separately without it clogging your main notifications.\
|
||||||
|
@ -60,13 +61,13 @@ The following changelog entries focus on changes visible to users, administrator
|
||||||
- **Add timeline of public posts about a trending link** (#30381 and #30840 by @Gargron)\
|
- **Add timeline of public posts about a trending link** (#30381 and #30840 by @Gargron)\
|
||||||
You can now see public posts mentioning currently-trending articles from people who have opted into discovery features.\
|
You can now see public posts mentioning currently-trending articles from people who have opted into discovery features.\
|
||||||
This adds a new REST API endpoint: https://docs.joinmastodon.org/methods/timelines/#link
|
This adds a new REST API endpoint: https://docs.joinmastodon.org/methods/timelines/#link
|
||||||
- **Add author highlight for news articles whose authors are on the fediverse** (#30398, #30670, #30521, #30846, #31819, and #31900 by @Gargron and @oneiros)\
|
- **Add author highlight for news articles whose authors are on the fediverse** (#30398, #30670, #30521, #30846, #31819, #31900 and #32188 by @Gargron, @mjankowski and @oneiros)\
|
||||||
This adds a mechanism to [highlight the author of news articles](https://blog.joinmastodon.org/2024/07/highlighting-journalism-on-mastodon/) shared on Mastodon.\
|
This adds a mechanism to [highlight the author of news articles](https://blog.joinmastodon.org/2024/07/highlighting-journalism-on-mastodon/) shared on Mastodon.\
|
||||||
Articles hosted outside the fediverse can indicate a fediverse author with a meta tag:
|
Articles hosted outside the fediverse can indicate a fediverse author with a meta tag:
|
||||||
```html
|
```html
|
||||||
<meta name="fediverse:creator" content="username@domain" />
|
<meta name="fediverse:creator" content="username@domain" />
|
||||||
```
|
```
|
||||||
On the API side, this is represented by a new `authors` attribute to the `PreviewCard` entity: https://docs.joinmastodon.org/entities/PreviewCard/#authors\
|
On the API side, this is represented by a new `authors` attribute to the `PreviewCard` entity: https://docs.joinmastodon.org/entities/PreviewCard/#authors \
|
||||||
Users can allow arbitrary domains to use `fediverse:creator` to credit them by visiting `/settings/verification`.\
|
Users can allow arbitrary domains to use `fediverse:creator` to credit them by visiting `/settings/verification`.\
|
||||||
This is federated as a new `attributionDomains` property in the `http://joinmastodon.org/ns` namespace, containing an array of domain names: https://docs.joinmastodon.org/spec/activitypub/#properties-used-1
|
This is federated as a new `attributionDomains` property in the `http://joinmastodon.org/ns` namespace, containing an array of domain names: https://docs.joinmastodon.org/spec/activitypub/#properties-used-1
|
||||||
- **Add in-app notifications for moderation actions and warnings** (#30065, #30082, and #30081 by @ClearlyClaire)\
|
- **Add in-app notifications for moderation actions and warnings** (#30065, #30082, and #30081 by @ClearlyClaire)\
|
||||||
|
@ -76,7 +77,11 @@ The following changelog entries focus on changes visible to users, administrator
|
||||||
Clicking the domain of a user in their profile will now open a tooltip with a short explanation about servers and federation.
|
Clicking the domain of a user in their profile will now open a tooltip with a short explanation about servers and federation.
|
||||||
- **Add support for Redis sentinel** (#31694, #31623, #31744, #31767, and #31768 by @ThisIsMissEm and @oneiros)\
|
- **Add support for Redis sentinel** (#31694, #31623, #31744, #31767, and #31768 by @ThisIsMissEm and @oneiros)\
|
||||||
See https://docs.joinmastodon.org/admin/scaling/#redis-sentinel
|
See https://docs.joinmastodon.org/admin/scaling/#redis-sentinel
|
||||||
- Add ability to reorder uploaded media before posting in web UI (#28456 by @Gargron)
|
- **Add ability to reorder uploaded media before posting in web UI** (#28456 and #32093 by @Gargron)
|
||||||
|
- Add “A Mastodon update is available.” message on admin dashboard for non-bugfix updates (#32106 by @ClearlyClaire)
|
||||||
|
- Add ability to view alt text by clicking the ALT badge in web UI (#32058 by @Gargron)
|
||||||
|
- Add preview of followers removed in domain block modal in web UI (#32032 and #32105 by @ClearlyClaire and @Gargron)
|
||||||
|
- Add reblogs and favourites counts to statuses in ActivityPub (#32007 by @Gargron)
|
||||||
- Add moderation interface for searching hashtags (#30880 by @ThisIsMissEm)
|
- Add moderation interface for searching hashtags (#30880 by @ThisIsMissEm)
|
||||||
- Add ability for admins to configure instance favicon and logo (#30040, #30208, #30259, #30375, #30734, #31016, and #30205 by @ClearlyClaire, @FawazFarid, @JasonPunyon, @mgmn, and @renchap)\
|
- Add ability for admins to configure instance favicon and logo (#30040, #30208, #30259, #30375, #30734, #31016, and #30205 by @ClearlyClaire, @FawazFarid, @JasonPunyon, @mgmn, and @renchap)\
|
||||||
This is also exposed through the REST API: https://docs.joinmastodon.org/entities/Instance/#icon
|
This is also exposed through the REST API: https://docs.joinmastodon.org/entities/Instance/#icon
|
||||||
|
@ -122,14 +127,14 @@ The following changelog entries focus on changes visible to users, administrator
|
||||||
- Add Interlingue and Interlingua to interface languages (#28630 and #30828 by @Dhghomon and @renchap)
|
- Add Interlingue and Interlingua to interface languages (#28630 and #30828 by @Dhghomon and @renchap)
|
||||||
- Add Kashubian, Pennsylvania Dutch, Vai, Jawi Malay, Mohawk and Low German to posting languages (#26024, #26634, #27136, #29098, #27115, and #27434 by @EngineerDali, @HelgeKrueger, and @gunchleoc)
|
- Add Kashubian, Pennsylvania Dutch, Vai, Jawi Malay, Mohawk and Low German to posting languages (#26024, #26634, #27136, #29098, #27115, and #27434 by @EngineerDali, @HelgeKrueger, and @gunchleoc)
|
||||||
- Add option to use native Ruby driver for Redis through `REDIS_DRIVER=ruby` (#30717 by @vmstan)
|
- Add option to use native Ruby driver for Redis through `REDIS_DRIVER=ruby` (#30717 by @vmstan)
|
||||||
- Add support for libvips in addition to ImageMagick (#30090, #30590, #30597, #30632, #30857, #30869, and #30858 by @ClearlyClaire, @Gargron, and @mjankowski)\
|
- Add support for libvips in addition to ImageMagick (#30090, #30590, #30597, #30632, #30857, #30869, #30858 and #32104 by @ClearlyClaire, @Gargron, and @mjankowski)\
|
||||||
Server admins can now use libvips as a faster and lighter alternative to ImageMagick for processing user-uploaded images.\
|
Server admins can now use libvips as a faster and lighter alternative to ImageMagick for processing user-uploaded images.\
|
||||||
This requires libvips 8.13 or newer, and needs to be enabled with `MASTODON_USE_LIBVIPS=true`.\
|
This requires libvips 8.13 or newer, and needs to be enabled with `MASTODON_USE_LIBVIPS=true`.\
|
||||||
This is enabled by default in the official Docker images, and is intended to completely replace ImageMagick in the future.
|
This is enabled by default in the official Docker images, and is intended to completely replace ImageMagick in the future.
|
||||||
- Add validations to `Web::PushSubscription` (#30540 and #30542 by @ThisIsMissEm)
|
- Add validations to `Web::PushSubscription` (#30540 and #30542 by @ThisIsMissEm)
|
||||||
- Add anchors to each authorized application in `/oauth/authorized_applications` (#31677 by @fowl2)
|
- Add anchors to each authorized application in `/oauth/authorized_applications` (#31677 by @fowl2)
|
||||||
- Add active animation to header settings button (#30221, #30307, and #30388 by @daudix)
|
- Add active animation to header settings button (#30221, #30307, and #30388 by @daudix)
|
||||||
- Add OpenTelemetry instrumentation (#30130, #30322, #30353, and #30350 by @julianocosta89, @renchap, and @robbkidd)\
|
- Add OpenTelemetry instrumentation (#30130, #30322, #30353, #30350 and #31998 by @julianocosta89, @renchap, @robbkidd and @timetinytim)\
|
||||||
See https://docs.joinmastodon.org/admin/config/#otel for documentation
|
See https://docs.joinmastodon.org/admin/config/#otel for documentation
|
||||||
- Add API to get multiple accounts and statuses (#27871 and #30465 by @ClearlyClaire)\
|
- Add API to get multiple accounts and statuses (#27871 and #30465 by @ClearlyClaire)\
|
||||||
This adds `GET /api/v1/accounts` and `GET /api/v1/statuses` to the REST API, see https://docs.joinmastodon.org/methods/accounts/#index and https://docs.joinmastodon.org/methods/statuses/#index
|
This adds `GET /api/v1/accounts` and `GET /api/v1/statuses` to the REST API, see https://docs.joinmastodon.org/methods/accounts/#index and https://docs.joinmastodon.org/methods/statuses/#index
|
||||||
|
@ -138,7 +143,6 @@ The following changelog entries focus on changes visible to users, administrator
|
||||||
- Add RFC8414 OAuth 2.0 server metadata (#29191 by @ThisIsMissEm)
|
- Add RFC8414 OAuth 2.0 server metadata (#29191 by @ThisIsMissEm)
|
||||||
- Add loading indicator and empty result message to advanced interface search (#30085 by @ClearlyClaire)
|
- Add loading indicator and empty result message to advanced interface search (#30085 by @ClearlyClaire)
|
||||||
- Add `profile` OAuth 2.0 scope, allowing more limited access to user data (#29087 and #30357 by @ThisIsMissEm)
|
- Add `profile` OAuth 2.0 scope, allowing more limited access to user data (#29087 and #30357 by @ThisIsMissEm)
|
||||||
- Add global Regexp timeout (#31928 by @ClearlyClaire)
|
|
||||||
- Add the role ID to the badge component (#29707 by @renchap)
|
- Add the role ID to the badge component (#29707 by @renchap)
|
||||||
- Add diagnostic message for failure during CLI search deploy (#29462 by @mjankowski)
|
- Add diagnostic message for failure during CLI search deploy (#29462 by @mjankowski)
|
||||||
- Add pagination `Link` headers on API accounts/statuses when pinned true (#29442 by @mjankowski)
|
- Add pagination `Link` headers on API accounts/statuses when pinned true (#29442 by @mjankowski)
|
||||||
|
@ -146,10 +150,12 @@ The following changelog entries focus on changes visible to users, administrator
|
||||||
- Add groundwork for annual reports for accounts (#28693 by @Gargron)\
|
- Add groundwork for annual reports for accounts (#28693 by @Gargron)\
|
||||||
This lays the groundwork for a “year-in-review”/“wrapped” style report for local users, but is currently not in use.
|
This lays the groundwork for a “year-in-review”/“wrapped” style report for local users, but is currently not in use.
|
||||||
- Add notification email on invalid second authenticator (#28822 by @ClearlyClaire)
|
- Add notification email on invalid second authenticator (#28822 by @ClearlyClaire)
|
||||||
|
- Add date of account deletion in list of accounts in the admin interface (#25640 by @tribela)
|
||||||
- Add new emojis from `jdecked/twemoji` 15.0 (#28404 by @TheEssem)
|
- Add new emojis from `jdecked/twemoji` 15.0 (#28404 by @TheEssem)
|
||||||
- Add configurable error handling in attachment batch deletion (#28184 by @vmstan)\
|
- Add configurable error handling in attachment batch deletion (#28184 by @vmstan)\
|
||||||
This makes the S3 batch size configurable through the `S3_BATCH_DELETE_LIMIT` environment variable (defaults to 1000), and adds some retry logic, configurable through the `S3_BATCH_DELETE_RETRY` environment variable (defaults to 3).
|
This makes the S3 batch size configurable through the `S3_BATCH_DELETE_LIMIT` environment variable (defaults to 1000), and adds some retry logic, configurable through the `S3_BATCH_DELETE_RETRY` environment variable (defaults to 3).
|
||||||
- Add VAPID public key to instance serializer (#28006 by @ThisIsMissEm)
|
- Add VAPID public key to instance serializer (#28006 by @ThisIsMissEm)
|
||||||
|
- Add support for serving JRD `/.well-known/host-meta.json` in addition to XRD host-meta (#32206 by @c960657)
|
||||||
- Add `nodeName` and `nodeDescription` to nodeinfo `metadata` (#28079 by @6543)
|
- Add `nodeName` and `nodeDescription` to nodeinfo `metadata` (#28079 by @6543)
|
||||||
- Add Thai diacritics and tone marks in `HASHTAG_INVALID_CHARS_RE` (#26576 by @ppnplus)
|
- Add Thai diacritics and tone marks in `HASHTAG_INVALID_CHARS_RE` (#26576 by @ppnplus)
|
||||||
- Add variable delay before link verification of remote account links (#27774 by @ClearlyClaire)
|
- Add variable delay before link verification of remote account links (#27774 by @ClearlyClaire)
|
||||||
|
@ -164,18 +170,18 @@ The following changelog entries focus on changes visible to users, administrator
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- **Change icons throughout the web interface** (#27385, #27539, #27555, #27579, #27700, #27817, #28519, #28709, #28064, #28775, #28780, #27924, #29294, #29395, #29537, #29569, #29610, #29612, #29649, #29844, #27780, #30974, #30963, #30962, #30961, #31362, #31363, #31359, #31371, #31360, #31512, #31511, and #31525 by @ClearlyClaire, @Gargron, @arbolitoloco1, @mjankowski, @nclm, @renchap, @ronilaukkarinen, and @zunda)\
|
- **Change icons throughout the web interface** (#27385, #27539, #27555, #27579, #27700, #27817, #28519, #28709, #28064, #28775, #28780, #27924, #29294, #29395, #29537, #29569, #29610, #29612, #29649, #29844, #27780, #30974, #30963, #30962, #30961, #31362, #31363, #31359, #31371, #31360, #31512, #31511, #31525, #32153, and #32201 by @ClearlyClaire, @Gargron, @arbolitoloco1, @mjankowski, @nclm, @renchap, @ronilaukkarinen, and @zunda)\
|
||||||
This changes all the interface icons from FontAwesome to Material Symbols for a more modern look, consistent with the official Mastodon Android app.\
|
This changes all the interface icons from FontAwesome to Material Symbols for a more modern look, consistent with the official Mastodon Android app.\
|
||||||
In addition, better care is given to pixel alignment, and icon variants are used to better highlight active/inactive state.
|
In addition, better care is given to pixel alignment, and icon variants are used to better highlight active/inactive state.
|
||||||
- **Change design of compose form in web UI** (#28119, #29059, #29248, #29372, #29384, #29417, #29456, #29406, #29651, #29659, and #31889 by @ClearlyClaire, @Gargron, @eai04191, @hinaloe, and @ronilaukkarinen)\
|
- **Change design of compose form in web UI** (#28119, #29059, #29248, #29372, #29384, #29417, #29456, #29406, #29651, #29659, #31889 and #32033 by @ClearlyClaire, @Gargron, @eai04191, @hinaloe, and @ronilaukkarinen)\
|
||||||
The compose form has been completely redesigned for a more modern and consistent look, as well as spelling out the chosen privacy setting and language name at all times.\
|
The compose form has been completely redesigned for a more modern and consistent look, as well as spelling out the chosen privacy setting and language name at all times.\
|
||||||
As part of this, the “Unlisted” privacy setting has been renamed to “Quiet public”.
|
As part of this, the “Unlisted” privacy setting has been renamed to “Quiet public”.
|
||||||
- **Change design of modals in the web UI** (#29576, #29614, #29640, #29644, #30131, #30884, #31399, #31555, #31752, #31801, #31883, #31844, #31864, and #31943 by @ClearlyClaire, @Gargron, @tribela and @vmstan)\
|
- **Change design of modals in the web UI** (#29576, #29614, #29640, #29644, #30131, #30884, #31399, #31555, #31752, #31801, #31883, #31844, #31864, and #31943 by @ClearlyClaire, @Gargron, @tribela and @vmstan)\
|
||||||
The mute, block, and domain block confirmation modals have been completely redesigned to be clearer and include more detailed information on the action to be performed.\
|
The mute, block, and domain block confirmation modals have been completely redesigned to be clearer and include more detailed information on the action to be performed.\
|
||||||
They also have a more modern and consistent design, along with other confirmation modals in the application.
|
They also have a more modern and consistent design, along with other confirmation modals in the application.
|
||||||
- **Change colors throughout the web UI** (#29522, #29584, #29653, #29779, #29803, #29809, #29808, #29828, #31034, #31168, #31266, #31348, #31349, #31361, and #31510 by @ClearlyClaire, @Gargron, @renchap, and @vmstan)
|
- **Change colors throughout the web UI** (#29522, #29584, #29653, #29779, #29803, #29809, #29808, #29828, #31034, #31168, #31266, #31348, #31349, #31361, #31510 and #32128 by @ClearlyClaire, @Gargron, @mjankowski, @renchap, and @vmstan)
|
||||||
- **Change onboarding prompt to follow suggestions carousel in web UI** (#28878, #29272, and #31912 by @Gargron)
|
- **Change onboarding prompt to follow suggestions carousel in web UI** (#28878, #29272, and #31912 by @Gargron)
|
||||||
- **Change email templates** (#28416, #28755, #28814, #29064, #28883, #29470, #29607, #29761, #29760, and #29879 by @ClearlyClaire, @Gargron, @hteumeuleu, and @mjankowski)\
|
- **Change email templates** (#28416, #28755, #28814, #29064, #28883, #29470, #29607, #29761, #29760, #29879, #32073 and #32132 by @c960657, @ClearlyClaire, @Gargron, @hteumeuleu, and @mjankowski)\
|
||||||
All emails to end-users have been completely redesigned with a fresh new look, providing more information while making them easier to read and keeping maximum compatibility across mail clients.
|
All emails to end-users have been completely redesigned with a fresh new look, providing more information while making them easier to read and keeping maximum compatibility across mail clients.
|
||||||
- **Change follow recommendations algorithm** (#28314, #28433, #29017, #29108, #29306, #29550, #29619, and #31474 by @ClearlyClaire, @Gargron, @kernal053, @mjankowski, and @wheatear-dev)\
|
- **Change follow recommendations algorithm** (#28314, #28433, #29017, #29108, #29306, #29550, #29619, and #31474 by @ClearlyClaire, @Gargron, @kernal053, @mjankowski, and @wheatear-dev)\
|
||||||
This replaces the “past interactions” recommendation algorithm with a “friends of friends” algorithm that suggests accounts followed by people you follow, and a “similar profiles” algorithm that suggests accounts with a profile similar to your most recent follows.\
|
This replaces the “past interactions” recommendation algorithm with a “friends of friends” algorithm that suggests accounts followed by people you follow, and a “similar profiles” algorithm that suggests accounts with a profile similar to your most recent follows.\
|
||||||
|
@ -188,10 +194,17 @@ The following changelog entries focus on changes visible to users, administrator
|
||||||
Administrators may need to update their setup accordingly.
|
Administrators may need to update their setup accordingly.
|
||||||
- Change how content warnings and filters are displayed in web UI (#31365, and #31761 by @Gargron)
|
- Change how content warnings and filters are displayed in web UI (#31365, and #31761 by @Gargron)
|
||||||
- Change preview card processing to ignore `undefined` as canonical url (#31882 by @oneiros)
|
- Change preview card processing to ignore `undefined` as canonical url (#31882 by @oneiros)
|
||||||
- Change embedded posts to use web UI (#31766 by @Gargron)
|
- Change embedded posts to use web UI (#31766, #32135 and #32271 by @Gargron)
|
||||||
- Change inner borders in media galleries in web UI (#31852 by @Gargron)
|
- Change inner borders in media galleries in web UI (#31852 by @Gargron)
|
||||||
- Change design of hide media button in web UI (#31807 by @Gargron)
|
- Change design of media attachments and profile media tab in web UI (#31807, #32048, #31967, #32217, #32224 and #32257 by @ClearlyClaire and @Gargron)
|
||||||
- Change labels on thread indicators in web UI (#31806 by @Gargron)
|
- Change labels on thread indicators in web UI (#31806 by @Gargron)
|
||||||
|
- Change label of "Data export" menu item in settings interface (#32099 by @c960657)
|
||||||
|
- Change responsive break points on navigation panel in web UI (#32034 by @Gargron)
|
||||||
|
- Change cursor to `not-allowed` on disabled buttons (#32076 by @mjankowski)
|
||||||
|
- Change OAuth authorization prompt to not refer to apps as “third-party” (#32005 by @Gargron)
|
||||||
|
- Change Mastodon to issue correct HTTP signatures by default (#31994 by @ClearlyClaire)
|
||||||
|
- Change zoom icon in web UI (#29683 by @Gargron)
|
||||||
|
- Change directory page to use URL query strings for options (#31980, #31977 and #31984 by @ClearlyClaire and @renchap)
|
||||||
- Change report action buttons to be disabled when action has already been taken (#31773, #31822, and #31899 by @ClearlyClaire and @ThisIsMissEm)
|
- Change report action buttons to be disabled when action has already been taken (#31773, #31822, and #31899 by @ClearlyClaire and @ThisIsMissEm)
|
||||||
- Change width of columns in advanced web UI (#31762 by @Gargron)
|
- Change width of columns in advanced web UI (#31762 by @Gargron)
|
||||||
- Change design of unread conversations in web UI (#31763 by @Gargron)
|
- Change design of unread conversations in web UI (#31763 by @Gargron)
|
||||||
|
@ -254,6 +267,7 @@ The following changelog entries focus on changes visible to users, administrator
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
|
- Remove unused E2EE messaging code and related `crypto` OAuth scope (#31193, #31945, #31963, and #31964 by @ClearlyClaire and @mjankowski)
|
||||||
- Remove StatsD integration (replaced by OpenTelemetry) (#30240 by @mjankowski)
|
- Remove StatsD integration (replaced by OpenTelemetry) (#30240 by @mjankowski)
|
||||||
- Remove `CacheBuster` default options (#30718 by @mjankowski)
|
- Remove `CacheBuster` default options (#30718 by @mjankowski)
|
||||||
- Remove home marker updates from the Web UI (#22721 by @davbeck)\
|
- Remove home marker updates from the Web UI (#22721 by @davbeck)\
|
||||||
|
@ -269,9 +283,22 @@ The following changelog entries focus on changes visible to users, administrator
|
||||||
- Fix log out from user menu not working on Safari (#31402 by @renchap)
|
- Fix log out from user menu not working on Safari (#31402 by @renchap)
|
||||||
- Fix various issues when in link preview card generation (#28748, #30017, #30362, #30173, #30853, #30929, #30933, #30957, #30987, and #31144 by @adamniedzielski, @oneiros, @phocks, @timothyjrogers, and @tribela)
|
- Fix various issues when in link preview card generation (#28748, #30017, #30362, #30173, #30853, #30929, #30933, #30957, #30987, and #31144 by @adamniedzielski, @oneiros, @phocks, @timothyjrogers, and @tribela)
|
||||||
- Fix handling of missing links in Webfinger responses (#31030 by @adamniedzielski)
|
- Fix handling of missing links in Webfinger responses (#31030 by @adamniedzielski)
|
||||||
|
- Fix error when accepting an appeal for sensitive posts deleted in the meantime (#32037 by @ClearlyClaire)
|
||||||
|
- Fix error when encountering reblog of deleted post in feed rebuild (#32001 by @ClearlyClaire)
|
||||||
|
- Fix Safari browser glitch related to horizontal scrolling (#31960 by @Gargron)
|
||||||
|
- Fix unresolvable mentions sometimes preventing processing incoming posts (#29215 by @tribela and @ClearlyClaire)
|
||||||
|
- Fix too many requests caused by relationship look-ups in web UI (#32042 by @Gargron)
|
||||||
|
- Fix links for reblogs in moderation interface (#31979 by @ClearlyClaire)
|
||||||
|
- Fix the appearance of avatars when they do not load (#31966 and #32270 by @Gargron and @renchap)
|
||||||
|
- Fix spurious error notifications for aborted requests in web UI (#31952 by @c960657)
|
||||||
- Fix HTTP 500 error in `/api/v1/polls/:id/votes` when required `choices` parameter is missing (#25598 by @danielmbrasil)
|
- Fix HTTP 500 error in `/api/v1/polls/:id/votes` when required `choices` parameter is missing (#25598 by @danielmbrasil)
|
||||||
- Fix security context sometimes not being added in LD-Signed activities (#31871 by @ClearlyClaire)
|
- Fix security context sometimes not being added in LD-Signed activities (#31871 by @ClearlyClaire)
|
||||||
- Fix cross-origin loading of `inert.css` polyfill (#30687 by @louis77)
|
- Fix cross-origin loading of `inert.css` polyfill (#30687 by @louis77)
|
||||||
|
- Fix wrapping in dashboard quick access buttons (#32043 by @renchap)
|
||||||
|
- Fix recently used tags hint being displayed in profile edition page when there is none (#32120 by @mjankowski)
|
||||||
|
- Fix checkbox lists on narrow screens in the settings interface (#32112 by @mjankowski)
|
||||||
|
- Fix the position of status action buttons being affected by interaction counters (#32084 by @renchap)
|
||||||
|
- Fix the summary of converted ActivityPub object types to be treated as HTML (#28629 by @Menrath)
|
||||||
- Fix cutoff of instance name in sign-up form (#30598 by @oneiros)
|
- Fix cutoff of instance name in sign-up form (#30598 by @oneiros)
|
||||||
- Fix invalid date searches returning 503 errors (#31526 by @notchairmk)
|
- Fix invalid date searches returning 503 errors (#31526 by @notchairmk)
|
||||||
- Fix invalid `visibility` values in `POST /api/v1/statuses` returning 500 errors (#31571 by @c960657)
|
- Fix invalid `visibility` values in `POST /api/v1/statuses` returning 500 errors (#31571 by @c960657)
|
||||||
|
@ -285,10 +312,12 @@ The following changelog entries focus on changes visible to users, administrator
|
||||||
- Fix “Redirect URI” field not being marked as required in “New application” form (#30311 by @ThisIsMissEm)
|
- Fix “Redirect URI” field not being marked as required in “New application” form (#30311 by @ThisIsMissEm)
|
||||||
- Fix right-to-left text in preview cards (#30930 by @ClearlyClaire)
|
- Fix right-to-left text in preview cards (#30930 by @ClearlyClaire)
|
||||||
- Fix rack attack `match_type` value typo in logging config (#30514 by @mjankowski)
|
- Fix rack attack `match_type` value typo in logging config (#30514 by @mjankowski)
|
||||||
- Fix various cases of duplicate, missing, or inconsistent borders or scrollbar styles (#31068, #31286, #31268, #31275, #31284, #31305, #31346, #31372, #31373, #31389, #31432, #31391, and #31445 by @valtlai and @vmstan)
|
- Fix various cases of duplicate, missing, or inconsistent borders or scrollbar styles (#31068, #31286, #31268, #31275, #31284, #31305, #31346, #31372, #31373, #31389, #31432, #31391, #31445, #32091, #32147 and #32137 by @ClearlyClaire, @mjankowski, @valtlai and @vmstan)
|
||||||
|
- Fix editing description of media uploads with custom thumbnails (#32221 by @ClearlyClaire)
|
||||||
- Fix race condition in `POST /api/v1/push/subscription` (#30166 by @ClearlyClaire)
|
- Fix race condition in `POST /api/v1/push/subscription` (#30166 by @ClearlyClaire)
|
||||||
- Fix post deletion not being delayed when those are part of an account warning (#30163 by @ClearlyClaire)
|
- Fix post deletion not being delayed when those are part of an account warning (#30163 by @ClearlyClaire)
|
||||||
- Fix rendering error on `/start` when not logged in (#30023 by @timothyjrogers)
|
- Fix rendering error on `/start` when not logged in (#30023 by @timothyjrogers)
|
||||||
|
- Fix unneeded requests to blocked domains when receiving relayed signed activities from them (#31161 by @ClearlyClaire)
|
||||||
- Fix logo pushing header buttons out of view on certain conditions in mobile layout (#29787 by @ClearlyClaire)
|
- Fix logo pushing header buttons out of view on certain conditions in mobile layout (#29787 by @ClearlyClaire)
|
||||||
- Fix notification-related records not being reattributed when merging accounts (#29694 by @ClearlyClaire)
|
- Fix notification-related records not being reattributed when merging accounts (#29694 by @ClearlyClaire)
|
||||||
- Fix results/query in `api/v1/featured_tags/suggestions` (#29597 by @mjankowski)
|
- Fix results/query in `api/v1/featured_tags/suggestions` (#29597 by @mjankowski)
|
||||||
|
@ -298,6 +327,7 @@ The following changelog entries focus on changes visible to users, administrator
|
||||||
- Fix full date display not respecting the locale 12/24h format (#29448 by @renchap)
|
- Fix full date display not respecting the locale 12/24h format (#29448 by @renchap)
|
||||||
- Fix filters title and keywords overflow (#29396 by @GeopJr)
|
- Fix filters title and keywords overflow (#29396 by @GeopJr)
|
||||||
- Fix incorrect date format in “Follows and followers” (#29390 by @JasonPunyon)
|
- Fix incorrect date format in “Follows and followers” (#29390 by @JasonPunyon)
|
||||||
|
- Fix navigation item active highlight for some paths (#32159 by @mjankowski)
|
||||||
- Fix “Edit media” modal sizing and layout when space-constrained (#27095 by @ronilaukkarinen)
|
- Fix “Edit media” modal sizing and layout when space-constrained (#27095 by @ronilaukkarinen)
|
||||||
- Fix modal container bounds (#29185 by @nico3333fr)
|
- Fix modal container bounds (#29185 by @nico3333fr)
|
||||||
- Fix inefficient HTTP signature parsing using regexps and `StringScanner` (#29133 by @ClearlyClaire)
|
- Fix inefficient HTTP signature parsing using regexps and `StringScanner` (#29133 by @ClearlyClaire)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# syntax=docker/dockerfile:1.9
|
# syntax=docker/dockerfile:1.10
|
||||||
|
|
||||||
# This file is designed for production server deployment, not local development work
|
# This file is designed for production server deployment, not local development work
|
||||||
# For a containerized local dev environment, see: https://github.com/mastodon/mastodon/blob/main/README.md#docker
|
# For a containerized local dev environment, see: https://github.com/mastodon/mastodon/blob/main/README.md#docker
|
||||||
|
@ -15,7 +15,7 @@ ARG BUILDPLATFORM=${BUILDPLATFORM}
|
||||||
ARG RUBY_VERSION="3.3.5"
|
ARG RUBY_VERSION="3.3.5"
|
||||||
# # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"]
|
# # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"]
|
||||||
# renovate: datasource=node-version depName=node
|
# renovate: datasource=node-version depName=node
|
||||||
ARG NODE_MAJOR_VERSION="20"
|
ARG NODE_MAJOR_VERSION="22"
|
||||||
# Debian image to use for base image, change with [--build-arg DEBIAN_VERSION="bookworm"]
|
# Debian image to use for base image, change with [--build-arg DEBIAN_VERSION="bookworm"]
|
||||||
ARG DEBIAN_VERSION="bookworm"
|
ARG DEBIAN_VERSION="bookworm"
|
||||||
# Node image to use for base image based on combined variables (ex: 20-bookworm-slim)
|
# Node image to use for base image based on combined variables (ex: 20-bookworm-slim)
|
||||||
|
@ -191,7 +191,7 @@ FROM build AS libvips
|
||||||
|
|
||||||
# libvips version to compile, change with [--build-arg VIPS_VERSION="8.15.2"]
|
# libvips version to compile, change with [--build-arg VIPS_VERSION="8.15.2"]
|
||||||
# renovate: datasource=github-releases depName=libvips packageName=libvips/libvips
|
# renovate: datasource=github-releases depName=libvips packageName=libvips/libvips
|
||||||
ARG VIPS_VERSION=8.15.3
|
ARG VIPS_VERSION=8.16.0
|
||||||
# libvips download URL, change with [--build-arg VIPS_URL="https://github.com/libvips/libvips/releases/download"]
|
# libvips download URL, change with [--build-arg VIPS_URL="https://github.com/libvips/libvips/releases/download"]
|
||||||
ARG VIPS_URL=https://github.com/libvips/libvips/releases/download
|
ARG VIPS_URL=https://github.com/libvips/libvips/releases/download
|
||||||
|
|
||||||
|
@ -214,7 +214,7 @@ FROM build AS ffmpeg
|
||||||
|
|
||||||
# ffmpeg version to compile, change with [--build-arg FFMPEG_VERSION="7.0.x"]
|
# ffmpeg version to compile, change with [--build-arg FFMPEG_VERSION="7.0.x"]
|
||||||
# renovate: datasource=repology depName=ffmpeg packageName=openpkg_current/ffmpeg
|
# renovate: datasource=repology depName=ffmpeg packageName=openpkg_current/ffmpeg
|
||||||
ARG FFMPEG_VERSION=7.0.2
|
ARG FFMPEG_VERSION=7.1
|
||||||
# ffmpeg download URL, change with [--build-arg FFMPEG_URL="https://ffmpeg.org/releases"]
|
# ffmpeg download URL, change with [--build-arg FFMPEG_URL="https://ffmpeg.org/releases"]
|
||||||
ARG FFMPEG_URL=https://ffmpeg.org/releases
|
ARG FFMPEG_URL=https://ffmpeg.org/releases
|
||||||
|
|
||||||
|
|
12
Gemfile
12
Gemfile
|
@ -1,7 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
source 'https://rubygems.org'
|
source 'https://rubygems.org'
|
||||||
ruby '>= 3.1.0'
|
ruby '>= 3.2.0'
|
||||||
|
|
||||||
gem 'propshaft'
|
gem 'propshaft'
|
||||||
gem 'puma', '~> 6.3'
|
gem 'puma', '~> 6.3'
|
||||||
|
@ -16,10 +16,10 @@ gem 'pghero'
|
||||||
|
|
||||||
gem 'aws-sdk-s3', '~> 1.123', require: false
|
gem 'aws-sdk-s3', '~> 1.123', require: false
|
||||||
gem 'blurhash', '~> 0.1'
|
gem 'blurhash', '~> 0.1'
|
||||||
gem 'fog-core', '<= 2.5.0'
|
gem 'fog-core', '<= 2.6.0'
|
||||||
gem 'fog-openstack', '~> 1.0', require: false
|
gem 'fog-openstack', '~> 1.0', require: false
|
||||||
|
gem 'jd-paperclip-azure', '~> 3.0', require: false
|
||||||
gem 'kt-paperclip', '~> 7.2'
|
gem 'kt-paperclip', '~> 7.2'
|
||||||
gem 'md-paperclip-azure', '~> 2.2', require: false
|
|
||||||
gem 'ruby-vips', '~> 2.2', require: false
|
gem 'ruby-vips', '~> 2.2', require: false
|
||||||
|
|
||||||
gem 'active_model_serializers', '~> 0.10'
|
gem 'active_model_serializers', '~> 0.10'
|
||||||
|
@ -61,7 +61,7 @@ gem 'irb', '~> 1.8'
|
||||||
gem 'kaminari', '~> 1.2'
|
gem 'kaminari', '~> 1.2'
|
||||||
gem 'link_header', '~> 0.0'
|
gem 'link_header', '~> 0.0'
|
||||||
gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
|
gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
|
||||||
gem 'mime-types', '~> 3.5.0', require: 'mime/types/columnar'
|
gem 'mime-types', '~> 3.6.0', require: 'mime/types/columnar'
|
||||||
gem 'nokogiri', '~> 1.15'
|
gem 'nokogiri', '~> 1.15'
|
||||||
gem 'oj', '~> 3.14'
|
gem 'oj', '~> 3.14'
|
||||||
gem 'ox', '~> 2.14'
|
gem 'ox', '~> 2.14'
|
||||||
|
@ -111,8 +111,8 @@ group :opentelemetry do
|
||||||
gem 'opentelemetry-instrumentation-http_client', '~> 0.22.3', require: false
|
gem 'opentelemetry-instrumentation-http_client', '~> 0.22.3', require: false
|
||||||
gem 'opentelemetry-instrumentation-net_http', '~> 0.22.4', require: false
|
gem 'opentelemetry-instrumentation-net_http', '~> 0.22.4', require: false
|
||||||
gem 'opentelemetry-instrumentation-pg', '~> 0.29.0', require: false
|
gem 'opentelemetry-instrumentation-pg', '~> 0.29.0', require: false
|
||||||
gem 'opentelemetry-instrumentation-rack', '~> 0.24.1', require: false
|
gem 'opentelemetry-instrumentation-rack', '~> 0.25.0', require: false
|
||||||
gem 'opentelemetry-instrumentation-rails', '~> 0.31.0', require: false
|
gem 'opentelemetry-instrumentation-rails', '~> 0.32.0', require: false
|
||||||
gem 'opentelemetry-instrumentation-redis', '~> 0.25.3', require: false
|
gem 'opentelemetry-instrumentation-redis', '~> 0.25.3', require: false
|
||||||
gem 'opentelemetry-instrumentation-sidekiq', '~> 0.25.2', require: false
|
gem 'opentelemetry-instrumentation-sidekiq', '~> 0.25.2', require: false
|
||||||
gem 'opentelemetry-sdk', '~> 1.4', require: false
|
gem 'opentelemetry-sdk', '~> 1.4', require: false
|
||||||
|
|
243
Gemfile.lock
243
Gemfile.lock
|
@ -10,35 +10,35 @@ GIT
|
||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
actioncable (7.1.4)
|
actioncable (7.1.4.2)
|
||||||
actionpack (= 7.1.4)
|
actionpack (= 7.1.4.2)
|
||||||
activesupport (= 7.1.4)
|
activesupport (= 7.1.4.2)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
websocket-driver (>= 0.6.1)
|
websocket-driver (>= 0.6.1)
|
||||||
zeitwerk (~> 2.6)
|
zeitwerk (~> 2.6)
|
||||||
actionmailbox (7.1.4)
|
actionmailbox (7.1.4.2)
|
||||||
actionpack (= 7.1.4)
|
actionpack (= 7.1.4.2)
|
||||||
activejob (= 7.1.4)
|
activejob (= 7.1.4.2)
|
||||||
activerecord (= 7.1.4)
|
activerecord (= 7.1.4.2)
|
||||||
activestorage (= 7.1.4)
|
activestorage (= 7.1.4.2)
|
||||||
activesupport (= 7.1.4)
|
activesupport (= 7.1.4.2)
|
||||||
mail (>= 2.7.1)
|
mail (>= 2.7.1)
|
||||||
net-imap
|
net-imap
|
||||||
net-pop
|
net-pop
|
||||||
net-smtp
|
net-smtp
|
||||||
actionmailer (7.1.4)
|
actionmailer (7.1.4.2)
|
||||||
actionpack (= 7.1.4)
|
actionpack (= 7.1.4.2)
|
||||||
actionview (= 7.1.4)
|
actionview (= 7.1.4.2)
|
||||||
activejob (= 7.1.4)
|
activejob (= 7.1.4.2)
|
||||||
activesupport (= 7.1.4)
|
activesupport (= 7.1.4.2)
|
||||||
mail (~> 2.5, >= 2.5.4)
|
mail (~> 2.5, >= 2.5.4)
|
||||||
net-imap
|
net-imap
|
||||||
net-pop
|
net-pop
|
||||||
net-smtp
|
net-smtp
|
||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
actionpack (7.1.4)
|
actionpack (7.1.4.2)
|
||||||
actionview (= 7.1.4)
|
actionview (= 7.1.4.2)
|
||||||
activesupport (= 7.1.4)
|
activesupport (= 7.1.4.2)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
racc
|
racc
|
||||||
rack (>= 2.2.4)
|
rack (>= 2.2.4)
|
||||||
|
@ -46,15 +46,15 @@ GEM
|
||||||
rack-test (>= 0.6.3)
|
rack-test (>= 0.6.3)
|
||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
rails-html-sanitizer (~> 1.6)
|
rails-html-sanitizer (~> 1.6)
|
||||||
actiontext (7.1.4)
|
actiontext (7.1.4.2)
|
||||||
actionpack (= 7.1.4)
|
actionpack (= 7.1.4.2)
|
||||||
activerecord (= 7.1.4)
|
activerecord (= 7.1.4.2)
|
||||||
activestorage (= 7.1.4)
|
activestorage (= 7.1.4.2)
|
||||||
activesupport (= 7.1.4)
|
activesupport (= 7.1.4.2)
|
||||||
globalid (>= 0.6.0)
|
globalid (>= 0.6.0)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
actionview (7.1.4)
|
actionview (7.1.4.2)
|
||||||
activesupport (= 7.1.4)
|
activesupport (= 7.1.4.2)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubi (~> 1.11)
|
erubi (~> 1.11)
|
||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
|
@ -64,22 +64,22 @@ GEM
|
||||||
activemodel (>= 4.1)
|
activemodel (>= 4.1)
|
||||||
case_transform (>= 0.2)
|
case_transform (>= 0.2)
|
||||||
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
|
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
|
||||||
activejob (7.1.4)
|
activejob (7.1.4.2)
|
||||||
activesupport (= 7.1.4)
|
activesupport (= 7.1.4.2)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (7.1.4)
|
activemodel (7.1.4.2)
|
||||||
activesupport (= 7.1.4)
|
activesupport (= 7.1.4.2)
|
||||||
activerecord (7.1.4)
|
activerecord (7.1.4.2)
|
||||||
activemodel (= 7.1.4)
|
activemodel (= 7.1.4.2)
|
||||||
activesupport (= 7.1.4)
|
activesupport (= 7.1.4.2)
|
||||||
timeout (>= 0.4.0)
|
timeout (>= 0.4.0)
|
||||||
activestorage (7.1.4)
|
activestorage (7.1.4.2)
|
||||||
actionpack (= 7.1.4)
|
actionpack (= 7.1.4.2)
|
||||||
activejob (= 7.1.4)
|
activejob (= 7.1.4.2)
|
||||||
activerecord (= 7.1.4)
|
activerecord (= 7.1.4.2)
|
||||||
activesupport (= 7.1.4)
|
activesupport (= 7.1.4.2)
|
||||||
marcel (~> 1.0)
|
marcel (~> 1.0)
|
||||||
activesupport (7.1.4)
|
activesupport (7.1.4.2)
|
||||||
base64
|
base64
|
||||||
bigdecimal
|
bigdecimal
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
|
@ -100,29 +100,23 @@ GEM
|
||||||
attr_required (1.0.2)
|
attr_required (1.0.2)
|
||||||
awrence (1.2.1)
|
awrence (1.2.1)
|
||||||
aws-eventstream (1.3.0)
|
aws-eventstream (1.3.0)
|
||||||
aws-partitions (1.978.0)
|
aws-partitions (1.997.0)
|
||||||
aws-sdk-core (3.209.0)
|
aws-sdk-core (3.211.0)
|
||||||
aws-eventstream (~> 1, >= 1.3.0)
|
aws-eventstream (~> 1, >= 1.3.0)
|
||||||
aws-partitions (~> 1, >= 1.651.0)
|
aws-partitions (~> 1, >= 1.992.0)
|
||||||
aws-sigv4 (~> 1.9)
|
aws-sigv4 (~> 1.9)
|
||||||
jmespath (~> 1, >= 1.6.1)
|
jmespath (~> 1, >= 1.6.1)
|
||||||
aws-sdk-kms (1.94.0)
|
aws-sdk-kms (1.95.0)
|
||||||
aws-sdk-core (~> 3, >= 3.207.0)
|
aws-sdk-core (~> 3, >= 3.210.0)
|
||||||
aws-sigv4 (~> 1.5)
|
aws-sigv4 (~> 1.5)
|
||||||
aws-sdk-s3 (1.166.0)
|
aws-sdk-s3 (1.169.0)
|
||||||
aws-sdk-core (~> 3, >= 3.207.0)
|
aws-sdk-core (~> 3, >= 3.210.0)
|
||||||
aws-sdk-kms (~> 1)
|
aws-sdk-kms (~> 1)
|
||||||
aws-sigv4 (~> 1.5)
|
aws-sigv4 (~> 1.5)
|
||||||
aws-sigv4 (1.10.0)
|
aws-sigv4 (1.10.1)
|
||||||
aws-eventstream (~> 1, >= 1.0.2)
|
aws-eventstream (~> 1, >= 1.0.2)
|
||||||
azure-storage-blob (2.0.3)
|
azure-blob (0.5.2)
|
||||||
azure-storage-common (~> 2.0)
|
rexml
|
||||||
nokogiri (~> 1, >= 1.10.8)
|
|
||||||
azure-storage-common (2.0.4)
|
|
||||||
faraday (~> 1.0)
|
|
||||||
faraday_middleware (~> 1.0, >= 1.0.0.rc1)
|
|
||||||
net-http-persistent (~> 4.0)
|
|
||||||
nokogiri (~> 1, >= 1.10.8)
|
|
||||||
base64 (0.2.0)
|
base64 (0.2.0)
|
||||||
bcp47_spec (0.2.1)
|
bcp47_spec (0.2.1)
|
||||||
bcrypt (3.1.20)
|
bcrypt (3.1.20)
|
||||||
|
@ -137,7 +131,7 @@ GEM
|
||||||
blurhash (0.1.8)
|
blurhash (0.1.8)
|
||||||
bootsnap (1.18.4)
|
bootsnap (1.18.4)
|
||||||
msgpack (~> 1.2)
|
msgpack (~> 1.2)
|
||||||
brakeman (6.2.1)
|
brakeman (6.2.2)
|
||||||
racc
|
racc
|
||||||
browser (5.3.1)
|
browser (5.3.1)
|
||||||
brpoplpush-redis_script (0.1.3)
|
brpoplpush-redis_script (0.1.3)
|
||||||
|
@ -179,7 +173,7 @@ GEM
|
||||||
bigdecimal
|
bigdecimal
|
||||||
rexml
|
rexml
|
||||||
crass (1.0.6)
|
crass (1.0.6)
|
||||||
css_parser (1.19.0)
|
css_parser (1.19.1)
|
||||||
addressable
|
addressable
|
||||||
csv (3.3.0)
|
csv (3.3.0)
|
||||||
database_cleaner-active_record (2.2.0)
|
database_cleaner-active_record (2.2.0)
|
||||||
|
@ -231,9 +225,9 @@ GEM
|
||||||
erubi (1.13.0)
|
erubi (1.13.0)
|
||||||
et-orbi (1.2.11)
|
et-orbi (1.2.11)
|
||||||
tzinfo
|
tzinfo
|
||||||
excon (0.111.0)
|
excon (0.112.0)
|
||||||
fabrication (2.31.0)
|
fabrication (2.31.0)
|
||||||
faker (3.4.2)
|
faker (3.5.1)
|
||||||
i18n (>= 1.8.11, < 2)
|
i18n (>= 1.8.11, < 2)
|
||||||
faraday (1.10.3)
|
faraday (1.10.3)
|
||||||
faraday-em_http (~> 1.0)
|
faraday-em_http (~> 1.0)
|
||||||
|
@ -258,11 +252,9 @@ GEM
|
||||||
faraday-patron (1.0.0)
|
faraday-patron (1.0.0)
|
||||||
faraday-rack (1.0.0)
|
faraday-rack (1.0.0)
|
||||||
faraday-retry (1.0.3)
|
faraday-retry (1.0.3)
|
||||||
faraday_middleware (1.2.0)
|
|
||||||
faraday (~> 1.0)
|
|
||||||
fast_blank (1.0.1)
|
fast_blank (1.0.1)
|
||||||
fastimage (2.3.1)
|
fastimage (2.3.1)
|
||||||
ffi (1.16.3)
|
ffi (1.17.0)
|
||||||
ffi-compiler (1.3.2)
|
ffi-compiler (1.3.2)
|
||||||
ffi (>= 1.15.5)
|
ffi (>= 1.15.5)
|
||||||
rake
|
rake
|
||||||
|
@ -301,7 +293,7 @@ GEM
|
||||||
activesupport (>= 5.1)
|
activesupport (>= 5.1)
|
||||||
haml (>= 4.0.6)
|
haml (>= 4.0.6)
|
||||||
railties (>= 5.1)
|
railties (>= 5.1)
|
||||||
haml_lint (0.58.0)
|
haml_lint (0.59.0)
|
||||||
haml (>= 5.0)
|
haml (>= 5.0)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
rainbow
|
rainbow
|
||||||
|
@ -347,11 +339,15 @@ GEM
|
||||||
activesupport (>= 3.0)
|
activesupport (>= 3.0)
|
||||||
nokogiri (>= 1.6)
|
nokogiri (>= 1.6)
|
||||||
io-console (0.7.2)
|
io-console (0.7.2)
|
||||||
irb (1.14.0)
|
irb (1.14.1)
|
||||||
rdoc (>= 4.0.0)
|
rdoc (>= 4.0.0)
|
||||||
reline (>= 0.4.2)
|
reline (>= 0.4.2)
|
||||||
|
jd-paperclip-azure (3.0.0)
|
||||||
|
addressable (~> 2.5)
|
||||||
|
azure-blob (~> 0.5.2)
|
||||||
|
hashie (~> 5.0)
|
||||||
jmespath (1.6.2)
|
jmespath (1.6.2)
|
||||||
json (2.7.2)
|
json (2.7.4)
|
||||||
json-canonicalization (1.0.0)
|
json-canonicalization (1.0.0)
|
||||||
json-jwt (1.15.3.1)
|
json-jwt (1.15.3.1)
|
||||||
activesupport (>= 4.2)
|
activesupport (>= 4.2)
|
||||||
|
@ -369,7 +365,7 @@ GEM
|
||||||
json-ld-preloaded (3.3.0)
|
json-ld-preloaded (3.3.0)
|
||||||
json-ld (~> 3.3)
|
json-ld (~> 3.3)
|
||||||
rdf (~> 3.3)
|
rdf (~> 3.3)
|
||||||
json-schema (5.0.0)
|
json-schema (5.0.1)
|
||||||
addressable (~> 2.8)
|
addressable (~> 2.8)
|
||||||
jsonapi-renderer (0.2.2)
|
jsonapi-renderer (0.2.2)
|
||||||
jwt (2.7.1)
|
jwt (2.7.1)
|
||||||
|
@ -412,7 +408,7 @@ GEM
|
||||||
activesupport (>= 4)
|
activesupport (>= 4)
|
||||||
railties (>= 4)
|
railties (>= 4)
|
||||||
request_store (~> 1.0)
|
request_store (~> 1.0)
|
||||||
loofah (2.22.0)
|
loofah (2.23.1)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.12.0)
|
nokogiri (>= 1.12.0)
|
||||||
mail (2.8.1)
|
mail (2.8.1)
|
||||||
|
@ -424,26 +420,21 @@ GEM
|
||||||
mario-redis-lock (1.2.1)
|
mario-redis-lock (1.2.1)
|
||||||
redis (>= 3.0.5)
|
redis (>= 3.0.5)
|
||||||
matrix (0.4.2)
|
matrix (0.4.2)
|
||||||
md-paperclip-azure (2.2.0)
|
|
||||||
addressable (~> 2.5)
|
|
||||||
azure-storage-blob (~> 2.0.1)
|
|
||||||
hashie (~> 5.0)
|
|
||||||
memory_profiler (1.1.0)
|
memory_profiler (1.1.0)
|
||||||
mime-types (3.5.2)
|
mime-types (3.6.0)
|
||||||
|
logger
|
||||||
mime-types-data (~> 3.2015)
|
mime-types-data (~> 3.2015)
|
||||||
mime-types-data (3.2024.0820)
|
mime-types-data (3.2024.1001)
|
||||||
mini_mime (1.1.5)
|
mini_mime (1.1.5)
|
||||||
mini_portile2 (2.8.7)
|
mini_portile2 (2.8.7)
|
||||||
minitest (5.25.1)
|
minitest (5.25.1)
|
||||||
msgpack (1.7.2)
|
msgpack (1.7.3)
|
||||||
multi_json (1.15.0)
|
multi_json (1.15.0)
|
||||||
multipart-post (2.4.1)
|
multipart-post (2.4.1)
|
||||||
mutex_m (0.2.0)
|
mutex_m (0.2.0)
|
||||||
net-http (0.4.1)
|
net-http (0.4.1)
|
||||||
uri
|
uri
|
||||||
net-http-persistent (4.0.2)
|
net-imap (0.5.0)
|
||||||
connection_pool (~> 2.2)
|
|
||||||
net-imap (0.4.15)
|
|
||||||
date
|
date
|
||||||
net-protocol
|
net-protocol
|
||||||
net-ldap (0.19.0)
|
net-ldap (0.19.0)
|
||||||
|
@ -503,7 +494,7 @@ GEM
|
||||||
opentelemetry-semantic_conventions
|
opentelemetry-semantic_conventions
|
||||||
opentelemetry-helpers-sql-obfuscation (0.2.0)
|
opentelemetry-helpers-sql-obfuscation (0.2.0)
|
||||||
opentelemetry-common (~> 0.21)
|
opentelemetry-common (~> 0.21)
|
||||||
opentelemetry-instrumentation-action_mailer (0.1.0)
|
opentelemetry-instrumentation-action_mailer (0.2.0)
|
||||||
opentelemetry-api (~> 1.0)
|
opentelemetry-api (~> 1.0)
|
||||||
opentelemetry-instrumentation-active_support (~> 0.1)
|
opentelemetry-instrumentation-active_support (~> 0.1)
|
||||||
opentelemetry-instrumentation-base (~> 0.22.1)
|
opentelemetry-instrumentation-base (~> 0.22.1)
|
||||||
|
@ -515,13 +506,13 @@ GEM
|
||||||
opentelemetry-api (~> 1.0)
|
opentelemetry-api (~> 1.0)
|
||||||
opentelemetry-instrumentation-active_support (~> 0.1)
|
opentelemetry-instrumentation-active_support (~> 0.1)
|
||||||
opentelemetry-instrumentation-base (~> 0.22.1)
|
opentelemetry-instrumentation-base (~> 0.22.1)
|
||||||
opentelemetry-instrumentation-active_job (0.7.7)
|
opentelemetry-instrumentation-active_job (0.7.8)
|
||||||
opentelemetry-api (~> 1.0)
|
opentelemetry-api (~> 1.0)
|
||||||
opentelemetry-instrumentation-base (~> 0.22.1)
|
opentelemetry-instrumentation-base (~> 0.22.1)
|
||||||
opentelemetry-instrumentation-active_model_serializers (0.20.2)
|
opentelemetry-instrumentation-active_model_serializers (0.20.2)
|
||||||
opentelemetry-api (~> 1.0)
|
opentelemetry-api (~> 1.0)
|
||||||
opentelemetry-instrumentation-base (~> 0.22.1)
|
opentelemetry-instrumentation-base (~> 0.22.1)
|
||||||
opentelemetry-instrumentation-active_record (0.7.3)
|
opentelemetry-instrumentation-active_record (0.8.0)
|
||||||
opentelemetry-api (~> 1.0)
|
opentelemetry-api (~> 1.0)
|
||||||
opentelemetry-instrumentation-base (~> 0.22.1)
|
opentelemetry-instrumentation-base (~> 0.22.1)
|
||||||
opentelemetry-instrumentation-active_support (0.6.0)
|
opentelemetry-instrumentation-active_support (0.6.0)
|
||||||
|
@ -553,16 +544,16 @@ GEM
|
||||||
opentelemetry-api (~> 1.0)
|
opentelemetry-api (~> 1.0)
|
||||||
opentelemetry-helpers-sql-obfuscation
|
opentelemetry-helpers-sql-obfuscation
|
||||||
opentelemetry-instrumentation-base (~> 0.22.1)
|
opentelemetry-instrumentation-base (~> 0.22.1)
|
||||||
opentelemetry-instrumentation-rack (0.24.6)
|
opentelemetry-instrumentation-rack (0.25.0)
|
||||||
opentelemetry-api (~> 1.0)
|
opentelemetry-api (~> 1.0)
|
||||||
opentelemetry-instrumentation-base (~> 0.22.1)
|
opentelemetry-instrumentation-base (~> 0.22.1)
|
||||||
opentelemetry-instrumentation-rails (0.31.2)
|
opentelemetry-instrumentation-rails (0.32.0)
|
||||||
opentelemetry-api (~> 1.0)
|
opentelemetry-api (~> 1.0)
|
||||||
opentelemetry-instrumentation-action_mailer (~> 0.1.0)
|
opentelemetry-instrumentation-action_mailer (~> 0.2.0)
|
||||||
opentelemetry-instrumentation-action_pack (~> 0.9.0)
|
opentelemetry-instrumentation-action_pack (~> 0.9.0)
|
||||||
opentelemetry-instrumentation-action_view (~> 0.7.0)
|
opentelemetry-instrumentation-action_view (~> 0.7.0)
|
||||||
opentelemetry-instrumentation-active_job (~> 0.7.0)
|
opentelemetry-instrumentation-active_job (~> 0.7.0)
|
||||||
opentelemetry-instrumentation-active_record (~> 0.7.0)
|
opentelemetry-instrumentation-active_record (~> 0.8.0)
|
||||||
opentelemetry-instrumentation-active_support (~> 0.6.0)
|
opentelemetry-instrumentation-active_support (~> 0.6.0)
|
||||||
opentelemetry-instrumentation-base (~> 0.22.1)
|
opentelemetry-instrumentation-base (~> 0.22.1)
|
||||||
opentelemetry-instrumentation-redis (0.25.7)
|
opentelemetry-instrumentation-redis (0.25.7)
|
||||||
|
@ -590,8 +581,8 @@ GEM
|
||||||
parslet (2.0.0)
|
parslet (2.0.0)
|
||||||
pastel (0.8.0)
|
pastel (0.8.0)
|
||||||
tty-color (~> 0.5)
|
tty-color (~> 0.5)
|
||||||
pg (1.5.8)
|
pg (1.5.9)
|
||||||
pghero (3.6.0)
|
pghero (3.6.1)
|
||||||
activerecord (>= 6.1)
|
activerecord (>= 6.1)
|
||||||
premailer (1.27.0)
|
premailer (1.27.0)
|
||||||
addressable
|
addressable
|
||||||
|
@ -601,7 +592,7 @@ GEM
|
||||||
actionmailer (>= 3)
|
actionmailer (>= 3)
|
||||||
net-smtp
|
net-smtp
|
||||||
premailer (~> 1.7, >= 1.7.9)
|
premailer (~> 1.7, >= 1.7.9)
|
||||||
propshaft (1.0.0)
|
propshaft (1.1.0)
|
||||||
actionpack (>= 7.0.0)
|
actionpack (>= 7.0.0)
|
||||||
activesupport (>= 7.0.0)
|
activesupport (>= 7.0.0)
|
||||||
rack
|
rack
|
||||||
|
@ -615,7 +606,7 @@ GEM
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
raabro (1.4.0)
|
raabro (1.4.0)
|
||||||
racc (1.8.1)
|
racc (1.8.1)
|
||||||
rack (2.2.9)
|
rack (2.2.10)
|
||||||
rack-attack (6.7.0)
|
rack-attack (6.7.0)
|
||||||
rack (>= 1.0, < 4)
|
rack (>= 1.0, < 4)
|
||||||
rack-cors (2.0.2)
|
rack-cors (2.0.2)
|
||||||
|
@ -638,20 +629,20 @@ GEM
|
||||||
rackup (1.0.0)
|
rackup (1.0.0)
|
||||||
rack (< 3)
|
rack (< 3)
|
||||||
webrick
|
webrick
|
||||||
rails (7.1.4)
|
rails (7.1.4.2)
|
||||||
actioncable (= 7.1.4)
|
actioncable (= 7.1.4.2)
|
||||||
actionmailbox (= 7.1.4)
|
actionmailbox (= 7.1.4.2)
|
||||||
actionmailer (= 7.1.4)
|
actionmailer (= 7.1.4.2)
|
||||||
actionpack (= 7.1.4)
|
actionpack (= 7.1.4.2)
|
||||||
actiontext (= 7.1.4)
|
actiontext (= 7.1.4.2)
|
||||||
actionview (= 7.1.4)
|
actionview (= 7.1.4.2)
|
||||||
activejob (= 7.1.4)
|
activejob (= 7.1.4.2)
|
||||||
activemodel (= 7.1.4)
|
activemodel (= 7.1.4.2)
|
||||||
activerecord (= 7.1.4)
|
activerecord (= 7.1.4.2)
|
||||||
activestorage (= 7.1.4)
|
activestorage (= 7.1.4.2)
|
||||||
activesupport (= 7.1.4)
|
activesupport (= 7.1.4.2)
|
||||||
bundler (>= 1.15.0)
|
bundler (>= 1.15.0)
|
||||||
railties (= 7.1.4)
|
railties (= 7.1.4.2)
|
||||||
rails-controller-testing (1.0.5)
|
rails-controller-testing (1.0.5)
|
||||||
actionpack (>= 5.0.1.rc1)
|
actionpack (>= 5.0.1.rc1)
|
||||||
actionview (>= 5.0.1.rc1)
|
actionview (>= 5.0.1.rc1)
|
||||||
|
@ -663,12 +654,12 @@ GEM
|
||||||
rails-html-sanitizer (1.6.0)
|
rails-html-sanitizer (1.6.0)
|
||||||
loofah (~> 2.21)
|
loofah (~> 2.21)
|
||||||
nokogiri (~> 1.14)
|
nokogiri (~> 1.14)
|
||||||
rails-i18n (7.0.9)
|
rails-i18n (7.0.10)
|
||||||
i18n (>= 0.7, < 2)
|
i18n (>= 0.7, < 2)
|
||||||
railties (>= 6.0.0, < 8)
|
railties (>= 6.0.0, < 8)
|
||||||
railties (7.1.4)
|
railties (7.1.4.2)
|
||||||
actionpack (= 7.1.4)
|
actionpack (= 7.1.4.2)
|
||||||
activesupport (= 7.1.4)
|
activesupport (= 7.1.4.2)
|
||||||
irb
|
irb
|
||||||
rackup (>= 1.0.0)
|
rackup (>= 1.0.0)
|
||||||
rake (>= 12.2)
|
rake (>= 12.2)
|
||||||
|
@ -698,9 +689,9 @@ GEM
|
||||||
responders (3.1.1)
|
responders (3.1.1)
|
||||||
actionpack (>= 5.2)
|
actionpack (>= 5.2)
|
||||||
railties (>= 5.2)
|
railties (>= 5.2)
|
||||||
rexml (3.3.7)
|
rexml (3.3.9)
|
||||||
rotp (6.3.0)
|
rotp (6.3.0)
|
||||||
rouge (4.3.0)
|
rouge (4.4.0)
|
||||||
rpam2 (4.0.2)
|
rpam2 (4.0.2)
|
||||||
rqrcode (2.2.0)
|
rqrcode (2.2.0)
|
||||||
chunky_png (~> 1.0)
|
chunky_png (~> 1.0)
|
||||||
|
@ -710,14 +701,14 @@ GEM
|
||||||
rspec-core (~> 3.13.0)
|
rspec-core (~> 3.13.0)
|
||||||
rspec-expectations (~> 3.13.0)
|
rspec-expectations (~> 3.13.0)
|
||||||
rspec-mocks (~> 3.13.0)
|
rspec-mocks (~> 3.13.0)
|
||||||
rspec-core (3.13.1)
|
rspec-core (3.13.2)
|
||||||
rspec-support (~> 3.13.0)
|
rspec-support (~> 3.13.0)
|
||||||
rspec-expectations (3.13.2)
|
rspec-expectations (3.13.3)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.13.0)
|
rspec-support (~> 3.13.0)
|
||||||
rspec-github (2.4.0)
|
rspec-github (2.4.0)
|
||||||
rspec-core (~> 3.0)
|
rspec-core (~> 3.0)
|
||||||
rspec-mocks (3.13.1)
|
rspec-mocks (3.13.2)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.13.0)
|
rspec-support (~> 3.13.0)
|
||||||
rspec-rails (7.0.1)
|
rspec-rails (7.0.1)
|
||||||
|
@ -748,20 +739,20 @@ GEM
|
||||||
parser (>= 3.3.1.0)
|
parser (>= 3.3.1.0)
|
||||||
rubocop-capybara (2.21.0)
|
rubocop-capybara (2.21.0)
|
||||||
rubocop (~> 1.41)
|
rubocop (~> 1.41)
|
||||||
rubocop-performance (1.21.1)
|
rubocop-performance (1.22.1)
|
||||||
rubocop (>= 1.48.1, < 2.0)
|
rubocop (>= 1.48.1, < 2.0)
|
||||||
rubocop-ast (>= 1.31.1, < 2.0)
|
rubocop-ast (>= 1.31.1, < 2.0)
|
||||||
rubocop-rails (2.25.1)
|
rubocop-rails (2.27.0)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
rack (>= 1.1)
|
rack (>= 1.1)
|
||||||
rubocop (>= 1.33.0, < 2.0)
|
rubocop (>= 1.52.0, < 2.0)
|
||||||
rubocop-ast (>= 1.31.1, < 2.0)
|
rubocop-ast (>= 1.31.1, < 2.0)
|
||||||
rubocop-rspec (3.0.4)
|
rubocop-rspec (3.2.0)
|
||||||
rubocop (~> 1.61)
|
rubocop (~> 1.61)
|
||||||
rubocop-rspec_rails (2.30.0)
|
rubocop-rspec_rails (2.30.0)
|
||||||
rubocop (~> 1.61)
|
rubocop (~> 1.61)
|
||||||
rubocop-rspec (~> 3, >= 3.0.1)
|
rubocop-rspec (~> 3, >= 3.0.1)
|
||||||
ruby-prof (1.7.0)
|
ruby-prof (1.7.1)
|
||||||
ruby-progressbar (1.13.0)
|
ruby-progressbar (1.13.0)
|
||||||
ruby-saml (1.17.0)
|
ruby-saml (1.17.0)
|
||||||
nokogiri (>= 1.13.10)
|
nokogiri (>= 1.13.10)
|
||||||
|
@ -781,7 +772,7 @@ GEM
|
||||||
scenic (1.8.0)
|
scenic (1.8.0)
|
||||||
activerecord (>= 4.0.0)
|
activerecord (>= 4.0.0)
|
||||||
railties (>= 4.0.0)
|
railties (>= 4.0.0)
|
||||||
selenium-webdriver (4.25.0)
|
selenium-webdriver (4.26.0)
|
||||||
base64 (~> 0.2)
|
base64 (~> 0.2)
|
||||||
logger (~> 1.4)
|
logger (~> 1.4)
|
||||||
rexml (~> 3.2, >= 3.2.5)
|
rexml (~> 3.2, >= 3.2.5)
|
||||||
|
@ -815,14 +806,14 @@ GEM
|
||||||
docile (~> 1.1)
|
docile (~> 1.1)
|
||||||
simplecov-html (~> 0.11)
|
simplecov-html (~> 0.11)
|
||||||
simplecov_json_formatter (~> 0.1)
|
simplecov_json_formatter (~> 0.1)
|
||||||
simplecov-html (0.12.3)
|
simplecov-html (0.13.1)
|
||||||
simplecov-lcov (0.8.0)
|
simplecov-lcov (0.8.0)
|
||||||
simplecov_json_formatter (0.1.4)
|
simplecov_json_formatter (0.1.4)
|
||||||
stackprof (0.2.26)
|
stackprof (0.2.26)
|
||||||
stoplight (4.1.0)
|
stoplight (4.1.0)
|
||||||
redlock (~> 1.0)
|
redlock (~> 1.0)
|
||||||
stringio (3.1.1)
|
stringio (3.1.1)
|
||||||
strong_migrations (2.0.0)
|
strong_migrations (2.0.2)
|
||||||
activerecord (>= 6.1)
|
activerecord (>= 6.1)
|
||||||
swd (1.3.0)
|
swd (1.3.0)
|
||||||
activesupport (>= 3)
|
activesupport (>= 3)
|
||||||
|
@ -862,7 +853,7 @@ GEM
|
||||||
unf (0.1.4)
|
unf (0.1.4)
|
||||||
unf_ext
|
unf_ext
|
||||||
unf_ext (0.0.9.1)
|
unf_ext (0.0.9.1)
|
||||||
unicode-display_width (2.5.0)
|
unicode-display_width (2.6.0)
|
||||||
uri (0.13.1)
|
uri (0.13.1)
|
||||||
validate_email (0.1.6)
|
validate_email (0.1.6)
|
||||||
activemodel (>= 3.0)
|
activemodel (>= 3.0)
|
||||||
|
@ -884,7 +875,7 @@ GEM
|
||||||
webfinger (1.2.0)
|
webfinger (1.2.0)
|
||||||
activesupport
|
activesupport
|
||||||
httpclient (>= 2.4)
|
httpclient (>= 2.4)
|
||||||
webmock (3.23.1)
|
webmock (3.24.0)
|
||||||
addressable (>= 2.8.0)
|
addressable (>= 2.8.0)
|
||||||
crack (>= 0.3.2)
|
crack (>= 0.3.2)
|
||||||
hashdiff (>= 0.4.0, < 2.0.0)
|
hashdiff (>= 0.4.0, < 2.0.0)
|
||||||
|
@ -902,7 +893,7 @@ GEM
|
||||||
xorcist (1.1.3)
|
xorcist (1.1.3)
|
||||||
xpath (3.2.0)
|
xpath (3.2.0)
|
||||||
nokogiri (~> 1.8)
|
nokogiri (~> 1.8)
|
||||||
zeitwerk (2.6.18)
|
zeitwerk (2.7.1)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
|
@ -942,7 +933,7 @@ DEPENDENCIES
|
||||||
fast_blank (~> 1.0)
|
fast_blank (~> 1.0)
|
||||||
fastimage
|
fastimage
|
||||||
flatware-rspec
|
flatware-rspec
|
||||||
fog-core (<= 2.5.0)
|
fog-core (<= 2.6.0)
|
||||||
fog-openstack (~> 1.0)
|
fog-openstack (~> 1.0)
|
||||||
haml-rails (~> 2.0)
|
haml-rails (~> 2.0)
|
||||||
haml_lint
|
haml_lint
|
||||||
|
@ -957,6 +948,7 @@ DEPENDENCIES
|
||||||
idn-ruby
|
idn-ruby
|
||||||
inline_svg
|
inline_svg
|
||||||
irb (~> 1.8)
|
irb (~> 1.8)
|
||||||
|
jd-paperclip-azure (~> 3.0)
|
||||||
json-ld
|
json-ld
|
||||||
json-ld-preloaded (~> 3.2)
|
json-ld-preloaded (~> 3.2)
|
||||||
json-schema (~> 5.0)
|
json-schema (~> 5.0)
|
||||||
|
@ -968,9 +960,8 @@ DEPENDENCIES
|
||||||
lograge (~> 0.12)
|
lograge (~> 0.12)
|
||||||
mail (~> 2.8)
|
mail (~> 2.8)
|
||||||
mario-redis-lock (~> 1.2)
|
mario-redis-lock (~> 1.2)
|
||||||
md-paperclip-azure (~> 2.2)
|
|
||||||
memory_profiler
|
memory_profiler
|
||||||
mime-types (~> 3.5.0)
|
mime-types (~> 3.6.0)
|
||||||
net-http (~> 0.4.0)
|
net-http (~> 0.4.0)
|
||||||
net-ldap (~> 0.18)
|
net-ldap (~> 0.18)
|
||||||
nokogiri (~> 1.15)
|
nokogiri (~> 1.15)
|
||||||
|
@ -991,8 +982,8 @@ DEPENDENCIES
|
||||||
opentelemetry-instrumentation-http_client (~> 0.22.3)
|
opentelemetry-instrumentation-http_client (~> 0.22.3)
|
||||||
opentelemetry-instrumentation-net_http (~> 0.22.4)
|
opentelemetry-instrumentation-net_http (~> 0.22.4)
|
||||||
opentelemetry-instrumentation-pg (~> 0.29.0)
|
opentelemetry-instrumentation-pg (~> 0.29.0)
|
||||||
opentelemetry-instrumentation-rack (~> 0.24.1)
|
opentelemetry-instrumentation-rack (~> 0.25.0)
|
||||||
opentelemetry-instrumentation-rails (~> 0.31.0)
|
opentelemetry-instrumentation-rails (~> 0.32.0)
|
||||||
opentelemetry-instrumentation-redis (~> 0.25.3)
|
opentelemetry-instrumentation-redis (~> 0.25.3)
|
||||||
opentelemetry-instrumentation-sidekiq (~> 0.25.2)
|
opentelemetry-instrumentation-sidekiq (~> 0.25.2)
|
||||||
opentelemetry-sdk (~> 1.4)
|
opentelemetry-sdk (~> 1.4)
|
||||||
|
@ -1057,7 +1048,7 @@ DEPENDENCIES
|
||||||
xorcist (~> 1.1)
|
xorcist (~> 1.1)
|
||||||
|
|
||||||
RUBY VERSION
|
RUBY VERSION
|
||||||
ruby 3.3.4p94
|
ruby 3.3.5p100
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
2.5.18
|
2.5.22
|
||||||
|
|
|
@ -69,7 +69,7 @@ Mastodon acts as an OAuth2 provider, so 3rd party apps can use the REST and Stre
|
||||||
|
|
||||||
- **PostgreSQL** 12+
|
- **PostgreSQL** 12+
|
||||||
- **Redis** 4+
|
- **Redis** 4+
|
||||||
- **Ruby** 3.1+
|
- **Ruby** 3.2+
|
||||||
- **Node.js** 18+
|
- **Node.js** 18+
|
||||||
|
|
||||||
The repository includes deployment configurations for **Docker and docker-compose** as well as specific platforms like **Heroku**, and **Scalingo**. For Helm charts, reference the [mastodon/chart repository](https://github.com/mastodon/chart). The [**standalone** installation guide](https://docs.joinmastodon.org/admin/install/) is available in the documentation.
|
The repository includes deployment configurations for **Docker and docker-compose** as well as specific platforms like **Heroku**, and **Scalingo**. For Helm charts, reference the [mastodon/chart repository](https://github.com/mastodon/chart). The [**standalone** installation guide](https://docs.joinmastodon.org/admin/install/) is available in the documentation.
|
||||||
|
|
11
SECURITY.md
11
SECURITY.md
|
@ -13,8 +13,9 @@ A "vulnerability in Mastodon" is a vulnerability in the code distributed through
|
||||||
|
|
||||||
## Supported Versions
|
## Supported Versions
|
||||||
|
|
||||||
| Version | Supported |
|
| Version | Supported |
|
||||||
| ------- | --------- |
|
| ------- | ---------------- |
|
||||||
| 4.2.x | Yes |
|
| 4.3.x | Yes |
|
||||||
| 4.1.x | Yes |
|
| 4.2.x | Yes |
|
||||||
| < 4.1 | No |
|
| 4.1.x | Until 2025-04-08 |
|
||||||
|
| < 4.1 | No |
|
||||||
|
|
|
@ -41,11 +41,11 @@ class ActivityPub::OutboxesController < ActivityPub::BaseController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def outbox_url(**kwargs)
|
def outbox_url(**)
|
||||||
if params[:account_username].present?
|
if params[:account_username].present?
|
||||||
account_outbox_url(@account, **kwargs)
|
account_outbox_url(@account, **)
|
||||||
else
|
else
|
||||||
instance_actor_outbox_url(**kwargs)
|
instance_actor_outbox_url(**)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ class Admin::AnnouncementsController < Admin::BaseController
|
||||||
|
|
||||||
def index
|
def index
|
||||||
authorize :announcement, :index?
|
authorize :announcement, :index?
|
||||||
|
@published_announcements_count = Announcement.published.async_count
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
|
|
|
@ -6,6 +6,7 @@ class Admin::Disputes::AppealsController < Admin::BaseController
|
||||||
def index
|
def index
|
||||||
authorize :appeal, :index?
|
authorize :appeal, :index?
|
||||||
|
|
||||||
|
@pending_appeals_count = Appeal.pending.async_count
|
||||||
@appeals = filtered_appeals.page(params[:page])
|
@appeals = filtered_appeals.page(params[:page])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ class Admin::Trends::Links::PreviewCardProvidersController < Admin::BaseControll
|
||||||
def index
|
def index
|
||||||
authorize :preview_card_provider, :review?
|
authorize :preview_card_provider, :review?
|
||||||
|
|
||||||
|
@pending_preview_card_providers_count = PreviewCardProvider.unreviewed.async_count
|
||||||
@preview_card_providers = filtered_preview_card_providers.page(params[:page])
|
@preview_card_providers = filtered_preview_card_providers.page(params[:page])
|
||||||
@form = Trends::PreviewCardProviderBatch.new
|
@form = Trends::PreviewCardProviderBatch.new
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,7 +4,7 @@ class Admin::Trends::LinksController < Admin::BaseController
|
||||||
def index
|
def index
|
||||||
authorize :preview_card, :review?
|
authorize :preview_card, :review?
|
||||||
|
|
||||||
@locales = PreviewCardTrend.pluck('distinct language')
|
@locales = PreviewCardTrend.locales
|
||||||
@preview_cards = filtered_preview_cards.page(params[:page])
|
@preview_cards = filtered_preview_cards.page(params[:page])
|
||||||
@form = Trends::PreviewCardBatch.new
|
@form = Trends::PreviewCardBatch.new
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,7 +4,7 @@ class Admin::Trends::StatusesController < Admin::BaseController
|
||||||
def index
|
def index
|
||||||
authorize [:admin, :status], :review?
|
authorize [:admin, :status], :review?
|
||||||
|
|
||||||
@locales = StatusTrend.pluck('distinct language')
|
@locales = StatusTrend.locales
|
||||||
@statuses = filtered_statuses.page(params[:page])
|
@statuses = filtered_statuses.page(params[:page])
|
||||||
@form = Trends::StatusBatch.new
|
@form = Trends::StatusBatch.new
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,6 +4,7 @@ class Admin::Trends::TagsController < Admin::BaseController
|
||||||
def index
|
def index
|
||||||
authorize :tag, :review?
|
authorize :tag, :review?
|
||||||
|
|
||||||
|
@pending_tags_count = Tag.pending_review.async_count
|
||||||
@tags = filtered_tags.page(params[:page])
|
@tags = filtered_tags.page(params[:page])
|
||||||
@form = Trends::TagBatch.new
|
@form = Trends::TagBatch.new
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,6 +16,7 @@ class Api::V1::AccountsController < Api::BaseController
|
||||||
before_action :check_account_confirmation, except: [:index, :create]
|
before_action :check_account_confirmation, except: [:index, :create]
|
||||||
before_action :check_enabled_registrations, only: [:create]
|
before_action :check_enabled_registrations, only: [:create]
|
||||||
before_action :check_accounts_limit, only: [:index]
|
before_action :check_accounts_limit, only: [:index]
|
||||||
|
before_action :check_following_self, only: [:follow]
|
||||||
|
|
||||||
skip_before_action :require_authenticated_user!, only: :create
|
skip_before_action :require_authenticated_user!, only: :create
|
||||||
|
|
||||||
|
@ -101,8 +102,12 @@ class Api::V1::AccountsController < Api::BaseController
|
||||||
raise(Mastodon::ValidationError) if account_ids.size > DEFAULT_ACCOUNTS_LIMIT
|
raise(Mastodon::ValidationError) if account_ids.size > DEFAULT_ACCOUNTS_LIMIT
|
||||||
end
|
end
|
||||||
|
|
||||||
def relationships(**options)
|
def check_following_self
|
||||||
AccountRelationshipsPresenter.new([@account], current_user.account_id, **options)
|
render json: { error: I18n.t('accounts.self_follow_error') }, status: 403 if current_user.account.id == @account.id
|
||||||
|
end
|
||||||
|
|
||||||
|
def relationships(**)
|
||||||
|
AccountRelationshipsPresenter.new([@account], current_user.account_id, **)
|
||||||
end
|
end
|
||||||
|
|
||||||
def account_ids
|
def account_ids
|
||||||
|
|
|
@ -28,8 +28,8 @@ class Api::V1::FollowRequestsController < Api::BaseController
|
||||||
@account ||= Account.find(params[:id])
|
@account ||= Account.find(params[:id])
|
||||||
end
|
end
|
||||||
|
|
||||||
def relationships(**options)
|
def relationships(**)
|
||||||
AccountRelationshipsPresenter.new([account], current_user.account_id, **options)
|
AccountRelationshipsPresenter.new([account], current_user.account_id, **)
|
||||||
end
|
end
|
||||||
|
|
||||||
def load_accounts
|
def load_accounts
|
||||||
|
|
|
@ -52,7 +52,7 @@ class Api::V1::Notifications::RequestsController < Api::BaseController
|
||||||
private
|
private
|
||||||
|
|
||||||
def load_requests
|
def load_requests
|
||||||
requests = NotificationRequest.where(account: current_account).includes(:last_status, from_account: [:account_stat, :user]).to_a_paginated_by_id(
|
requests = NotificationRequest.where(account: current_account).without_suspended.includes(:last_status, from_account: [:account_stat, :user]).to_a_paginated_by_id(
|
||||||
limit_param(DEFAULT_ACCOUNTS_LIMIT),
|
limit_param(DEFAULT_ACCOUNTS_LIMIT),
|
||||||
params_slice(:max_id, :since_id, :min_id)
|
params_slice(:max_id, :since_id, :min_id)
|
||||||
)
|
)
|
||||||
|
|
|
@ -23,6 +23,6 @@ class Api::V1::Statuses::TranslationsController < Api::V1::Statuses::BaseControl
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_translation
|
def set_translation
|
||||||
@translation = TranslateStatusService.new.call(@status, content_locale)
|
@translation = TranslateStatusService.new.call(@status, I18n.locale.to_s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Api::Web::PushSubscriptionsController < Api::Web::BaseController
|
class Api::Web::PushSubscriptionsController < Api::Web::BaseController
|
||||||
before_action :require_user!
|
before_action :require_user!, except: :destroy
|
||||||
before_action :set_push_subscription, only: :update
|
before_action :set_push_subscription, only: :update
|
||||||
before_action :destroy_previous_subscriptions, only: :create, if: :prior_subscriptions?
|
before_action :destroy_previous_subscriptions, only: :create, if: :prior_subscriptions?
|
||||||
after_action :update_session_with_subscription, only: :create
|
after_action :update_session_with_subscription, only: :create
|
||||||
|
@ -17,6 +17,13 @@ class Api::Web::PushSubscriptionsController < Api::Web::BaseController
|
||||||
render json: @push_subscription, serializer: REST::WebPushSubscriptionSerializer
|
render json: @push_subscription, serializer: REST::WebPushSubscriptionSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
push_subscription = ::Web::PushSubscription.find_by_token_for(:unsubscribe, params[:id])
|
||||||
|
push_subscription&.destroy
|
||||||
|
|
||||||
|
head 200
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def active_session
|
def active_session
|
||||||
|
|
|
@ -32,7 +32,7 @@ class ApplicationController < ActionController::Base
|
||||||
rescue_from ActionController::InvalidAuthenticityToken, with: :unprocessable_entity
|
rescue_from ActionController::InvalidAuthenticityToken, with: :unprocessable_entity
|
||||||
rescue_from Mastodon::RateLimitExceededError, with: :too_many_requests
|
rescue_from Mastodon::RateLimitExceededError, with: :too_many_requests
|
||||||
|
|
||||||
rescue_from HTTP::Error, OpenSSL::SSL::SSLError, with: :internal_server_error
|
rescue_from(*Mastodon::HTTP_CONNECTION_ERRORS, with: :internal_server_error)
|
||||||
rescue_from Mastodon::RaceConditionError, Stoplight::Error::RedLight, ActiveRecord::SerializationFailure, with: :service_unavailable
|
rescue_from Mastodon::RaceConditionError, Stoplight::Error::RedLight, ActiveRecord::SerializationFailure, with: :service_unavailable
|
||||||
|
|
||||||
rescue_from Seahorse::Client::NetworkingError do |e|
|
rescue_from Seahorse::Client::NetworkingError do |e|
|
||||||
|
|
|
@ -20,7 +20,7 @@ module Api::ErrorHandling
|
||||||
render json: { error: 'Record not found' }, status: 404
|
render json: { error: 'Record not found' }, status: 404
|
||||||
end
|
end
|
||||||
|
|
||||||
rescue_from HTTP::Error, Mastodon::UnexpectedResponseError do
|
rescue_from(*Mastodon::HTTP_CONNECTION_ERRORS, Mastodon::UnexpectedResponseError) do
|
||||||
render json: { error: 'Remote data could not be fetched' }, status: 503
|
render json: { error: 'Remote data could not be fetched' }, status: 503
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ module Auth::CaptchaConcern
|
||||||
end
|
end
|
||||||
|
|
||||||
def captcha_available?
|
def captcha_available?
|
||||||
ENV['HCAPTCHA_SECRET_KEY'].present? && ENV['HCAPTCHA_SITE_KEY'].present?
|
Rails.configuration.x.captcha.secret_key.present? && Rails.configuration.x.captcha.site_key.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def captcha_enabled?
|
def captcha_enabled?
|
||||||
|
|
|
@ -80,7 +80,7 @@ module SignatureVerification
|
||||||
fail_with! "Verification failed for #{actor.to_log_human_identifier} #{actor.uri} using rsa-sha256 (RSASSA-PKCS1-v1_5 with SHA-256)", signed_string: compare_signed_string, signature: signature_params['signature']
|
fail_with! "Verification failed for #{actor.to_log_human_identifier} #{actor.uri} using rsa-sha256 (RSASSA-PKCS1-v1_5 with SHA-256)", signed_string: compare_signed_string, signature: signature_params['signature']
|
||||||
rescue SignatureVerificationError => e
|
rescue SignatureVerificationError => e
|
||||||
fail_with! e.message
|
fail_with! e.message
|
||||||
rescue HTTP::Error, OpenSSL::SSL::SSLError => e
|
rescue *Mastodon::HTTP_CONNECTION_ERRORS => e
|
||||||
fail_with! "Failed to fetch remote data: #{e.message}"
|
fail_with! "Failed to fetch remote data: #{e.message}"
|
||||||
rescue Mastodon::UnexpectedResponseError
|
rescue Mastodon::UnexpectedResponseError
|
||||||
fail_with! 'Failed to fetch remote data (got unexpected reply from server)'
|
fail_with! 'Failed to fetch remote data (got unexpected reply from server)'
|
||||||
|
|
|
@ -13,7 +13,7 @@ module WebAppControllerConcern
|
||||||
policy = ContentSecurityPolicy.new
|
policy = ContentSecurityPolicy.new
|
||||||
|
|
||||||
if policy.sso_host.present?
|
if policy.sso_host.present?
|
||||||
p.form_action policy.sso_host
|
p.form_action policy.sso_host, -> { "https://#{request.host}/auth/auth/" }
|
||||||
else
|
else
|
||||||
p.form_action :none
|
p.form_action :none
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,7 +13,7 @@ class MediaProxyController < ApplicationController
|
||||||
rescue_from ActiveRecord::RecordInvalid, with: :not_found
|
rescue_from ActiveRecord::RecordInvalid, with: :not_found
|
||||||
rescue_from Mastodon::UnexpectedResponseError, with: :not_found
|
rescue_from Mastodon::UnexpectedResponseError, with: :not_found
|
||||||
rescue_from Mastodon::NotPermittedError, with: :not_found
|
rescue_from Mastodon::NotPermittedError, with: :not_found
|
||||||
rescue_from HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError, with: :internal_server_error
|
rescue_from(*Mastodon::HTTP_CONNECTION_ERRORS, with: :internal_server_error)
|
||||||
|
|
||||||
def show
|
def show
|
||||||
with_redis_lock("media_download:#{params[:id]}") do
|
with_redis_lock("media_download:#{params[:id]}") do
|
||||||
|
|
11
app/controllers/oauth/userinfo_controller.rb
Normal file
11
app/controllers/oauth/userinfo_controller.rb
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Oauth::UserinfoController < Api::BaseController
|
||||||
|
before_action -> { doorkeeper_authorize! :profile }, only: [:show]
|
||||||
|
before_action :require_user!
|
||||||
|
|
||||||
|
def show
|
||||||
|
@account = current_account
|
||||||
|
render json: @account, serializer: OauthUserinfoSerializer
|
||||||
|
end
|
||||||
|
end
|
|
@ -9,7 +9,7 @@ class Settings::ExportsController < Settings::BaseController
|
||||||
skip_before_action :require_functional!
|
skip_before_action :require_functional!
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@export = Export.new(current_account)
|
@export_summary = ExportSummary.new(preloaded_account)
|
||||||
@backups = current_user.backups
|
@backups = current_user.backups
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -25,4 +25,15 @@ class Settings::ExportsController < Settings::BaseController
|
||||||
|
|
||||||
redirect_to settings_export_path
|
redirect_to settings_export_path
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def preloaded_account
|
||||||
|
current_account.tap do |account|
|
||||||
|
ActiveRecord::Associations::Preloader.new(
|
||||||
|
records: [account],
|
||||||
|
associations: :account_stat
|
||||||
|
).call
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,7 +15,7 @@ module Settings
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
session[:new_otp_secret] = User.generate_otp_secret(32)
|
session[:new_otp_secret] = User.generate_otp_secret
|
||||||
|
|
||||||
redirect_to new_settings_two_factor_authentication_confirmation_path
|
redirect_to new_settings_two_factor_authentication_confirmation_path
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,7 +7,23 @@ module WellKnown
|
||||||
def show
|
def show
|
||||||
@webfinger_template = "#{webfinger_url}?resource={uri}"
|
@webfinger_template = "#{webfinger_url}?resource={uri}"
|
||||||
expires_in 3.days, public: true
|
expires_in 3.days, public: true
|
||||||
render content_type: 'application/xrd+xml', formats: [:xml]
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.any do
|
||||||
|
render content_type: 'application/xrd+xml', formats: [:xml]
|
||||||
|
end
|
||||||
|
|
||||||
|
format.json do
|
||||||
|
render json: {
|
||||||
|
links: [
|
||||||
|
{
|
||||||
|
rel: 'lrdd',
|
||||||
|
template: @webfinger_template,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -35,4 +35,11 @@ module Admin::ActionLogsHelper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def sorted_action_log_types
|
||||||
|
Admin::ActionLogFilter::ACTION_TYPE_MAP
|
||||||
|
.keys
|
||||||
|
.map { |key| [I18n.t("admin.action_logs.action_types.#{key}"), key] }
|
||||||
|
.sort_by(&:first)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,6 +18,11 @@ module Admin::DashboardHelper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def date_range(range)
|
||||||
|
[l(range.first), l(range.last)]
|
||||||
|
.join(' - ')
|
||||||
|
end
|
||||||
|
|
||||||
def relevant_account_timestamp(account)
|
def relevant_account_timestamp(account)
|
||||||
timestamp, exact = if account.user_current_sign_in_at && account.user_current_sign_in_at < 24.hours.ago
|
timestamp, exact = if account.user_current_sign_in_at && account.user_current_sign_in_at < 24.hours.ago
|
||||||
[account.user_current_sign_in_at, true]
|
[account.user_current_sign_in_at, true]
|
||||||
|
@ -25,6 +30,8 @@ module Admin::DashboardHelper
|
||||||
[account.user_current_sign_in_at, false]
|
[account.user_current_sign_in_at, false]
|
||||||
elsif account.user_pending?
|
elsif account.user_pending?
|
||||||
[account.user_created_at, true]
|
[account.user_created_at, true]
|
||||||
|
elsif account.suspended_at.present? && account.local? && account.user.nil?
|
||||||
|
[account.suspended_at, true]
|
||||||
elsif account.last_status_at.present?
|
elsif account.last_status_at.present?
|
||||||
[account.last_status_at, true]
|
[account.last_status_at, true]
|
||||||
else
|
else
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
module Admin::SettingsHelper
|
module Admin::SettingsHelper
|
||||||
def captcha_available?
|
def captcha_available?
|
||||||
ENV['HCAPTCHA_SECRET_KEY'].present? && ENV['HCAPTCHA_SITE_KEY'].present?
|
Rails.configuration.x.captcha.secret_key.present? && Rails.configuration.x.captcha.site_key.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def login_activity_title(activity)
|
def login_activity_title(activity)
|
||||||
|
|
|
@ -1,12 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module ApplicationHelper
|
module ApplicationHelper
|
||||||
DANGEROUS_SCOPES = %w(
|
|
||||||
read
|
|
||||||
write
|
|
||||||
follow
|
|
||||||
).freeze
|
|
||||||
|
|
||||||
RTL_LOCALES = %i(
|
RTL_LOCALES = %i(
|
||||||
ar
|
ar
|
||||||
ckb
|
ckb
|
||||||
|
@ -95,8 +89,11 @@ module ApplicationHelper
|
||||||
Rails.env.production? ? site_title : "#{site_title} (Dev)"
|
Rails.env.production? ? site_title : "#{site_title} (Dev)"
|
||||||
end
|
end
|
||||||
|
|
||||||
def class_for_scope(scope)
|
def label_for_scope(scope)
|
||||||
'scope-danger' if DANGEROUS_SCOPES.include?(scope.to_s)
|
safe_join [
|
||||||
|
tag.samp(scope, class: { 'scope-danger' => SessionActivation::DEFAULT_SCOPES.include?(scope.to_s) }),
|
||||||
|
tag.span(t("doorkeeper.scopes.#{scope}"), class: :hint),
|
||||||
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
def can?(action, record)
|
def can?(action, record)
|
||||||
|
@ -123,18 +120,6 @@ module ApplicationHelper
|
||||||
inline_svg_tag 'check.svg'
|
inline_svg_tag 'check.svg'
|
||||||
end
|
end
|
||||||
|
|
||||||
def visibility_icon(status)
|
|
||||||
if status.public_visibility?
|
|
||||||
material_symbol('globe', title: I18n.t('statuses.visibilities.public'))
|
|
||||||
elsif status.unlisted_visibility?
|
|
||||||
material_symbol('lock_open', title: I18n.t('statuses.visibilities.unlisted'))
|
|
||||||
elsif status.private_visibility? || status.limited_visibility?
|
|
||||||
material_symbol('lock', title: I18n.t('statuses.visibilities.private'))
|
|
||||||
elsif status.direct_visibility?
|
|
||||||
material_symbol('alternate_email', title: I18n.t('statuses.visibilities.direct'))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def interrelationships_icon(relationships, account_id)
|
def interrelationships_icon(relationships, account_id)
|
||||||
if relationships.following[account_id] && relationships.followed_by[account_id]
|
if relationships.following[account_id] && relationships.followed_by[account_id]
|
||||||
material_symbol('sync_alt', title: I18n.t('relationships.mutual'), class: 'active passive')
|
material_symbol('sync_alt', title: I18n.t('relationships.mutual'), class: 'active passive')
|
||||||
|
@ -243,6 +228,15 @@ module ApplicationHelper
|
||||||
full_asset_url(instance_presenter.mascot&.file&.url || frontend_asset_path('images/elephant_ui_plane.svg'))
|
full_asset_url(instance_presenter.mascot&.file&.url || frontend_asset_path('images/elephant_ui_plane.svg'))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def copyable_input(options = {})
|
||||||
|
tag.input(type: :text, maxlength: 999, spellcheck: false, readonly: true, **options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def recent_tag_usage(tag)
|
||||||
|
people = tag.history.aggregate(2.days.ago.to_date..Time.zone.today).accounts
|
||||||
|
I18n.t 'user_mailer.welcome.hashtags_recent_count', people: number_with_delimiter(people), count: people
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def storage_host_var
|
def storage_host_var
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module FormattingHelper
|
module FormattingHelper
|
||||||
|
SYNDICATED_EMOJI_STYLES = <<~CSS.squish
|
||||||
|
height: 1.1em;
|
||||||
|
margin: -.2ex .15em .2ex;
|
||||||
|
object-fit: contain;
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 1.1em;
|
||||||
|
CSS
|
||||||
|
|
||||||
def html_aware_format(text, local, options = {})
|
def html_aware_format(text, local, options = {})
|
||||||
HtmlAwareFormatter.new(text, local, options).to_s
|
HtmlAwareFormatter.new(text, local, options).to_s
|
||||||
end
|
end
|
||||||
|
@ -19,42 +27,33 @@ module FormattingHelper
|
||||||
module_function :extract_status_plain_text
|
module_function :extract_status_plain_text
|
||||||
|
|
||||||
def status_content_format(status)
|
def status_content_format(status)
|
||||||
html_aware_format(status.text, status.local?, preloaded_accounts: [status.account] + (status.respond_to?(:active_mentions) ? status.active_mentions.map(&:account) : []))
|
MastodonOTELTracer.in_span('HtmlAwareFormatter rendering') do |span|
|
||||||
|
span.add_attributes(
|
||||||
|
'app.formatter.content.type' => 'status',
|
||||||
|
'app.formatter.content.origin' => status.local? ? 'local' : 'remote'
|
||||||
|
)
|
||||||
|
|
||||||
|
html_aware_format(status.text, status.local?, preloaded_accounts: [status.account] + (status.respond_to?(:active_mentions) ? status.active_mentions.map(&:account) : []))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def rss_status_content_format(status)
|
def rss_status_content_format(status)
|
||||||
html = status_content_format(status)
|
|
||||||
|
|
||||||
before_html = if status.spoiler_text?
|
|
||||||
tag.p do
|
|
||||||
tag.strong do
|
|
||||||
I18n.t('rss.content_warning', locale: available_locale_or_nil(status.language) || I18n.default_locale)
|
|
||||||
end
|
|
||||||
|
|
||||||
status.spoiler_text
|
|
||||||
end + tag.hr
|
|
||||||
end
|
|
||||||
|
|
||||||
after_html = if status.preloadable_poll
|
|
||||||
tag.p do
|
|
||||||
safe_join(
|
|
||||||
status.preloadable_poll.options.map do |o|
|
|
||||||
tag.send(status.preloadable_poll.multiple? ? 'checkbox' : 'radio', o, disabled: true)
|
|
||||||
end,
|
|
||||||
tag.br
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
prerender_custom_emojis(
|
prerender_custom_emojis(
|
||||||
safe_join([before_html, html, after_html]),
|
wrapped_status_content_format(status),
|
||||||
status.emojis,
|
status.emojis,
|
||||||
style: 'width: 1.1em; height: 1.1em; object-fit: contain; vertical-align: middle; margin: -.2ex .15em .2ex'
|
style: SYNDICATED_EMOJI_STYLES
|
||||||
).to_str
|
).to_str
|
||||||
end
|
end
|
||||||
|
|
||||||
def account_bio_format(account)
|
def account_bio_format(account)
|
||||||
html_aware_format(account.note, account.local?)
|
MastodonOTELTracer.in_span('HtmlAwareFormatter rendering') do |span|
|
||||||
|
span.add_attributes(
|
||||||
|
'app.formatter.content.type' => 'account_bio',
|
||||||
|
'app.formatter.content.origin' => account.local? ? 'local' : 'remote'
|
||||||
|
)
|
||||||
|
|
||||||
|
html_aware_format(account.note, account.local?)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def account_field_value_format(field, with_rel_me: true)
|
def account_field_value_format(field, with_rel_me: true)
|
||||||
|
@ -64,4 +63,47 @@ module FormattingHelper
|
||||||
html_aware_format(field.value, field.account.local?, with_rel_me: with_rel_me, with_domains: true, multiline: false)
|
html_aware_format(field.value, field.account.local?, with_rel_me: with_rel_me, with_domains: true, multiline: false)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def wrapped_status_content_format(status)
|
||||||
|
safe_join [
|
||||||
|
rss_content_preroll(status),
|
||||||
|
status_content_format(status),
|
||||||
|
rss_content_postroll(status),
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
def rss_content_preroll(status)
|
||||||
|
if status.spoiler_text?
|
||||||
|
safe_join [
|
||||||
|
tag.p { spoiler_with_warning(status) },
|
||||||
|
tag.hr,
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def spoiler_with_warning(status)
|
||||||
|
safe_join [
|
||||||
|
tag.strong { I18n.t('rss.content_warning', locale: available_locale_or_nil(status.language) || I18n.default_locale) },
|
||||||
|
status.spoiler_text,
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
def rss_content_postroll(status)
|
||||||
|
if status.preloadable_poll
|
||||||
|
tag.p do
|
||||||
|
poll_option_tags(status)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def poll_option_tags(status)
|
||||||
|
safe_join(
|
||||||
|
status.preloadable_poll.options.map do |option|
|
||||||
|
tag.send(status.preloadable_poll.multiple? ? 'checkbox' : 'radio', option, disabled: true)
|
||||||
|
end,
|
||||||
|
tag.br
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -162,7 +162,7 @@ module LanguagesHelper
|
||||||
th: ['Thai', 'ไทย'].freeze,
|
th: ['Thai', 'ไทย'].freeze,
|
||||||
ti: ['Tigrinya', 'ትግርኛ'].freeze,
|
ti: ['Tigrinya', 'ትግርኛ'].freeze,
|
||||||
tk: ['Turkmen', 'Türkmen'].freeze,
|
tk: ['Turkmen', 'Türkmen'].freeze,
|
||||||
tl: ['Tagalog', 'Wikang Tagalog'].freeze,
|
tl: ['Tagalog', 'Tagalog'].freeze,
|
||||||
tn: ['Tswana', 'Setswana'].freeze,
|
tn: ['Tswana', 'Setswana'].freeze,
|
||||||
to: ['Tonga', 'faka Tonga'].freeze,
|
to: ['Tonga', 'faka Tonga'].freeze,
|
||||||
tr: ['Turkish', 'Türkçe'].freeze,
|
tr: ['Turkish', 'Türkçe'].freeze,
|
||||||
|
@ -193,6 +193,7 @@ module LanguagesHelper
|
||||||
ckb: ['Sorani (Kurdish)', 'سۆرانی'].freeze,
|
ckb: ['Sorani (Kurdish)', 'سۆرانی'].freeze,
|
||||||
cnr: ['Montenegrin', 'crnogorski'].freeze,
|
cnr: ['Montenegrin', 'crnogorski'].freeze,
|
||||||
csb: ['Kashubian', 'Kaszëbsczi'].freeze,
|
csb: ['Kashubian', 'Kaszëbsczi'].freeze,
|
||||||
|
gsw: ['Swiss German', 'Schwiizertütsch'].freeze,
|
||||||
jbo: ['Lojban', 'la .lojban.'].freeze,
|
jbo: ['Lojban', 'la .lojban.'].freeze,
|
||||||
kab: ['Kabyle', 'Taqbaylit'].freeze,
|
kab: ['Kabyle', 'Taqbaylit'].freeze,
|
||||||
ldn: ['Láadan', 'Láadan'].freeze,
|
ldn: ['Láadan', 'Láadan'].freeze,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module MediaComponentHelper
|
module MediaComponentHelper
|
||||||
def render_video_component(status, **options)
|
def render_video_component(status, **)
|
||||||
video = status.ordered_media_attachments.first
|
video = status.ordered_media_attachments.first
|
||||||
|
|
||||||
meta = video.file.meta || {}
|
meta = video.file.meta || {}
|
||||||
|
@ -18,14 +18,14 @@ module MediaComponentHelper
|
||||||
media: [
|
media: [
|
||||||
serialize_media_attachment(video),
|
serialize_media_attachment(video),
|
||||||
].as_json,
|
].as_json,
|
||||||
}.merge(**options)
|
}.merge(**)
|
||||||
|
|
||||||
react_component :video, component_params do
|
react_component :video, component_params do
|
||||||
render partial: 'statuses/attachment_list', locals: { attachments: status.ordered_media_attachments }
|
render partial: 'statuses/attachment_list', locals: { attachments: status.ordered_media_attachments }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_audio_component(status, **options)
|
def render_audio_component(status, **)
|
||||||
audio = status.ordered_media_attachments.first
|
audio = status.ordered_media_attachments.first
|
||||||
|
|
||||||
meta = audio.file.meta || {}
|
meta = audio.file.meta || {}
|
||||||
|
@ -38,19 +38,19 @@ module MediaComponentHelper
|
||||||
foregroundColor: meta.dig('colors', 'foreground'),
|
foregroundColor: meta.dig('colors', 'foreground'),
|
||||||
accentColor: meta.dig('colors', 'accent'),
|
accentColor: meta.dig('colors', 'accent'),
|
||||||
duration: meta.dig('original', 'duration'),
|
duration: meta.dig('original', 'duration'),
|
||||||
}.merge(**options)
|
}.merge(**)
|
||||||
|
|
||||||
react_component :audio, component_params do
|
react_component :audio, component_params do
|
||||||
render partial: 'statuses/attachment_list', locals: { attachments: status.ordered_media_attachments }
|
render partial: 'statuses/attachment_list', locals: { attachments: status.ordered_media_attachments }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_media_gallery_component(status, **options)
|
def render_media_gallery_component(status, **)
|
||||||
component_params = {
|
component_params = {
|
||||||
sensitive: sensitive_viewer?(status, current_account),
|
sensitive: sensitive_viewer?(status, current_account),
|
||||||
autoplay: prefers_autoplay?,
|
autoplay: prefers_autoplay?,
|
||||||
media: status.ordered_media_attachments.map { |a| serialize_media_attachment(a).as_json },
|
media: status.ordered_media_attachments.map { |a| serialize_media_attachment(a).as_json },
|
||||||
}.merge(**options)
|
}.merge(**)
|
||||||
|
|
||||||
react_component :media_gallery, component_params do
|
react_component :media_gallery, component_params do
|
||||||
render partial: 'statuses/attachment_list', locals: { attachments: status.ordered_media_attachments }
|
render partial: 'statuses/attachment_list', locals: { attachments: status.ordered_media_attachments }
|
||||||
|
|
|
@ -14,8 +14,8 @@ module RoutingHelper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def full_asset_url(source, **options)
|
def full_asset_url(source, **)
|
||||||
source = ActionController::Base.helpers.asset_url(source, **options) unless use_storage?
|
source = ActionController::Base.helpers.asset_url(source, **) unless use_storage?
|
||||||
|
|
||||||
URI.join(asset_host, source).to_s
|
URI.join(asset_host, source).to_s
|
||||||
end
|
end
|
||||||
|
@ -24,12 +24,12 @@ module RoutingHelper
|
||||||
Rails.configuration.action_controller.asset_host || root_url
|
Rails.configuration.action_controller.asset_host || root_url
|
||||||
end
|
end
|
||||||
|
|
||||||
def frontend_asset_path(source, **options)
|
def frontend_asset_path(source, **)
|
||||||
asset_pack_path("media/#{source}", **options)
|
asset_pack_path("media/#{source}", **)
|
||||||
end
|
end
|
||||||
|
|
||||||
def frontend_asset_url(source, **options)
|
def frontend_asset_url(source, **)
|
||||||
full_asset_url(frontend_asset_path(source, **options))
|
full_asset_url(frontend_asset_path(source, **))
|
||||||
end
|
end
|
||||||
|
|
||||||
def use_storage?
|
def use_storage?
|
||||||
|
|
|
@ -12,7 +12,7 @@ module StatusesHelper
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
def nothing_here(extra_classes = '')
|
def nothing_here(extra_classes = '')
|
||||||
content_tag(:div, class: "nothing-here #{extra_classes}") do
|
tag.div(class: ['nothing-here', extra_classes]) do
|
||||||
t('accounts.nothing_here')
|
t('accounts.nothing_here')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module WebfingerHelper
|
|
||||||
def webfinger!(uri)
|
|
||||||
Webfinger.new(uri).perform
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -327,31 +327,24 @@ Rails.delegate(document, '.input-copy button', 'click', ({ target }) => {
|
||||||
|
|
||||||
if (!input) return;
|
if (!input) return;
|
||||||
|
|
||||||
const oldReadOnly = input.readOnly;
|
navigator.clipboard
|
||||||
|
.writeText(input.value)
|
||||||
input.readOnly = false;
|
.then(() => {
|
||||||
input.focus();
|
|
||||||
input.select();
|
|
||||||
input.setSelectionRange(0, input.value.length);
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (document.execCommand('copy')) {
|
|
||||||
input.blur();
|
|
||||||
|
|
||||||
const parent = target.parentElement;
|
const parent = target.parentElement;
|
||||||
|
|
||||||
if (!parent) return;
|
if (parent) {
|
||||||
parent.classList.add('copied');
|
parent.classList.add('copied');
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
parent.classList.remove('copied');
|
parent.classList.remove('copied');
|
||||||
}, 700);
|
}, 700);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
input.readOnly = oldReadOnly;
|
return true;
|
||||||
|
})
|
||||||
|
.catch((error: unknown) => {
|
||||||
|
console.error(error);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const toggleSidebar = () => {
|
const toggleSidebar = () => {
|
||||||
|
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 5.6 KiB |
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg"><symbol id="mastodon-svg-logo" viewBox="0 0 216.4144 232.00976"><path d="M107.86523 0C78.203984.2425 49.672422 3.4535937 33.044922 11.089844c0 0-32.97656262 14.752031-32.97656262 65.082031 0 11.525-.224375 25.306175.140625 39.919925 1.19750002 49.22 9.02375002 97.72843 54.53124962 109.77343 20.9825 5.55375 38.99711 6.71547 53.505856 5.91797 26.31125-1.45875 41.08203-9.38867 41.08203-9.38867l-.86914-19.08984s-18.80171 5.92758-39.91796 5.20508c-20.921254-.7175-43.006879-2.25516-46.390629-27.94141-.3125-2.25625-.46875-4.66938-.46875-7.20313 0 0 20.536953 5.0204 46.564449 6.21289 15.915.73001 30.8393-.93343 45.99805-2.74218 29.07-3.47125 54.38125-21.3818 57.5625-37.74805 5.0125-25.78125 4.59961-62.916015 4.59961-62.916015 0-50.33-32.97461-65.082031-32.97461-65.082031C166.80539 3.4535938 138.255.2425 108.59375 0h-.72852zM74.296875 39.326172c12.355 0 21.710234 4.749297 27.896485 14.248047l6.01367 10.080078 6.01563-10.080078c6.185-9.49875 15.54023-14.248047 27.89648-14.248047 10.6775 0 19.28156 3.753672 25.85156 11.076172 6.36875 7.3225 9.53907 17.218828 9.53907 29.673828v60.941408h-24.14454V81.869141c0-12.46875-5.24453-18.798829-15.73828-18.798829-11.6025 0-17.41797 7.508516-17.41797 22.353516v32.375002H96.207031V85.423828c0-14.845-5.815468-22.353515-17.417969-22.353516-10.49375 0-15.740234 6.330079-15.740234 18.798829v59.148439H38.904297V80.076172c0-12.455 3.171016-22.351328 9.541015-29.673828 6.568751-7.3225 15.172813-11.076172 25.851563-11.076172z" /></symbol></svg>
|
|
Before Width: | Height: | Size: 1.5 KiB |
3
app/javascript/images/quote.svg
Normal file
3
app/javascript/images/quote.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="24" height="20" viewBox="0 0 24 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M23.933 2.82414C22.324 4.07931 21.0726 5.3569 20.1788 6.6569C19.3296 7.91207 18.905 9.1 18.905 10.2207C19.0838 10.131 19.3073 10.0862 19.5754 10.0862C19.8883 10.0414 20.1564 10.019 20.3799 10.019C21.4078 10.019 22.257 10.4448 22.9274 11.2966C23.6425 12.1034 24 13.1121 24 14.3224C24 15.8017 23.5084 17.0345 22.5251 18.0207C21.5419 19.0069 20.3129 19.5 18.838 19.5C17.2737 19.5 16.0447 18.9397 15.1508 17.819C14.257 16.6535 13.8101 15.1069 13.8101 13.1793C13.8101 10.8931 14.5028 8.62931 15.8883 6.38793C17.2737 4.14655 19.3073 2.01724 21.9888 0L23.933 2.82414ZM10.1229 2.82414C8.51397 4.07931 7.26257 5.3569 6.36872 6.6569C5.51955 7.91207 5.09497 9.1 5.09497 10.2207C5.27374 10.131 5.49721 10.0862 5.76536 10.0862C6.07821 10.0414 6.34637 10.019 6.56983 10.019C7.59777 10.019 8.44693 10.4448 9.11732 11.2966C9.8324 12.1034 10.1899 13.1121 10.1899 14.3224C10.1899 15.8017 9.69832 17.0345 8.71508 18.0207C7.73184 19.0069 6.50279 19.5 5.02793 19.5C3.46369 19.5 2.23464 18.9397 1.34078 17.819C0.446927 16.6535 0 15.1069 0 13.1793C0 10.8931 0.692738 8.62931 2.07821 6.38793C3.46369 4.14655 5.49721 2.01724 8.17877 0L10.1229 2.82414Z" fill="currentColor" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
|
@ -37,8 +37,7 @@ export const synchronouslySubmitMarkers = createAppAsyncThunk(
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
} else if ('sendBeacon' in navigator) {
|
||||||
} else if ('navigator' && 'sendBeacon' in navigator) {
|
|
||||||
// Failing that, we can use sendBeacon, but we have to encode the data as
|
// Failing that, we can use sendBeacon, but we have to encode the data as
|
||||||
// FormData for DoorKeeper to recognize the token.
|
// FormData for DoorKeeper to recognize the token.
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
|
|
@ -8,6 +8,7 @@ import type { ApiAccountJSON } from 'mastodon/api_types/accounts';
|
||||||
import type {
|
import type {
|
||||||
ApiNotificationGroupJSON,
|
ApiNotificationGroupJSON,
|
||||||
ApiNotificationJSON,
|
ApiNotificationJSON,
|
||||||
|
NotificationType,
|
||||||
} from 'mastodon/api_types/notifications';
|
} from 'mastodon/api_types/notifications';
|
||||||
import { allNotificationTypes } from 'mastodon/api_types/notifications';
|
import { allNotificationTypes } from 'mastodon/api_types/notifications';
|
||||||
import type { ApiStatusJSON } from 'mastodon/api_types/statuses';
|
import type { ApiStatusJSON } from 'mastodon/api_types/statuses';
|
||||||
|
@ -15,6 +16,7 @@ import { usePendingItems } from 'mastodon/initial_state';
|
||||||
import type { NotificationGap } from 'mastodon/reducers/notification_groups';
|
import type { NotificationGap } from 'mastodon/reducers/notification_groups';
|
||||||
import {
|
import {
|
||||||
selectSettingsNotificationsExcludedTypes,
|
selectSettingsNotificationsExcludedTypes,
|
||||||
|
selectSettingsNotificationsGroupFollows,
|
||||||
selectSettingsNotificationsQuickFilterActive,
|
selectSettingsNotificationsQuickFilterActive,
|
||||||
selectSettingsNotificationsShows,
|
selectSettingsNotificationsShows,
|
||||||
} from 'mastodon/selectors/settings';
|
} from 'mastodon/selectors/settings';
|
||||||
|
@ -68,13 +70,19 @@ function dispatchAssociatedRecords(
|
||||||
dispatch(importFetchedStatuses(fetchedStatuses));
|
dispatch(importFetchedStatuses(fetchedStatuses));
|
||||||
}
|
}
|
||||||
|
|
||||||
const supportedGroupedNotificationTypes = ['favourite', 'reblog'];
|
function selectNotificationGroupedTypes(state: RootState) {
|
||||||
|
const types: NotificationType[] = ['favourite', 'reblog'];
|
||||||
|
|
||||||
|
if (selectSettingsNotificationsGroupFollows(state)) types.push('follow');
|
||||||
|
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
export const fetchNotifications = createDataLoadingThunk(
|
export const fetchNotifications = createDataLoadingThunk(
|
||||||
'notificationGroups/fetch',
|
'notificationGroups/fetch',
|
||||||
async (_params, { getState }) =>
|
async (_params, { getState }) =>
|
||||||
apiFetchNotificationGroups({
|
apiFetchNotificationGroups({
|
||||||
grouped_types: supportedGroupedNotificationTypes,
|
grouped_types: selectNotificationGroupedTypes(getState()),
|
||||||
exclude_types: getExcludedTypes(getState()),
|
exclude_types: getExcludedTypes(getState()),
|
||||||
}),
|
}),
|
||||||
({ notifications, accounts, statuses }, { dispatch }) => {
|
({ notifications, accounts, statuses }, { dispatch }) => {
|
||||||
|
@ -98,7 +106,7 @@ export const fetchNotificationsGap = createDataLoadingThunk(
|
||||||
'notificationGroups/fetchGap',
|
'notificationGroups/fetchGap',
|
||||||
async (params: { gap: NotificationGap }, { getState }) =>
|
async (params: { gap: NotificationGap }, { getState }) =>
|
||||||
apiFetchNotificationGroups({
|
apiFetchNotificationGroups({
|
||||||
grouped_types: supportedGroupedNotificationTypes,
|
grouped_types: selectNotificationGroupedTypes(getState()),
|
||||||
max_id: params.gap.maxId,
|
max_id: params.gap.maxId,
|
||||||
exclude_types: getExcludedTypes(getState()),
|
exclude_types: getExcludedTypes(getState()),
|
||||||
}),
|
}),
|
||||||
|
@ -115,7 +123,7 @@ export const pollRecentNotifications = createDataLoadingThunk(
|
||||||
'notificationGroups/pollRecentNotifications',
|
'notificationGroups/pollRecentNotifications',
|
||||||
async (_params, { getState }) => {
|
async (_params, { getState }) => {
|
||||||
return apiFetchNotificationGroups({
|
return apiFetchNotificationGroups({
|
||||||
grouped_types: supportedGroupedNotificationTypes,
|
grouped_types: selectNotificationGroupedTypes(getState()),
|
||||||
max_id: undefined,
|
max_id: undefined,
|
||||||
exclude_types: getExcludedTypes(getState()),
|
exclude_types: getExcludedTypes(getState()),
|
||||||
// In slow mode, we don't want to include notifications that duplicate the already-displayed ones
|
// In slow mode, we don't want to include notifications that duplicate the already-displayed ones
|
||||||
|
@ -164,7 +172,10 @@ export const processNewNotificationForGroups = createAppAsyncThunk(
|
||||||
|
|
||||||
dispatchAssociatedRecords(dispatch, [notification]);
|
dispatchAssociatedRecords(dispatch, [notification]);
|
||||||
|
|
||||||
return notification;
|
return {
|
||||||
|
notification,
|
||||||
|
groupedTypes: selectNotificationGroupedTypes(state),
|
||||||
|
};
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -106,12 +106,13 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti
|
||||||
dispatch(processNewNotificationForGroups(notificationJSON));
|
dispatch(processNewNotificationForGroups(notificationJSON));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'notifications_merged':
|
case 'notifications_merged': {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
if (state.notifications.top || !state.notifications.mounted)
|
if (state.notifications.top || !state.notifications.mounted)
|
||||||
dispatch(expandNotifications({ forceLoad: true, maxId: undefined }));
|
dispatch(expandNotifications({ forceLoad: true, maxId: undefined }));
|
||||||
dispatch(refreshStaleNotificationGroups());
|
dispatch(refreshStaleNotificationGroups());
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 'conversation':
|
case 'conversation':
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
dispatch(updateConversations(JSON.parse(data.payload)));
|
dispatch(updateConversations(JSON.parse(data.payload)));
|
||||||
|
|
|
@ -13,7 +13,7 @@ export interface ApiAccountRoleJSON {
|
||||||
}
|
}
|
||||||
|
|
||||||
// See app/serializers/rest/account_serializer.rb
|
// See app/serializers/rest/account_serializer.rb
|
||||||
export interface ApiAccountJSON {
|
export interface BaseApiAccountJSON {
|
||||||
acct: string;
|
acct: string;
|
||||||
avatar: string;
|
avatar: string;
|
||||||
avatar_static: string;
|
avatar_static: string;
|
||||||
|
@ -45,3 +45,12 @@ export interface ApiAccountJSON {
|
||||||
memorial?: boolean;
|
memorial?: boolean;
|
||||||
hide_collections: boolean;
|
hide_collections: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See app/serializers/rest/muted_account_serializer.rb
|
||||||
|
export interface ApiMutedAccountJSON extends BaseApiAccountJSON {
|
||||||
|
mute_expires_at?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For now, we have the same type representing both `Account` and `MutedAccount`
|
||||||
|
// objects, but we should refactor this in the future.
|
||||||
|
export type ApiAccountJSON = ApiMutedAccountJSON;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
exports[`<Avatar /> Autoplay renders a animated avatar 1`] = `
|
exports[`<Avatar /> Autoplay renders a animated avatar 1`] = `
|
||||||
<div
|
<div
|
||||||
className="account__avatar"
|
className="account__avatar account__avatar--loading"
|
||||||
onMouseEnter={[Function]}
|
onMouseEnter={[Function]}
|
||||||
onMouseLeave={[Function]}
|
onMouseLeave={[Function]}
|
||||||
style={
|
style={
|
||||||
|
@ -14,6 +14,8 @@ exports[`<Avatar /> Autoplay renders a animated avatar 1`] = `
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt=""
|
alt=""
|
||||||
|
onError={[Function]}
|
||||||
|
onLoad={[Function]}
|
||||||
src="/animated/alice.gif"
|
src="/animated/alice.gif"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -21,7 +23,7 @@ exports[`<Avatar /> Autoplay renders a animated avatar 1`] = `
|
||||||
|
|
||||||
exports[`<Avatar /> Still renders a still avatar 1`] = `
|
exports[`<Avatar /> Still renders a still avatar 1`] = `
|
||||||
<div
|
<div
|
||||||
className="account__avatar"
|
className="account__avatar account__avatar--loading"
|
||||||
onMouseEnter={[Function]}
|
onMouseEnter={[Function]}
|
||||||
onMouseLeave={[Function]}
|
onMouseLeave={[Function]}
|
||||||
style={
|
style={
|
||||||
|
@ -33,6 +35,8 @@ exports[`<Avatar /> Still renders a still avatar 1`] = `
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt=""
|
alt=""
|
||||||
|
onError={[Function]}
|
||||||
|
onLoad={[Function]}
|
||||||
src="/static/alice.jpg"
|
src="/static/alice.jpg"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
|
import { useState, useCallback } from 'react';
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import { useHovering } from 'mastodon/../hooks/useHovering';
|
||||||
|
import { autoPlayGif } from 'mastodon/initial_state';
|
||||||
import type { Account } from 'mastodon/models/account';
|
import type { Account } from 'mastodon/models/account';
|
||||||
|
|
||||||
import { useHovering } from '../../hooks/useHovering';
|
|
||||||
import { autoPlayGif } from '../initial_state';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
account: Account | undefined; // FIXME: remove `undefined` once we know for sure its always there
|
account: Account | undefined; // FIXME: remove `undefined` once we know for sure its always there
|
||||||
size: number;
|
size: number;
|
||||||
|
@ -25,6 +26,8 @@ export const Avatar: React.FC<Props> = ({
|
||||||
counterBorderColor,
|
counterBorderColor,
|
||||||
}) => {
|
}) => {
|
||||||
const { hovering, handleMouseEnter, handleMouseLeave } = useHovering(animate);
|
const { hovering, handleMouseEnter, handleMouseLeave } = useHovering(animate);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [error, setError] = useState(false);
|
||||||
|
|
||||||
const style = {
|
const style = {
|
||||||
...styleFromParent,
|
...styleFromParent,
|
||||||
|
@ -37,16 +40,28 @@ export const Avatar: React.FC<Props> = ({
|
||||||
? account?.get('avatar')
|
? account?.get('avatar')
|
||||||
: account?.get('avatar_static');
|
: account?.get('avatar_static');
|
||||||
|
|
||||||
|
const handleLoad = useCallback(() => {
|
||||||
|
setLoading(false);
|
||||||
|
}, [setLoading]);
|
||||||
|
|
||||||
|
const handleError = useCallback(() => {
|
||||||
|
setError(true);
|
||||||
|
}, [setError]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames('account__avatar', {
|
className={classNames('account__avatar', {
|
||||||
'account__avatar-inline': inline,
|
'account__avatar--inline': inline,
|
||||||
|
'account__avatar--loading': loading,
|
||||||
})}
|
})}
|
||||||
onMouseEnter={handleMouseEnter}
|
onMouseEnter={handleMouseEnter}
|
||||||
onMouseLeave={handleMouseLeave}
|
onMouseLeave={handleMouseLeave}
|
||||||
style={style}
|
style={style}
|
||||||
>
|
>
|
||||||
{src && <img src={src} alt='' />}
|
{src && !error && (
|
||||||
|
<img src={src} alt='' onLoad={handleLoad} onError={handleError} />
|
||||||
|
)}
|
||||||
|
|
||||||
{counter && (
|
{counter && (
|
||||||
<div
|
<div
|
||||||
className='account__avatar__counter'
|
className='account__avatar__counter'
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { PropsWithChildren } from 'react';
|
import type { PropsWithChildren, JSX } from 'react';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
|
@ -8,7 +8,7 @@ export const ContentWarning: React.FC<{
|
||||||
<StatusBanner
|
<StatusBanner
|
||||||
expanded={expanded}
|
expanded={expanded}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
variant={BannerVariant.Yellow}
|
variant={BannerVariant.Warning}
|
||||||
>
|
>
|
||||||
<p dangerouslySetInnerHTML={{ __html: text }} />
|
<p dangerouslySetInnerHTML={{ __html: text }} />
|
||||||
</StatusBanner>
|
</StatusBanner>
|
||||||
|
|
|
@ -10,13 +10,16 @@ export const FilterWarning: React.FC<{
|
||||||
<StatusBanner
|
<StatusBanner
|
||||||
expanded={expanded}
|
expanded={expanded}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
variant={BannerVariant.Blue}
|
variant={BannerVariant.Filter}
|
||||||
>
|
>
|
||||||
<p>
|
<p>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='filter_warning.matches_filter'
|
id='filter_warning.matches_filter'
|
||||||
defaultMessage='Matches filter “{title}”'
|
defaultMessage='Matches filter “<span>{title}</span>”'
|
||||||
values={{ title }}
|
values={{
|
||||||
|
title,
|
||||||
|
span: (chunks) => <span className='filter-name'>{chunks}</span>,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
</StatusBanner>
|
</StatusBanner>
|
||||||
|
|
|
@ -196,7 +196,7 @@ class Item extends PureComponent {
|
||||||
|
|
||||||
{visible && thumbnail}
|
{visible && thumbnail}
|
||||||
|
|
||||||
{badges && (
|
{visible && badges && (
|
||||||
<div className='media-gallery__item__badges'>
|
<div className='media-gallery__item__badges'>
|
||||||
{badges}
|
{badges}
|
||||||
</div>
|
</div>
|
||||||
|
@ -336,14 +336,14 @@ class MediaGallery extends PureComponent {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`media-gallery media-gallery--layout-${size}`} style={style} ref={this.handleRef}>
|
<div className={`media-gallery media-gallery--layout-${size}`} style={style} ref={this.handleRef}>
|
||||||
|
{children}
|
||||||
|
|
||||||
{(!visible || uncached) && (
|
{(!visible || uncached) && (
|
||||||
<div className={classNames('spoiler-button', { 'spoiler-button--click-thru': uncached })}>
|
<div className={classNames('spoiler-button', { 'spoiler-button--click-thru': uncached })}>
|
||||||
{spoilerButton}
|
{spoilerButton}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{children}
|
|
||||||
|
|
||||||
{(visible && !uncached) && (
|
{(visible && !uncached) && (
|
||||||
<div className='media-gallery__actions'>
|
<div className='media-gallery__actions'>
|
||||||
<button className='media-gallery__actions__pill' onClick={this.handleOpen}><FormattedMessage id='media_gallery.hide' defaultMessage='Hide' /></button>
|
<button className='media-gallery__actions__pill' onClick={this.handleOpen}><FormattedMessage id='media_gallery.hide' defaultMessage='Hide' /></button>
|
||||||
|
|
|
@ -41,12 +41,14 @@ const makeEmojiMap = record => record.get('emojis').reduce((obj, emoji) => {
|
||||||
class Poll extends ImmutablePureComponent {
|
class Poll extends ImmutablePureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
identity: identityContextPropShape,
|
identity: identityContextPropShape,
|
||||||
poll: ImmutablePropTypes.map,
|
poll: ImmutablePropTypes.map.isRequired,
|
||||||
|
status: ImmutablePropTypes.map.isRequired,
|
||||||
lang: PropTypes.string,
|
lang: PropTypes.string,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
disabled: PropTypes.bool,
|
disabled: PropTypes.bool,
|
||||||
refresh: PropTypes.func,
|
refresh: PropTypes.func,
|
||||||
onVote: PropTypes.func,
|
onVote: PropTypes.func,
|
||||||
|
onInteractionModal: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
|
@ -117,7 +119,11 @@ class Poll extends ImmutablePureComponent {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.props.onVote(Object.keys(this.state.selected));
|
if (this.props.identity.signedIn) {
|
||||||
|
this.props.onVote(Object.keys(this.state.selected));
|
||||||
|
} else {
|
||||||
|
this.props.onInteractionModal('vote', this.props.status);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
handleRefresh = () => {
|
handleRefresh = () => {
|
||||||
|
@ -232,7 +238,7 @@ class Poll extends ImmutablePureComponent {
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div className='poll__footer'>
|
<div className='poll__footer'>
|
||||||
{!showResults && <button className='button button-secondary' disabled={disabled || !this.props.identity.signedIn} onClick={this.handleVote}><FormattedMessage id='poll.vote' defaultMessage='Vote' /></button>}
|
{!showResults && <button className='button button-secondary' disabled={disabled} onClick={this.handleVote}><FormattedMessage id='poll.vote' defaultMessage='Vote' /></button>}
|
||||||
{!showResults && <><button className='poll__link' onClick={this.handleReveal}><FormattedMessage id='poll.reveal' defaultMessage='See results' /></button> · </>}
|
{!showResults && <><button className='poll__link' onClick={this.handleReveal}><FormattedMessage id='poll.reveal' defaultMessage='See results' /></button> · </>}
|
||||||
{showResults && !this.props.disabled && <><button className='poll__link' onClick={this.handleRefresh}><FormattedMessage id='poll.refresh' defaultMessage='Refresh' /></button> · </>}
|
{showResults && !this.props.disabled && <><button className='poll__link' onClick={this.handleRefresh}><FormattedMessage id='poll.refresh' defaultMessage='Refresh' /></button> · </>}
|
||||||
{votesCount}
|
{votesCount}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
import type { JSX } from 'react';
|
||||||
|
|
||||||
import { FormattedMessage, FormattedNumber } from 'react-intl';
|
import { FormattedMessage, FormattedNumber } from 'react-intl';
|
||||||
|
|
||||||
|
|
|
@ -449,7 +449,7 @@ class Status extends ImmutablePureComponent {
|
||||||
} else if (status.get('media_attachments').size > 0) {
|
} else if (status.get('media_attachments').size > 0) {
|
||||||
const language = status.getIn(['translation', 'language']) || status.get('language');
|
const language = status.getIn(['translation', 'language']) || status.get('language');
|
||||||
|
|
||||||
if (['image', 'gifv'].includes(status.getIn(['media_attachments', 0, 'type'])) || status.get('media_attachments').size > 1) {
|
if (['image', 'gifv', 'unknown'].includes(status.getIn(['media_attachments', 0, 'type'])) || status.get('media_attachments').size > 1) {
|
||||||
media = (
|
media = (
|
||||||
<Bundle fetchComponent={MediaGallery} loading={this.renderLoadingMediaGallery}>
|
<Bundle fetchComponent={MediaGallery} loading={this.renderLoadingMediaGallery}>
|
||||||
{Component => (
|
{Component => (
|
||||||
|
|
|
@ -264,7 +264,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||||
menu.push({ text: intl.formatMessage(messages.share), action: this.handleShareClick });
|
menu.push({ text: intl.formatMessage(messages.share), action: this.handleShareClick });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (publicStatus && (signedIn || !isRemote)) {
|
if (publicStatus && !isRemote) {
|
||||||
menu.push({ text: intl.formatMessage(messages.embed), action: this.handleEmbed });
|
menu.push({ text: intl.formatMessage(messages.embed), action: this.handleEmbed });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
export enum BannerVariant {
|
export enum BannerVariant {
|
||||||
Yellow = 'yellow',
|
Warning = 'warning',
|
||||||
Blue = 'blue',
|
Filter = 'filter',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const StatusBanner: React.FC<{
|
export const StatusBanner: React.FC<{
|
||||||
|
@ -11,9 +11,9 @@ export const StatusBanner: React.FC<{
|
||||||
expanded?: boolean;
|
expanded?: boolean;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
}> = ({ children, variant, expanded, onClick }) => (
|
}> = ({ children, variant, expanded, onClick }) => (
|
||||||
<div
|
<label
|
||||||
className={
|
className={
|
||||||
variant === BannerVariant.Yellow
|
variant === BannerVariant.Warning
|
||||||
? 'content-warning'
|
? 'content-warning'
|
||||||
: 'content-warning content-warning--filter'
|
: 'content-warning content-warning--filter'
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,11 @@ export const StatusBanner: React.FC<{
|
||||||
id='content_warning.hide'
|
id='content_warning.hide'
|
||||||
defaultMessage='Hide post'
|
defaultMessage='Hide post'
|
||||||
/>
|
/>
|
||||||
|
) : variant === BannerVariant.Warning ? (
|
||||||
|
<FormattedMessage
|
||||||
|
id='content_warning.show_more'
|
||||||
|
defaultMessage='Show more'
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='content_warning.show'
|
id='content_warning.show'
|
||||||
|
@ -33,5 +38,5 @@ export const StatusBanner: React.FC<{
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</label>
|
||||||
);
|
);
|
||||||
|
|
|
@ -245,7 +245,7 @@ class StatusContent extends PureComponent {
|
||||||
);
|
);
|
||||||
|
|
||||||
const poll = !!status.get('poll') && (
|
const poll = !!status.get('poll') && (
|
||||||
<PollContainer pollId={status.get('poll')} lang={language} />
|
<PollContainer pollId={status.get('poll')} status={status} lang={language} />
|
||||||
);
|
);
|
||||||
|
|
||||||
if (this.props.onClick) {
|
if (this.props.onClick) {
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
|
|
||||||
|
import { openModal } from 'mastodon/actions/modal';
|
||||||
import { fetchPoll, vote } from 'mastodon/actions/polls';
|
import { fetchPoll, vote } from 'mastodon/actions/polls';
|
||||||
import Poll from 'mastodon/components/poll';
|
import Poll from 'mastodon/components/poll';
|
||||||
|
|
||||||
|
@ -17,6 +18,17 @@ const mapDispatchToProps = (dispatch, { pollId }) => ({
|
||||||
onVote (choices) {
|
onVote (choices) {
|
||||||
dispatch(vote(pollId, choices));
|
dispatch(vote(pollId, choices));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onInteractionModal (type, status) {
|
||||||
|
dispatch(openModal({
|
||||||
|
modalType: 'INTERACTION',
|
||||||
|
modalProps: {
|
||||||
|
type,
|
||||||
|
accountId: status.getIn(['account', 'id']),
|
||||||
|
url: status.get('uri'),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapStateToProps = (state, { pollId }) => ({
|
const mapStateToProps = (state, { pollId }) => ({
|
||||||
|
|
|
@ -21,9 +21,11 @@ class ColumnSettings extends PureComponent {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='column-settings'>
|
<div className='column-settings'>
|
||||||
<div className='column-settings__row'>
|
<section>
|
||||||
<SettingToggle settings={settings} settingPath={['other', 'onlyMedia']} onChange={onChange} label={<FormattedMessage id='community.column_settings.media_only' defaultMessage='Media only' />} />
|
<div className='column-settings__row'>
|
||||||
</div>
|
<SettingToggle settings={settings} settingPath={['other', 'onlyMedia']} onChange={onChange} label={<FormattedMessage id='community.column_settings.media_only' defaultMessage='Media only' />} />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ const messages = defineMessages({
|
||||||
minutes: { id: 'intervals.full.minutes', defaultMessage: '{number, plural, one {# minute} other {# minutes}}' },
|
minutes: { id: 'intervals.full.minutes', defaultMessage: '{number, plural, one {# minute} other {# minutes}}' },
|
||||||
hours: { id: 'intervals.full.hours', defaultMessage: '{number, plural, one {# hour} other {# hours}}' },
|
hours: { id: 'intervals.full.hours', defaultMessage: '{number, plural, one {# hour} other {# hours}}' },
|
||||||
days: { id: 'intervals.full.days', defaultMessage: '{number, plural, one {# day} other {# days}}' },
|
days: { id: 'intervals.full.days', defaultMessage: '{number, plural, one {# day} other {# days}}' },
|
||||||
singleChoice: { id: 'compose_form.poll.single', defaultMessage: 'Pick one' },
|
singleChoice: { id: 'compose_form.poll.single', defaultMessage: 'Single choice' },
|
||||||
multipleChoice: { id: 'compose_form.poll.multiple', defaultMessage: 'Multiple choice' },
|
multipleChoice: { id: 'compose_form.poll.multiple', defaultMessage: 'Multiple choice' },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -129,8 +129,13 @@ export const InlineFollowSuggestions = ({ hidden }) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setCanScrollLeft(bodyRef.current.scrollLeft > 0);
|
if (getComputedStyle(bodyRef.current).direction === 'rtl') {
|
||||||
setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth);
|
setCanScrollLeft((bodyRef.current.clientWidth - bodyRef.current.scrollLeft) < bodyRef.current.scrollWidth);
|
||||||
|
setCanScrollRight(bodyRef.current.scrollLeft < 0);
|
||||||
|
} else {
|
||||||
|
setCanScrollLeft(bodyRef.current.scrollLeft > 0);
|
||||||
|
setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth);
|
||||||
|
}
|
||||||
}, [setCanScrollRight, setCanScrollLeft, bodyRef, suggestions]);
|
}, [setCanScrollRight, setCanScrollLeft, bodyRef, suggestions]);
|
||||||
|
|
||||||
const handleLeftNav = useCallback(() => {
|
const handleLeftNav = useCallback(() => {
|
||||||
|
@ -146,8 +151,13 @@ export const InlineFollowSuggestions = ({ hidden }) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setCanScrollLeft(bodyRef.current.scrollLeft > 0);
|
if (getComputedStyle(bodyRef.current).direction === 'rtl') {
|
||||||
setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth);
|
setCanScrollLeft((bodyRef.current.clientWidth - bodyRef.current.scrollLeft) < bodyRef.current.scrollWidth);
|
||||||
|
setCanScrollRight(bodyRef.current.scrollLeft < 0);
|
||||||
|
} else {
|
||||||
|
setCanScrollLeft(bodyRef.current.scrollLeft > 0);
|
||||||
|
setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth);
|
||||||
|
}
|
||||||
}, [setCanScrollRight, setCanScrollLeft, bodyRef]);
|
}, [setCanScrollRight, setCanScrollLeft, bodyRef]);
|
||||||
|
|
||||||
const handleDismiss = useCallback(() => {
|
const handleDismiss = useCallback(() => {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { throttle, escapeRegExp } from 'lodash';
|
import { throttle, escapeRegExp } from 'lodash';
|
||||||
|
|
||||||
|
import InsertChartIcon from '@/material-icons/400-24px/insert_chart.svg?react';
|
||||||
import PersonAddIcon from '@/material-icons/400-24px/person_add.svg?react';
|
import PersonAddIcon from '@/material-icons/400-24px/person_add.svg?react';
|
||||||
import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react';
|
import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react';
|
||||||
import ReplyIcon from '@/material-icons/400-24px/reply.svg?react';
|
import ReplyIcon from '@/material-icons/400-24px/reply.svg?react';
|
||||||
|
@ -340,7 +341,7 @@ class InteractionModal extends React.PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
displayNameHtml: PropTypes.string,
|
displayNameHtml: PropTypes.string,
|
||||||
url: PropTypes.string,
|
url: PropTypes.string,
|
||||||
type: PropTypes.oneOf(['reply', 'reblog', 'favourite', 'follow']),
|
type: PropTypes.oneOf(['reply', 'reblog', 'favourite', 'follow', 'vote']),
|
||||||
onSignupClick: PropTypes.func.isRequired,
|
onSignupClick: PropTypes.func.isRequired,
|
||||||
signupUrl: PropTypes.string.isRequired,
|
signupUrl: PropTypes.string.isRequired,
|
||||||
};
|
};
|
||||||
|
@ -377,6 +378,11 @@ class InteractionModal extends React.PureComponent {
|
||||||
title = <FormattedMessage id='interaction_modal.title.follow' defaultMessage='Follow {name}' values={{ name }} />;
|
title = <FormattedMessage id='interaction_modal.title.follow' defaultMessage='Follow {name}' values={{ name }} />;
|
||||||
actionDescription = <FormattedMessage id='interaction_modal.description.follow' defaultMessage='With an account on Mastodon, you can follow {name} to receive their posts in your home feed.' values={{ name }} />;
|
actionDescription = <FormattedMessage id='interaction_modal.description.follow' defaultMessage='With an account on Mastodon, you can follow {name} to receive their posts in your home feed.' values={{ name }} />;
|
||||||
break;
|
break;
|
||||||
|
case 'vote':
|
||||||
|
icon = <Icon id='tasks' icon={InsertChartIcon} />;
|
||||||
|
title = <FormattedMessage id='interaction_modal.title.vote' defaultMessage="Vote in {name}'s poll" values={{ name }} />;
|
||||||
|
actionDescription = <FormattedMessage id='interaction_modal.description.vote' defaultMessage='With an account on Mastodon, you can vote in this poll.' />;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let signupButton;
|
let signupButton;
|
||||||
|
|
|
@ -38,6 +38,7 @@ class ColumnSettings extends PureComponent {
|
||||||
const alertStr = <FormattedMessage id='notifications.column_settings.alert' defaultMessage='Desktop notifications' />;
|
const alertStr = <FormattedMessage id='notifications.column_settings.alert' defaultMessage='Desktop notifications' />;
|
||||||
const showStr = <FormattedMessage id='notifications.column_settings.show' defaultMessage='Show in column' />;
|
const showStr = <FormattedMessage id='notifications.column_settings.show' defaultMessage='Show in column' />;
|
||||||
const soundStr = <FormattedMessage id='notifications.column_settings.sound' defaultMessage='Play sound' />;
|
const soundStr = <FormattedMessage id='notifications.column_settings.sound' defaultMessage='Play sound' />;
|
||||||
|
const groupStr = <FormattedMessage id='notifications.column_settings.group' defaultMessage='Group' />;
|
||||||
|
|
||||||
const showPushSettings = pushSettings.get('browserSupport') && pushSettings.get('isSubscribed');
|
const showPushSettings = pushSettings.get('browserSupport') && pushSettings.get('isSubscribed');
|
||||||
const pushStr = showPushSettings && <FormattedMessage id='notifications.column_settings.push' defaultMessage='Push notifications' />;
|
const pushStr = showPushSettings && <FormattedMessage id='notifications.column_settings.push' defaultMessage='Push notifications' />;
|
||||||
|
@ -94,6 +95,7 @@ class ColumnSettings extends PureComponent {
|
||||||
{showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingPath={['alerts', 'follow']} onChange={this.onPushChange} label={pushStr} />}
|
{showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingPath={['alerts', 'follow']} onChange={this.onPushChange} label={pushStr} />}
|
||||||
<SettingToggle prefix='notifications' settings={settings} settingPath={['shows', 'follow']} onChange={onChange} label={showStr} />
|
<SettingToggle prefix='notifications' settings={settings} settingPath={['shows', 'follow']} onChange={onChange} label={showStr} />
|
||||||
<SettingToggle prefix='notifications' settings={settings} settingPath={['sounds', 'follow']} onChange={onChange} label={soundStr} />
|
<SettingToggle prefix='notifications' settings={settings} settingPath={['sounds', 'follow']} onChange={onChange} label={soundStr} />
|
||||||
|
<SettingToggle prefix='notifications' settings={settings} settingPath={['group', 'follow']} onChange={onChange} label={groupStr} />
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
|
@ -56,11 +56,12 @@ const mapDispatchToProps = (dispatch) => ({
|
||||||
} else {
|
} else {
|
||||||
dispatch(changeSetting(['notifications', ...path], checked));
|
dispatch(changeSetting(['notifications', ...path], checked));
|
||||||
}
|
}
|
||||||
} else if(path[0] === 'groupingBeta') {
|
|
||||||
dispatch(changeSetting(['notifications', ...path], checked));
|
|
||||||
dispatch(initializeNotifications());
|
|
||||||
} else {
|
} else {
|
||||||
dispatch(changeSetting(['notifications', ...path], checked));
|
dispatch(changeSetting(['notifications', ...path], checked));
|
||||||
|
|
||||||
|
if(path[0] === 'group' && path[1] === 'follow') {
|
||||||
|
dispatch(initializeNotifications());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,21 @@
|
||||||
|
import type { JSX } from 'react';
|
||||||
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import PersonAddIcon from '@/material-icons/400-24px/person_add-fill.svg?react';
|
import PersonAddIcon from '@/material-icons/400-24px/person_add-fill.svg?react';
|
||||||
import { FollowersCounter } from 'mastodon/components/counters';
|
import { FollowersCounter } from 'mastodon/components/counters';
|
||||||
import { FollowButton } from 'mastodon/components/follow_button';
|
import { FollowButton } from 'mastodon/components/follow_button';
|
||||||
import { ShortNumber } from 'mastodon/components/short_number';
|
import { ShortNumber } from 'mastodon/components/short_number';
|
||||||
|
import { me } from 'mastodon/initial_state';
|
||||||
import type { NotificationGroupFollow } from 'mastodon/models/notification_group';
|
import type { NotificationGroupFollow } from 'mastodon/models/notification_group';
|
||||||
import { useAppSelector } from 'mastodon/store';
|
import { useAppSelector } from 'mastodon/store';
|
||||||
|
|
||||||
import type { LabelRenderer } from './notification_group_with_status';
|
import type { LabelRenderer } from './notification_group_with_status';
|
||||||
import { NotificationGroupWithStatus } from './notification_group_with_status';
|
import { NotificationGroupWithStatus } from './notification_group_with_status';
|
||||||
|
|
||||||
const labelRenderer: LabelRenderer = (displayedName, total) => {
|
const labelRenderer: LabelRenderer = (displayedName, total, seeMoreHref) => {
|
||||||
if (total === 1)
|
if (total === 1)
|
||||||
return (
|
return (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
|
@ -23,10 +28,12 @@ const labelRenderer: LabelRenderer = (displayedName, total) => {
|
||||||
return (
|
return (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='notification.follow.name_and_others'
|
id='notification.follow.name_and_others'
|
||||||
defaultMessage='{name} and {count, plural, one {# other} other {# others}} followed you'
|
defaultMessage='{name} and <a>{count, plural, one {# other} other {# others}}</a> followed you'
|
||||||
values={{
|
values={{
|
||||||
name: displayedName,
|
name: displayedName,
|
||||||
count: total - 1,
|
count: total - 1,
|
||||||
|
a: (chunks) =>
|
||||||
|
seeMoreHref ? <Link to={seeMoreHref}>{chunks}</Link> : chunks,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -46,6 +53,10 @@ export const NotificationFollow: React.FC<{
|
||||||
notification: NotificationGroupFollow;
|
notification: NotificationGroupFollow;
|
||||||
unread: boolean;
|
unread: boolean;
|
||||||
}> = ({ notification, unread }) => {
|
}> = ({ notification, unread }) => {
|
||||||
|
const username = useAppSelector(
|
||||||
|
(state) => state.accounts.getIn([me, 'username']) as string,
|
||||||
|
);
|
||||||
|
|
||||||
let actions: JSX.Element | undefined;
|
let actions: JSX.Element | undefined;
|
||||||
let additionalContent: JSX.Element | undefined;
|
let additionalContent: JSX.Element | undefined;
|
||||||
|
|
||||||
|
@ -68,6 +79,7 @@ export const NotificationFollow: React.FC<{
|
||||||
timestamp={notification.latest_page_notification_at}
|
timestamp={notification.latest_page_notification_at}
|
||||||
count={notification.notifications_count}
|
count={notification.notifications_count}
|
||||||
labelRenderer={labelRenderer}
|
labelRenderer={labelRenderer}
|
||||||
|
labelSeeMoreHref={`/@${username}/followers`}
|
||||||
unread={unread}
|
unread={unread}
|
||||||
actions={actions}
|
actions={actions}
|
||||||
additionalContent={additionalContent}
|
additionalContent={additionalContent}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
import type { JSX } from 'react';
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ import {
|
||||||
import type { IconProp } from 'mastodon/components/icon';
|
import type { IconProp } from 'mastodon/components/icon';
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
import Status from 'mastodon/containers/status_container';
|
import Status from 'mastodon/containers/status_container';
|
||||||
|
import { getStatusHidden } from 'mastodon/selectors/filters';
|
||||||
import { useAppSelector, useAppDispatch } from 'mastodon/store';
|
import { useAppSelector, useAppDispatch } from 'mastodon/store';
|
||||||
|
|
||||||
import { DisplayedName } from './displayed_name';
|
import { DisplayedName } from './displayed_name';
|
||||||
|
@ -48,6 +49,12 @@ export const NotificationWithStatus: React.FC<{
|
||||||
(state) => state.statuses.getIn([statusId, 'visibility']) === 'direct',
|
(state) => state.statuses.getIn([statusId, 'visibility']) === 'direct',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const isFiltered = useAppSelector(
|
||||||
|
(state) =>
|
||||||
|
statusId &&
|
||||||
|
getStatusHidden(state, { id: statusId, contextType: 'notifications' }),
|
||||||
|
);
|
||||||
|
|
||||||
const handlers = useMemo(
|
const handlers = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
open: () => {
|
open: () => {
|
||||||
|
@ -73,7 +80,7 @@ export const NotificationWithStatus: React.FC<{
|
||||||
[dispatch, statusId],
|
[dispatch, statusId],
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!statusId) return null;
|
if (!statusId || isFiltered) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={handlers}>
|
<HotKeys handlers={handlers}>
|
||||||
|
|
|
@ -14,6 +14,8 @@ import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react';
|
||||||
import ReplyIcon from '@/material-icons/400-24px/reply.svg?react';
|
import ReplyIcon from '@/material-icons/400-24px/reply.svg?react';
|
||||||
import ReplyAllIcon from '@/material-icons/400-24px/reply_all.svg?react';
|
import ReplyAllIcon from '@/material-icons/400-24px/reply_all.svg?react';
|
||||||
import StarIcon from '@/material-icons/400-24px/star.svg?react';
|
import StarIcon from '@/material-icons/400-24px/star.svg?react';
|
||||||
|
import RepeatDisabledIcon from '@/svg-icons/repeat_disabled.svg?react';
|
||||||
|
import RepeatPrivateIcon from '@/svg-icons/repeat_private.svg?react';
|
||||||
import { replyCompose } from 'mastodon/actions/compose';
|
import { replyCompose } from 'mastodon/actions/compose';
|
||||||
import { toggleReblog, toggleFavourite } from 'mastodon/actions/interactions';
|
import { toggleReblog, toggleFavourite } from 'mastodon/actions/interactions';
|
||||||
import { openModal } from 'mastodon/actions/modal';
|
import { openModal } from 'mastodon/actions/modal';
|
||||||
|
@ -159,22 +161,26 @@ class Footer extends ImmutablePureComponent {
|
||||||
replyTitle = intl.formatMessage(messages.replyAll);
|
replyTitle = intl.formatMessage(messages.replyAll);
|
||||||
}
|
}
|
||||||
|
|
||||||
let reblogTitle = '';
|
let reblogTitle, reblogIconComponent;
|
||||||
|
|
||||||
if (status.get('reblogged')) {
|
if (status.get('reblogged')) {
|
||||||
reblogTitle = intl.formatMessage(messages.cancel_reblog_private);
|
reblogTitle = intl.formatMessage(messages.cancel_reblog_private);
|
||||||
|
reblogIconComponent = publicStatus ? RepeatIcon : RepeatPrivateIcon;
|
||||||
} else if (publicStatus) {
|
} else if (publicStatus) {
|
||||||
reblogTitle = intl.formatMessage(messages.reblog);
|
reblogTitle = intl.formatMessage(messages.reblog);
|
||||||
|
reblogIconComponent = RepeatIcon;
|
||||||
} else if (reblogPrivate) {
|
} else if (reblogPrivate) {
|
||||||
reblogTitle = intl.formatMessage(messages.reblog_private);
|
reblogTitle = intl.formatMessage(messages.reblog_private);
|
||||||
|
reblogIconComponent = RepeatPrivateIcon;
|
||||||
} else {
|
} else {
|
||||||
reblogTitle = intl.formatMessage(messages.cannot_reblog);
|
reblogTitle = intl.formatMessage(messages.cannot_reblog);
|
||||||
|
reblogIconComponent = RepeatDisabledIcon;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='picture-in-picture__footer'>
|
<div className='picture-in-picture__footer'>
|
||||||
<IconButton className='status__action-bar-button' title={replyTitle} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} iconComponent={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? ReplyIcon : replyIconComponent} onClick={this.handleReplyClick} counter={status.get('replies_count')} />
|
<IconButton className='status__action-bar-button' title={replyTitle} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} iconComponent={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? ReplyIcon : replyIconComponent} onClick={this.handleReplyClick} counter={status.get('replies_count')} />
|
||||||
<IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={RepeatIcon} onClick={this.handleReblogClick} counter={status.get('reblogs_count')} />
|
<IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={reblogIconComponent} onClick={this.handleReblogClick} counter={status.get('reblogs_count')} />
|
||||||
<IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={StarIcon} onClick={this.handleFavouriteClick} counter={status.get('favourites_count')} />
|
<IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={StarIcon} onClick={this.handleFavouriteClick} counter={status.get('favourites_count')} />
|
||||||
{withOpenButton && <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.open)} icon='external-link' iconComponent={OpenInNewIcon} onClick={this.handleOpenClick} href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} />}
|
{withOpenButton && <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.open)} icon='external-link' iconComponent={OpenInNewIcon} onClick={this.handleOpenClick} href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} />}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -152,7 +152,7 @@ export const DetailedStatus: React.FC<{
|
||||||
media = <PictureInPicturePlaceholder aspectRatio={attachmentAspectRatio} />;
|
media = <PictureInPicturePlaceholder aspectRatio={attachmentAspectRatio} />;
|
||||||
} else if (status.get('media_attachments').size > 0) {
|
} else if (status.get('media_attachments').size > 0) {
|
||||||
if (
|
if (
|
||||||
['image', 'gifv'].includes(
|
['image', 'gifv', 'unknown'].includes(
|
||||||
status.getIn(['media_attachments', 0, 'type']) as string,
|
status.getIn(['media_attachments', 0, 'type']) as string,
|
||||||
) ||
|
) ||
|
||||||
status.get('media_attachments').size > 1
|
status.get('media_attachments').size > 1
|
||||||
|
|
|
@ -15,7 +15,7 @@ const ColumnLink = ({ icon, activeIcon, iconComponent, activeIconComponent, text
|
||||||
|
|
||||||
if (href) {
|
if (href) {
|
||||||
return (
|
return (
|
||||||
<a href={href} className={className} data-method={method} title={text} {...other}>
|
<a href={href} className={className} data-method={method} {...other}>
|
||||||
{active ? activeIconElement : iconElement}
|
{active ? activeIconElement : iconElement}
|
||||||
<span>{text}</span>
|
<span>{text}</span>
|
||||||
{badgeElement}
|
{badgeElement}
|
||||||
|
@ -23,7 +23,7 @@ const ColumnLink = ({ icon, activeIcon, iconComponent, activeIconComponent, text
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<NavLink to={to} className={className} title={text} exact {...other}>
|
<NavLink to={to} className={className} exact {...other}>
|
||||||
{active ? activeIconElement : iconElement}
|
{active ? activeIconElement : iconElement}
|
||||||
<span>{text}</span>
|
<span>{text}</span>
|
||||||
{badgeElement}
|
{badgeElement}
|
||||||
|
|
|
@ -116,6 +116,7 @@ export const MuteModal = ({ accountId, acct }) => {
|
||||||
<div className='safety-action-modal__bottom__collapsible'>
|
<div className='safety-action-modal__bottom__collapsible'>
|
||||||
<div className='safety-action-modal__field-group'>
|
<div className='safety-action-modal__field-group'>
|
||||||
<RadioButtonLabel name='duration' value='0' label={intl.formatMessage(messages.indefinite)} currentValue={muteDuration} onChange={handleChangeMuteDuration} />
|
<RadioButtonLabel name='duration' value='0' label={intl.formatMessage(messages.indefinite)} currentValue={muteDuration} onChange={handleChangeMuteDuration} />
|
||||||
|
<RadioButtonLabel name='duration' value='21600' label={intl.formatMessage(messages.hours, { number: 6 })} currentValue={muteDuration} onChange={handleChangeMuteDuration} />
|
||||||
<RadioButtonLabel name='duration' value='86400' label={intl.formatMessage(messages.hours, { number: 24 })} currentValue={muteDuration} onChange={handleChangeMuteDuration} />
|
<RadioButtonLabel name='duration' value='86400' label={intl.formatMessage(messages.hours, { number: 24 })} currentValue={muteDuration} onChange={handleChangeMuteDuration} />
|
||||||
<RadioButtonLabel name='duration' value='604800' label={intl.formatMessage(messages.days, { number: 7 })} currentValue={muteDuration} onChange={handleChangeMuteDuration} />
|
<RadioButtonLabel name='duration' value='604800' label={intl.formatMessage(messages.days, { number: 7 })} currentValue={muteDuration} onChange={handleChangeMuteDuration} />
|
||||||
<RadioButtonLabel name='duration' value='2592000' label={intl.formatMessage(messages.days, { number: 30 })} currentValue={muteDuration} onChange={handleChangeMuteDuration} />
|
<RadioButtonLabel name='duration' value='2592000' label={intl.formatMessage(messages.days, { number: 30 })} currentValue={muteDuration} onChange={handleChangeMuteDuration} />
|
||||||
|
|
|
@ -84,6 +84,7 @@
|
||||||
"alert.rate_limited.title": "معدل الطلبات محدود",
|
"alert.rate_limited.title": "معدل الطلبات محدود",
|
||||||
"alert.unexpected.message": "لقد طرأ خطأ غير متوقّع.",
|
"alert.unexpected.message": "لقد طرأ خطأ غير متوقّع.",
|
||||||
"alert.unexpected.title": "المعذرة!",
|
"alert.unexpected.title": "المعذرة!",
|
||||||
|
"alt_text_badge.title": "نص بديل",
|
||||||
"announcement.announcement": "إعلان",
|
"announcement.announcement": "إعلان",
|
||||||
"attachments_list.unprocessed": "(غير معالَج)",
|
"attachments_list.unprocessed": "(غير معالَج)",
|
||||||
"audio.hide": "إخفاء المقطع الصوتي",
|
"audio.hide": "إخفاء المقطع الصوتي",
|
||||||
|
@ -156,7 +157,6 @@
|
||||||
"compose_form.poll.duration": "مُدَّة اِستطلاع الرأي",
|
"compose_form.poll.duration": "مُدَّة اِستطلاع الرأي",
|
||||||
"compose_form.poll.multiple": "متعدد الخيارات",
|
"compose_form.poll.multiple": "متعدد الخيارات",
|
||||||
"compose_form.poll.option_placeholder": "الخيار {number}",
|
"compose_form.poll.option_placeholder": "الخيار {number}",
|
||||||
"compose_form.poll.single": "اختر واحدا",
|
|
||||||
"compose_form.poll.switch_to_multiple": "تغيِير الاستطلاع للسماح باِخيارات مُتعدِّدة",
|
"compose_form.poll.switch_to_multiple": "تغيِير الاستطلاع للسماح باِخيارات مُتعدِّدة",
|
||||||
"compose_form.poll.switch_to_single": "تغيِير الاستطلاع للسماح باِخيار واحد فقط",
|
"compose_form.poll.switch_to_single": "تغيِير الاستطلاع للسماح باِخيار واحد فقط",
|
||||||
"compose_form.poll.type": "الطراز",
|
"compose_form.poll.type": "الطراز",
|
||||||
|
@ -301,7 +301,6 @@
|
||||||
"filter_modal.select_filter.subtitle": "استخدم فئة موجودة أو قم بإنشاء فئة جديدة",
|
"filter_modal.select_filter.subtitle": "استخدم فئة موجودة أو قم بإنشاء فئة جديدة",
|
||||||
"filter_modal.select_filter.title": "تصفية هذا المنشور",
|
"filter_modal.select_filter.title": "تصفية هذا المنشور",
|
||||||
"filter_modal.title.status": "تصفية منشور",
|
"filter_modal.title.status": "تصفية منشور",
|
||||||
"filter_warning.matches_filter": "يطابق عامل التصفية \"{title}\"",
|
|
||||||
"filtered_notifications_banner.title": "الإشعارات المصفاة",
|
"filtered_notifications_banner.title": "الإشعارات المصفاة",
|
||||||
"firehose.all": "الكل",
|
"firehose.all": "الكل",
|
||||||
"firehose.local": "هذا الخادم",
|
"firehose.local": "هذا الخادم",
|
||||||
|
@ -758,7 +757,7 @@
|
||||||
"status.history.edited": "عدله {name} {date}",
|
"status.history.edited": "عدله {name} {date}",
|
||||||
"status.load_more": "حمّل المزيد",
|
"status.load_more": "حمّل المزيد",
|
||||||
"status.media.open": "اضغط للفتح",
|
"status.media.open": "اضغط للفتح",
|
||||||
"status.media.show": "اضغط لإظهاره",
|
"status.media.show": "اضغط لإظهارها",
|
||||||
"status.media_hidden": "وسائط مخفية",
|
"status.media_hidden": "وسائط مخفية",
|
||||||
"status.mention": "أذكُر @{name}",
|
"status.mention": "أذكُر @{name}",
|
||||||
"status.more": "المزيد",
|
"status.more": "المزيد",
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
"account.followers": "Siguidores",
|
"account.followers": "Siguidores",
|
||||||
"account.followers.empty": "Naide sigue a esti perfil.",
|
"account.followers.empty": "Naide sigue a esti perfil.",
|
||||||
"account.follows.empty": "Esti perfil nun sigue a naide.",
|
"account.follows.empty": "Esti perfil nun sigue a naide.",
|
||||||
"account.hide_reblogs": "Anubrir los artículos compartíos de @{name}",
|
"account.hide_reblogs": "Esconder los artículos compartíos de @{name}",
|
||||||
"account.in_memoriam": "N'alcordanza.",
|
"account.in_memoriam": "N'alcordanza.",
|
||||||
"account.joined_short": "Data de xunión",
|
"account.joined_short": "Data de xunión",
|
||||||
"account.link_verified_on": "La propiedá d'esti enllaz comprobóse'l {date}",
|
"account.link_verified_on": "La propiedá d'esti enllaz comprobóse'l {date}",
|
||||||
|
@ -122,6 +122,7 @@
|
||||||
"conversation.open": "Ver la conversación",
|
"conversation.open": "Ver la conversación",
|
||||||
"conversation.with": "Con {names}",
|
"conversation.with": "Con {names}",
|
||||||
"copypaste.copied": "Copióse",
|
"copypaste.copied": "Copióse",
|
||||||
|
"copypaste.copy_to_clipboard": "Copiar nel cartafueyu",
|
||||||
"directory.federated": "Del fediversu conocíu",
|
"directory.federated": "Del fediversu conocíu",
|
||||||
"directory.local": "De «{domain}» namás",
|
"directory.local": "De «{domain}» namás",
|
||||||
"directory.new_arrivals": "Cuentes nueves",
|
"directory.new_arrivals": "Cuentes nueves",
|
||||||
|
@ -130,7 +131,7 @@
|
||||||
"dismissable_banner.dismiss": "Escartar",
|
"dismissable_banner.dismiss": "Escartar",
|
||||||
"dismissable_banner.explore_tags": "Esta seición contién les etiquetes del fediversu que tán ganando popularidá güei. Les etiquetes más usaes polos perfiles apaecen no cimero.",
|
"dismissable_banner.explore_tags": "Esta seición contién les etiquetes del fediversu que tán ganando popularidá güei. Les etiquetes más usaes polos perfiles apaecen no cimero.",
|
||||||
"dismissable_banner.public_timeline": "Esta seición contién los artículos más nuevos de les persones na web social que les persones de {domain} siguen.",
|
"dismissable_banner.public_timeline": "Esta seición contién los artículos más nuevos de les persones na web social que les persones de {domain} siguen.",
|
||||||
"embed.instructions": "Empotra esti artículu nel to sitiu web pente la copia del códigu d'abaxo.",
|
"embed.instructions": "Empotra esti artículu nel to sitiu web copiando'l códigu d'abaxo.",
|
||||||
"embed.preview": "Va apaecer asina:",
|
"embed.preview": "Va apaecer asina:",
|
||||||
"emoji_button.activity": "Actividá",
|
"emoji_button.activity": "Actividá",
|
||||||
"emoji_button.flags": "Banderes",
|
"emoji_button.flags": "Banderes",
|
||||||
|
@ -213,6 +214,7 @@
|
||||||
"hashtag.counter_by_accounts": "{count, plural, one {{counter} participante} other {{counter} participantes}}",
|
"hashtag.counter_by_accounts": "{count, plural, one {{counter} participante} other {{counter} participantes}}",
|
||||||
"hashtag.follow": "Siguir a la etiqueta",
|
"hashtag.follow": "Siguir a la etiqueta",
|
||||||
"hashtag.unfollow": "Dexar de siguir a la etiqueta",
|
"hashtag.unfollow": "Dexar de siguir a la etiqueta",
|
||||||
|
"hints.threads.replies_may_be_missing": "Ye posible que falten les rempuestes d'otros sirvidores.",
|
||||||
"home.column_settings.show_reblogs": "Amosar los artículos compartíos",
|
"home.column_settings.show_reblogs": "Amosar los artículos compartíos",
|
||||||
"home.column_settings.show_replies": "Amosar les rempuestes",
|
"home.column_settings.show_replies": "Amosar les rempuestes",
|
||||||
"home.pending_critical_update.body": "¡Anueva'l sirvidor de Mastodon namás que puedas!",
|
"home.pending_critical_update.body": "¡Anueva'l sirvidor de Mastodon namás que puedas!",
|
||||||
|
@ -251,7 +253,7 @@
|
||||||
"keyboard_shortcuts.requests": "Abrir la llista de solicitúes de siguimientu",
|
"keyboard_shortcuts.requests": "Abrir la llista de solicitúes de siguimientu",
|
||||||
"keyboard_shortcuts.search": "Enfocar la barra de busca",
|
"keyboard_shortcuts.search": "Enfocar la barra de busca",
|
||||||
"keyboard_shortcuts.start": "Abrir la columna «Entamar»",
|
"keyboard_shortcuts.start": "Abrir la columna «Entamar»",
|
||||||
"keyboard_shortcuts.toggle_sensitivity": "Amosar/anubrir el conteníu multimedia",
|
"keyboard_shortcuts.toggle_sensitivity": "Amosar/esconder el conteníu multimedia",
|
||||||
"keyboard_shortcuts.toot": "Comenzar un artículu nuevu",
|
"keyboard_shortcuts.toot": "Comenzar un artículu nuevu",
|
||||||
"keyboard_shortcuts.unfocus": "Desenfocar l'área de composición/busca",
|
"keyboard_shortcuts.unfocus": "Desenfocar l'área de composición/busca",
|
||||||
"keyboard_shortcuts.up": "Xubir na llista",
|
"keyboard_shortcuts.up": "Xubir na llista",
|
||||||
|
@ -299,6 +301,7 @@
|
||||||
"notifications.column_settings.admin.sign_up": "Rexistros nuevos:",
|
"notifications.column_settings.admin.sign_up": "Rexistros nuevos:",
|
||||||
"notifications.column_settings.follow": "Siguidores nuevos:",
|
"notifications.column_settings.follow": "Siguidores nuevos:",
|
||||||
"notifications.column_settings.follow_request": "Solicitúes de siguimientu nueves:",
|
"notifications.column_settings.follow_request": "Solicitúes de siguimientu nueves:",
|
||||||
|
"notifications.column_settings.group": "Agrupar",
|
||||||
"notifications.column_settings.mention": "Menciones:",
|
"notifications.column_settings.mention": "Menciones:",
|
||||||
"notifications.column_settings.poll": "Resultaos de les encuestes:",
|
"notifications.column_settings.poll": "Resultaos de les encuestes:",
|
||||||
"notifications.column_settings.reblog": "Artículos compartíos:",
|
"notifications.column_settings.reblog": "Artículos compartíos:",
|
||||||
|
@ -418,11 +421,12 @@
|
||||||
"status.direct": "Mentar a @{name} per privao",
|
"status.direct": "Mentar a @{name} per privao",
|
||||||
"status.direct_indicator": "Mención privada",
|
"status.direct_indicator": "Mención privada",
|
||||||
"status.edited_x_times": "Editóse {count, plural, one {{count} vegada} other {{count} vegaes}}",
|
"status.edited_x_times": "Editóse {count, plural, one {{count} vegada} other {{count} vegaes}}",
|
||||||
|
"status.embed": "Consiguir el códigu pa empotrar",
|
||||||
"status.filter": "Peñerar esti artículu",
|
"status.filter": "Peñerar esti artículu",
|
||||||
"status.history.created": "{name} creó {date}",
|
"status.history.created": "{name} creó {date}",
|
||||||
"status.history.edited": "{name} editó {date}",
|
"status.history.edited": "{name} editó {date}",
|
||||||
"status.load_more": "Cargar más",
|
"status.load_more": "Cargar más",
|
||||||
"status.media_hidden": "Conteníu multimedia anubríu",
|
"status.media_hidden": "Conteníu multimedia escondíu",
|
||||||
"status.mention": "Mentar a @{name}",
|
"status.mention": "Mentar a @{name}",
|
||||||
"status.more": "Más",
|
"status.more": "Más",
|
||||||
"status.mute": "Desactivar los avisos de @{name}",
|
"status.mute": "Desactivar los avisos de @{name}",
|
||||||
|
@ -468,14 +472,14 @@
|
||||||
"upload_modal.applying": "Aplicando…",
|
"upload_modal.applying": "Aplicando…",
|
||||||
"upload_modal.detect_text": "Detectar el testu de la semeya",
|
"upload_modal.detect_text": "Detectar el testu de la semeya",
|
||||||
"upload_modal.edit_media": "Edición",
|
"upload_modal.edit_media": "Edición",
|
||||||
"upload_modal.hint": "Calca o arrastra'l círculu de la previsualización pa escoyer el puntu d'enfoque que siempres va tar a la vista en toles miniatures.",
|
"upload_modal.hint": "Calca o arrastra'l círculu de la previsualización pa escoyer el puntu d'enfoque que siempre va tar a la vista en toles miniatures.",
|
||||||
"upload_progress.label": "Xubiendo…",
|
"upload_progress.label": "Xubiendo…",
|
||||||
"upload_progress.processing": "Procesando…",
|
"upload_progress.processing": "Procesando…",
|
||||||
"video.close": "Zarrar el videu",
|
"video.close": "Zarrar el videu",
|
||||||
"video.download": "Baxar el ficheru",
|
"video.download": "Baxar el ficheru",
|
||||||
"video.expand": "Espander el videu",
|
"video.expand": "Espander el videu",
|
||||||
"video.fullscreen": "Pantalla completa",
|
"video.fullscreen": "Pantalla completa",
|
||||||
"video.hide": "Anubrir el videu",
|
"video.hide": "Esconder el videu",
|
||||||
"video.mute": "Desactivar el soníu",
|
"video.mute": "Desactivar el soníu",
|
||||||
"video.pause": "Posar",
|
"video.pause": "Posar",
|
||||||
"video.play": "Reproducir",
|
"video.play": "Reproducir",
|
||||||
|
|
|
@ -85,6 +85,7 @@
|
||||||
"alert.rate_limited.title": "Ліміт перавышаны",
|
"alert.rate_limited.title": "Ліміт перавышаны",
|
||||||
"alert.unexpected.message": "Узнікла нечаканая памылка.",
|
"alert.unexpected.message": "Узнікла нечаканая памылка.",
|
||||||
"alert.unexpected.title": "Вой!",
|
"alert.unexpected.title": "Вой!",
|
||||||
|
"alt_text_badge.title": "Альтернативный текст",
|
||||||
"announcement.announcement": "Аб'ява",
|
"announcement.announcement": "Аб'ява",
|
||||||
"attachments_list.unprocessed": "(неапрацаваны)",
|
"attachments_list.unprocessed": "(неапрацаваны)",
|
||||||
"audio.hide": "Схаваць аўдыя",
|
"audio.hide": "Схаваць аўдыя",
|
||||||
|
@ -97,6 +98,8 @@
|
||||||
"block_modal.title": "Заблакіраваць карыстальніка?",
|
"block_modal.title": "Заблакіраваць карыстальніка?",
|
||||||
"block_modal.you_wont_see_mentions": "Вы не ўбачыце паведамленняў са згадваннем карыстальніка.",
|
"block_modal.you_wont_see_mentions": "Вы не ўбачыце паведамленняў са згадваннем карыстальніка.",
|
||||||
"boost_modal.combo": "Націсніце {combo}, каб прапусціць наступным разам",
|
"boost_modal.combo": "Націсніце {combo}, каб прапусціць наступным разам",
|
||||||
|
"boost_modal.reblog": "Пашырыць допіс?",
|
||||||
|
"boost_modal.undo_reblog": "Прыбраць допіс?",
|
||||||
"bundle_column_error.copy_stacktrace": "Скапіраваць справаздачу пра памылку",
|
"bundle_column_error.copy_stacktrace": "Скапіраваць справаздачу пра памылку",
|
||||||
"bundle_column_error.error.body": "Запытаная старонка не можа быць адлюстраваная. Гэта магло стацца праз хібу ў нашым кодзе, або праз памылку сумяшчальнасці з браўзерам.",
|
"bundle_column_error.error.body": "Запытаная старонка не можа быць адлюстраваная. Гэта магло стацца праз хібу ў нашым кодзе, або праз памылку сумяшчальнасці з браўзерам.",
|
||||||
"bundle_column_error.error.title": "Халера!",
|
"bundle_column_error.error.title": "Халера!",
|
||||||
|
@ -194,6 +197,7 @@
|
||||||
"confirmations.unfollow.title": "Адпісацца ад карыстальніка?",
|
"confirmations.unfollow.title": "Адпісацца ад карыстальніка?",
|
||||||
"content_warning.hide": "Схаваць допіс",
|
"content_warning.hide": "Схаваць допіс",
|
||||||
"content_warning.show": "Усё адно паказаць",
|
"content_warning.show": "Усё адно паказаць",
|
||||||
|
"content_warning.show_more": "Паказаць усё роўна",
|
||||||
"conversation.delete": "Выдаліць размову",
|
"conversation.delete": "Выдаліць размову",
|
||||||
"conversation.mark_as_read": "Адзначыць прачытаным",
|
"conversation.mark_as_read": "Адзначыць прачытаным",
|
||||||
"conversation.open": "Прагледзець размову",
|
"conversation.open": "Прагледзець размову",
|
||||||
|
@ -219,6 +223,8 @@
|
||||||
"domain_block_modal.they_cant_follow": "Ніхто з гэтага сервера не зможа падпісацца на вас.",
|
"domain_block_modal.they_cant_follow": "Ніхто з гэтага сервера не зможа падпісацца на вас.",
|
||||||
"domain_block_modal.they_wont_know": "Карыстальнік не будзе ведаць пра блакіроўку.",
|
"domain_block_modal.they_wont_know": "Карыстальнік не будзе ведаць пра блакіроўку.",
|
||||||
"domain_block_modal.title": "Заблакіраваць дамен?",
|
"domain_block_modal.title": "Заблакіраваць дамен?",
|
||||||
|
"domain_block_modal.you_will_lose_num_followers": "Вы страціце {followersCount, plural, one {{followersCountDisplay} падпісчыка} other {{followersCountDisplay} падпісчыкаў}} і {followingCount, plural, one {{followingCountDisplay} чалавека, на якога падпісаны} other {{followingCountDisplay} людзей, на якіх падпісаны}}.",
|
||||||
|
"domain_block_modal.you_will_lose_relationships": "Вы страціце ўсех падпісчыкаў і людзей на якіх падпісаны на гэтым.",
|
||||||
"domain_block_modal.you_wont_see_posts": "Вы не ўбачыце допісаў і апавяшчэнняў ад карыстальнікаў з гэтага сервера.",
|
"domain_block_modal.you_wont_see_posts": "Вы не ўбачыце допісаў і апавяшчэнняў ад карыстальнікаў з гэтага сервера.",
|
||||||
"domain_pill.activitypub_lets_connect": "Ён дазваляе вам узаемадзейнічаць не толькі з карыстальнікамі Mastodon, але і розных іншых сацыяльных платформ.",
|
"domain_pill.activitypub_lets_connect": "Ён дазваляе вам узаемадзейнічаць не толькі з карыстальнікамі Mastodon, але і розных іншых сацыяльных платформ.",
|
||||||
"domain_pill.activitypub_like_language": "ActivityPub — гэта мова, на якой Mastodon размаўляе з іншымі сацыяльнымі сеткамі.",
|
"domain_pill.activitypub_like_language": "ActivityPub — гэта мова, на якой Mastodon размаўляе з іншымі сацыяльнымі сеткамі.",
|
||||||
|
@ -300,7 +306,7 @@
|
||||||
"filter_modal.select_filter.subtitle": "Скарыстайцеся існуючай катэгорыяй або стварыце новую",
|
"filter_modal.select_filter.subtitle": "Скарыстайцеся існуючай катэгорыяй або стварыце новую",
|
||||||
"filter_modal.select_filter.title": "Фільтраваць гэты допіс",
|
"filter_modal.select_filter.title": "Фільтраваць гэты допіс",
|
||||||
"filter_modal.title.status": "Фільтраваць допіс",
|
"filter_modal.title.status": "Фільтраваць допіс",
|
||||||
"filter_warning.matches_filter": "Адпавядае фільтру \"{title}\"",
|
"filter_warning.matches_filter": "Адпавядае фільтру \"<span>{title}</span>\"",
|
||||||
"filtered_notifications_banner.pending_requests": "Ад {count, plural, =0 {# людзей якіх} one {# чалавека якіх} few {# чалавек якіх} many {# людзей якіх} other {# чалавека якіх}} вы магчыма ведаеце",
|
"filtered_notifications_banner.pending_requests": "Ад {count, plural, =0 {# людзей якіх} one {# чалавека якіх} few {# чалавек якіх} many {# людзей якіх} other {# чалавека якіх}} вы магчыма ведаеце",
|
||||||
"filtered_notifications_banner.title": "Адфільтраваныя апавяшчэнні",
|
"filtered_notifications_banner.title": "Адфільтраваныя апавяшчэнні",
|
||||||
"firehose.all": "Усе",
|
"firehose.all": "Усе",
|
||||||
|
@ -350,6 +356,9 @@
|
||||||
"hashtag.follow": "Падпісацца на хэштэг",
|
"hashtag.follow": "Падпісацца на хэштэг",
|
||||||
"hashtag.unfollow": "Адпісацца ад хэштэга",
|
"hashtag.unfollow": "Адпісацца ад хэштэга",
|
||||||
"hashtags.and_other": "…і яшчэ {count, plural, other {#}}",
|
"hashtags.and_other": "…і яшчэ {count, plural, other {#}}",
|
||||||
|
"hints.profiles.followers_may_be_missing": "Падпісчыкі гэтага профілю могуць адсутнічаць.",
|
||||||
|
"hints.profiles.follows_may_be_missing": "Падпіскі гэтага профілю могуць адсутнічаць.",
|
||||||
|
"hints.profiles.posts_may_be_missing": "Некаторыя допісы гэтага профілю могуць адсутнічаць.",
|
||||||
"home.column_settings.show_reblogs": "Паказваць пашырэнні",
|
"home.column_settings.show_reblogs": "Паказваць пашырэнні",
|
||||||
"home.column_settings.show_replies": "Паказваць адказы",
|
"home.column_settings.show_replies": "Паказваць адказы",
|
||||||
"home.hide_announcements": "Схаваць аб'явы",
|
"home.hide_announcements": "Схаваць аб'явы",
|
||||||
|
@ -434,6 +443,7 @@
|
||||||
"lists.subheading": "Вашыя спісы",
|
"lists.subheading": "Вашыя спісы",
|
||||||
"load_pending": "{count, plural, one {# новы элемент} few {# новыя элементы} many {# новых элементаў} other {# новых элементаў}}",
|
"load_pending": "{count, plural, one {# новы элемент} few {# новыя элементы} many {# новых элементаў} other {# новых элементаў}}",
|
||||||
"loading_indicator.label": "Загрузка…",
|
"loading_indicator.label": "Загрузка…",
|
||||||
|
"media_gallery.hide": "Схаваць",
|
||||||
"moved_to_account_banner.text": "Ваш уліковы запіс {disabledAccount} зараз адключаны таму што вы перанесены на {movedToAccount}.",
|
"moved_to_account_banner.text": "Ваш уліковы запіс {disabledAccount} зараз адключаны таму што вы перанесены на {movedToAccount}.",
|
||||||
"mute_modal.hide_from_notifications": "Схаваць з апавяшчэнняў",
|
"mute_modal.hide_from_notifications": "Схаваць з апавяшчэнняў",
|
||||||
"mute_modal.hide_options": "Схаваць опцыі",
|
"mute_modal.hide_options": "Схаваць опцыі",
|
||||||
|
@ -479,11 +489,13 @@
|
||||||
"notification.favourite": "Ваш допіс упадабаны {name}",
|
"notification.favourite": "Ваш допіс упадабаны {name}",
|
||||||
"notification.follow": "{name} падпісаўся на вас",
|
"notification.follow": "{name} падпісаўся на вас",
|
||||||
"notification.follow_request": "{name} адправіў запыт на падпіску",
|
"notification.follow_request": "{name} адправіў запыт на падпіску",
|
||||||
|
"notification.follow_request.name_and_others": "{name} і {count, plural, one {# іншы} many {# іншых} other {# іншых}} запыталіся падпісацца на вас",
|
||||||
"notification.label.mention": "Згадванне",
|
"notification.label.mention": "Згадванне",
|
||||||
"notification.label.private_mention": "Асабістае згадванне",
|
"notification.label.private_mention": "Асабістае згадванне",
|
||||||
"notification.label.private_reply": "Асабісты адказ",
|
"notification.label.private_reply": "Асабісты адказ",
|
||||||
"notification.label.reply": "Адказ",
|
"notification.label.reply": "Адказ",
|
||||||
"notification.mention": "Згадванне",
|
"notification.mention": "Згадванне",
|
||||||
|
"notification.mentioned_you": "{name} згадаў вас",
|
||||||
"notification.moderation-warning.learn_more": "Даведацца больш",
|
"notification.moderation-warning.learn_more": "Даведацца больш",
|
||||||
"notification.moderation_warning": "Вы атрымалі папярэджанне аб мадэрацыі",
|
"notification.moderation_warning": "Вы атрымалі папярэджанне аб мадэрацыі",
|
||||||
"notification.moderation_warning.action_delete_statuses": "Некаторыя вашыя допісы былі выдаленыя.",
|
"notification.moderation_warning.action_delete_statuses": "Некаторыя вашыя допісы былі выдаленыя.",
|
||||||
|
@ -496,6 +508,7 @@
|
||||||
"notification.own_poll": "Ваша апытанне скончылася",
|
"notification.own_poll": "Ваша апытанне скончылася",
|
||||||
"notification.poll": "Апытанне, дзе вы прынялі ўдзел, скончылася",
|
"notification.poll": "Апытанне, дзе вы прынялі ўдзел, скончылася",
|
||||||
"notification.reblog": "{name} пашырыў ваш допіс",
|
"notification.reblog": "{name} пашырыў ваш допіс",
|
||||||
|
"notification.reblog.name_and_others_with_link": "{name} і <a>{count, plural, one {# іншы} many {# іншых} other {# іншых}}</a> абагулілі ваш допіс",
|
||||||
"notification.relationships_severance_event": "Страціў сувязь з {name}",
|
"notification.relationships_severance_event": "Страціў сувязь з {name}",
|
||||||
"notification.relationships_severance_event.account_suspension": "Адміністратар з {from} прыпыніў працу {target}, што азначае, што вы больш не можаце атрымліваць ад іх абнаўлення ці ўзаемадзейнічаць з імі.",
|
"notification.relationships_severance_event.account_suspension": "Адміністратар з {from} прыпыніў працу {target}, што азначае, што вы больш не можаце атрымліваць ад іх абнаўлення ці ўзаемадзейнічаць з імі.",
|
||||||
"notification.relationships_severance_event.domain_block": "Адміністратар з {from} заблакіраваў {target}, у тым ліку {followersCount} вашых падпісчыка(-аў) і {followingCount, plural, one {# уліковы запіс} few {# уліковыя запісы} many {# уліковых запісаў} other {# уліковых запісаў}}.",
|
"notification.relationships_severance_event.domain_block": "Адміністратар з {from} заблакіраваў {target}, у тым ліку {followersCount} вашых падпісчыка(-аў) і {followingCount, plural, one {# уліковы запіс} few {# уліковыя запісы} many {# уліковых запісаў} other {# уліковых запісаў}}.",
|
||||||
|
@ -525,6 +538,7 @@
|
||||||
"notifications.column_settings.filter_bar.category": "Панэль хуткай фільтрацыі",
|
"notifications.column_settings.filter_bar.category": "Панэль хуткай фільтрацыі",
|
||||||
"notifications.column_settings.follow": "Новыя падпісчыкі:",
|
"notifications.column_settings.follow": "Новыя падпісчыкі:",
|
||||||
"notifications.column_settings.follow_request": "Новыя запыты на падпіску:",
|
"notifications.column_settings.follow_request": "Новыя запыты на падпіску:",
|
||||||
|
"notifications.column_settings.group": "Аб'яднаць апавяшчэнні ад падпісчыкаў",
|
||||||
"notifications.column_settings.mention": "Згадванні:",
|
"notifications.column_settings.mention": "Згадванні:",
|
||||||
"notifications.column_settings.poll": "Вынікі апытання:",
|
"notifications.column_settings.poll": "Вынікі апытання:",
|
||||||
"notifications.column_settings.push": "Push-апавяшчэнні",
|
"notifications.column_settings.push": "Push-апавяшчэнні",
|
||||||
|
@ -743,6 +757,7 @@
|
||||||
"status.edit": "Рэдагаваць",
|
"status.edit": "Рэдагаваць",
|
||||||
"status.edited": "Апошняе рэдагаванне {date}",
|
"status.edited": "Апошняе рэдагаванне {date}",
|
||||||
"status.edited_x_times": "Рэдагавана {count, plural, one {{count} раз} few {{count} разы} many {{count} разоў} other {{count} разу}}",
|
"status.edited_x_times": "Рэдагавана {count, plural, one {{count} раз} few {{count} разы} many {{count} разоў} other {{count} разу}}",
|
||||||
|
"status.embed": "Атрымаць убудаваны код",
|
||||||
"status.favourite": "Упадабанае",
|
"status.favourite": "Упадабанае",
|
||||||
"status.favourites": "{count, plural, one {# упадабанае} few {# упадабаныя} many {# упадабаных} other {# упадабанага}}",
|
"status.favourites": "{count, plural, one {# упадабанае} few {# упадабаныя} many {# упадабаных} other {# упадабанага}}",
|
||||||
"status.filter": "Фільтраваць гэты допіс",
|
"status.filter": "Фільтраваць гэты допіс",
|
||||||
|
|
|
@ -85,6 +85,7 @@
|
||||||
"alert.rate_limited.title": "Скоростта е ограничена",
|
"alert.rate_limited.title": "Скоростта е ограничена",
|
||||||
"alert.unexpected.message": "Възникна неочаквана грешка.",
|
"alert.unexpected.message": "Възникна неочаквана грешка.",
|
||||||
"alert.unexpected.title": "Опаа!",
|
"alert.unexpected.title": "Опаа!",
|
||||||
|
"alt_text_badge.title": "Алтернативен текст",
|
||||||
"announcement.announcement": "Оповестяване",
|
"announcement.announcement": "Оповестяване",
|
||||||
"attachments_list.unprocessed": "(необработено)",
|
"attachments_list.unprocessed": "(необработено)",
|
||||||
"audio.hide": "Скриване на звука",
|
"audio.hide": "Скриване на звука",
|
||||||
|
@ -157,7 +158,6 @@
|
||||||
"compose_form.poll.duration": "Времетраене на анкетата",
|
"compose_form.poll.duration": "Времетраене на анкетата",
|
||||||
"compose_form.poll.multiple": "Множествен избор",
|
"compose_form.poll.multiple": "Множествен избор",
|
||||||
"compose_form.poll.option_placeholder": "Избор {number}",
|
"compose_form.poll.option_placeholder": "Избор {number}",
|
||||||
"compose_form.poll.single": "Подберете нещо",
|
|
||||||
"compose_form.poll.switch_to_multiple": "Промяна на анкетата, за да се позволят множество възможни избора",
|
"compose_form.poll.switch_to_multiple": "Промяна на анкетата, за да се позволят множество възможни избора",
|
||||||
"compose_form.poll.switch_to_single": "Промяна на анкетата, за да се позволи един възможен избор",
|
"compose_form.poll.switch_to_single": "Промяна на анкетата, за да се позволи един възможен избор",
|
||||||
"compose_form.poll.type": "Стил",
|
"compose_form.poll.type": "Стил",
|
||||||
|
@ -489,7 +489,6 @@
|
||||||
"notification.favourite": "{name} направи любима публикацията ви",
|
"notification.favourite": "{name} направи любима публикацията ви",
|
||||||
"notification.favourite.name_and_others_with_link": "{name} и <a>{count, plural, one {# друг} other {# други}}</a> направиха любима ваша публикация",
|
"notification.favourite.name_and_others_with_link": "{name} и <a>{count, plural, one {# друг} other {# други}}</a> направиха любима ваша публикация",
|
||||||
"notification.follow": "{name} ви последва",
|
"notification.follow": "{name} ви последва",
|
||||||
"notification.follow.name_and_others": "{name} и {count, plural, one {# друг} other {# други}} ви последваха",
|
|
||||||
"notification.follow_request": "{name} поиска да ви последва",
|
"notification.follow_request": "{name} поиска да ви последва",
|
||||||
"notification.follow_request.name_and_others": "{name} и {count, plural, one {# друг} other {# други}} поискаха да ви последват",
|
"notification.follow_request.name_and_others": "{name} и {count, plural, one {# друг} other {# други}} поискаха да ви последват",
|
||||||
"notification.label.mention": "Споменаване",
|
"notification.label.mention": "Споменаване",
|
||||||
|
|
|
@ -145,7 +145,6 @@
|
||||||
"compose_form.poll.duration": "Pad ar sontadeg",
|
"compose_form.poll.duration": "Pad ar sontadeg",
|
||||||
"compose_form.poll.multiple": "Meur a choaz",
|
"compose_form.poll.multiple": "Meur a choaz",
|
||||||
"compose_form.poll.option_placeholder": "Choaz {number}",
|
"compose_form.poll.option_placeholder": "Choaz {number}",
|
||||||
"compose_form.poll.single": "Dibabit unan",
|
|
||||||
"compose_form.poll.switch_to_multiple": "Kemmañ ar sontadeg evit aotren meur a zibab",
|
"compose_form.poll.switch_to_multiple": "Kemmañ ar sontadeg evit aotren meur a zibab",
|
||||||
"compose_form.poll.switch_to_single": "Kemmañ ar sontadeg evit aotren un dibab hepken",
|
"compose_form.poll.switch_to_single": "Kemmañ ar sontadeg evit aotren un dibab hepken",
|
||||||
"compose_form.poll.type": "Neuz",
|
"compose_form.poll.type": "Neuz",
|
||||||
|
@ -172,6 +171,7 @@
|
||||||
"confirmations.reply.message": "Respont bremañ a zilamo ar gemennadenn emaoc'h o skrivañ. Sur e oc'h e fell deoc'h kenderc'hel ganti?",
|
"confirmations.reply.message": "Respont bremañ a zilamo ar gemennadenn emaoc'h o skrivañ. Sur e oc'h e fell deoc'h kenderc'hel ganti?",
|
||||||
"confirmations.unfollow.confirm": "Diheuliañ",
|
"confirmations.unfollow.confirm": "Diheuliañ",
|
||||||
"confirmations.unfollow.message": "Ha sur oc'h e fell deoc'h paouez da heuliañ {name} ?",
|
"confirmations.unfollow.message": "Ha sur oc'h e fell deoc'h paouez da heuliañ {name} ?",
|
||||||
|
"content_warning.show_more": "Diskouez muioc'h",
|
||||||
"conversation.delete": "Dilemel ar gaozeadenn",
|
"conversation.delete": "Dilemel ar gaozeadenn",
|
||||||
"conversation.mark_as_read": "Merkañ evel lennet",
|
"conversation.mark_as_read": "Merkañ evel lennet",
|
||||||
"conversation.open": "Gwelout ar gaozeadenn",
|
"conversation.open": "Gwelout ar gaozeadenn",
|
||||||
|
@ -250,6 +250,7 @@
|
||||||
"filter_modal.select_filter.subtitle": "Implijout ur rummad a zo anezhañ pe krouiñ unan nevez",
|
"filter_modal.select_filter.subtitle": "Implijout ur rummad a zo anezhañ pe krouiñ unan nevez",
|
||||||
"filter_modal.select_filter.title": "Silañ an toud-mañ",
|
"filter_modal.select_filter.title": "Silañ an toud-mañ",
|
||||||
"filter_modal.title.status": "Silañ un toud",
|
"filter_modal.title.status": "Silañ un toud",
|
||||||
|
"filter_warning.matches_filter": "A glot gant ar sil “<span>{title}</span>”",
|
||||||
"firehose.all": "Pep tra",
|
"firehose.all": "Pep tra",
|
||||||
"firehose.local": "Ar servijer-mañ",
|
"firehose.local": "Ar servijer-mañ",
|
||||||
"firehose.remote": "Servijerioù all",
|
"firehose.remote": "Servijerioù all",
|
||||||
|
@ -385,6 +386,7 @@
|
||||||
"notification.admin.report": "Disklêriet eo bet {target} gant {name}",
|
"notification.admin.report": "Disklêriet eo bet {target} gant {name}",
|
||||||
"notification.admin.sign_up": "{name} en·he deus lakaet e·hec'h anv",
|
"notification.admin.sign_up": "{name} en·he deus lakaet e·hec'h anv",
|
||||||
"notification.follow": "heuliañ a ra {name} ac'hanoc'h",
|
"notification.follow": "heuliañ a ra {name} ac'hanoc'h",
|
||||||
|
"notification.follow.name_and_others": "{name} <a>{count, plural, one {hag # den all} two {ha # zen all} few {ha # den all} many {ha # den all} other {ha # den all}}</a> zo o heuliañ ac'hanoc'h",
|
||||||
"notification.follow_request": "Gant {name} eo bet goulennet ho heuliañ",
|
"notification.follow_request": "Gant {name} eo bet goulennet ho heuliañ",
|
||||||
"notification.moderation-warning.learn_more": "Gouzout hiroc'h",
|
"notification.moderation-warning.learn_more": "Gouzout hiroc'h",
|
||||||
"notification.own_poll": "Echu eo ho sontadeg",
|
"notification.own_poll": "Echu eo ho sontadeg",
|
||||||
|
@ -399,6 +401,7 @@
|
||||||
"notifications.column_settings.favourite": "Muiañ-karet:",
|
"notifications.column_settings.favourite": "Muiañ-karet:",
|
||||||
"notifications.column_settings.follow": "Heulierien nevez:",
|
"notifications.column_settings.follow": "Heulierien nevez:",
|
||||||
"notifications.column_settings.follow_request": "Pedadoù heuliañ nevez :",
|
"notifications.column_settings.follow_request": "Pedadoù heuliañ nevez :",
|
||||||
|
"notifications.column_settings.group": "Strollañ",
|
||||||
"notifications.column_settings.mention": "Menegoù:",
|
"notifications.column_settings.mention": "Menegoù:",
|
||||||
"notifications.column_settings.poll": "Disoc'hoù ar sontadeg:",
|
"notifications.column_settings.poll": "Disoc'hoù ar sontadeg:",
|
||||||
"notifications.column_settings.push": "Kemennoù push",
|
"notifications.column_settings.push": "Kemennoù push",
|
||||||
|
|
|
@ -158,7 +158,7 @@
|
||||||
"compose_form.poll.duration": "Durada de l'enquesta",
|
"compose_form.poll.duration": "Durada de l'enquesta",
|
||||||
"compose_form.poll.multiple": "Opcions múltiples",
|
"compose_form.poll.multiple": "Opcions múltiples",
|
||||||
"compose_form.poll.option_placeholder": "Opció {number}",
|
"compose_form.poll.option_placeholder": "Opció {number}",
|
||||||
"compose_form.poll.single": "Trieu-ne una",
|
"compose_form.poll.single": "Única opció",
|
||||||
"compose_form.poll.switch_to_multiple": "Canvia l’enquesta per a permetre múltiples opcions",
|
"compose_form.poll.switch_to_multiple": "Canvia l’enquesta per a permetre múltiples opcions",
|
||||||
"compose_form.poll.switch_to_single": "Canvia l’enquesta per a permetre una única opció",
|
"compose_form.poll.switch_to_single": "Canvia l’enquesta per a permetre una única opció",
|
||||||
"compose_form.poll.type": "Estil",
|
"compose_form.poll.type": "Estil",
|
||||||
|
@ -197,6 +197,7 @@
|
||||||
"confirmations.unfollow.title": "Deixar de seguir l'usuari?",
|
"confirmations.unfollow.title": "Deixar de seguir l'usuari?",
|
||||||
"content_warning.hide": "Amaga la publicació",
|
"content_warning.hide": "Amaga la publicació",
|
||||||
"content_warning.show": "Mostra-la igualment",
|
"content_warning.show": "Mostra-la igualment",
|
||||||
|
"content_warning.show_more": "Mostra'n més",
|
||||||
"conversation.delete": "Elimina la conversa",
|
"conversation.delete": "Elimina la conversa",
|
||||||
"conversation.mark_as_read": "Marca com a llegida",
|
"conversation.mark_as_read": "Marca com a llegida",
|
||||||
"conversation.open": "Mostra la conversa",
|
"conversation.open": "Mostra la conversa",
|
||||||
|
@ -305,7 +306,7 @@
|
||||||
"filter_modal.select_filter.subtitle": "Usa una categoria existent o crea'n una de nova",
|
"filter_modal.select_filter.subtitle": "Usa una categoria existent o crea'n una de nova",
|
||||||
"filter_modal.select_filter.title": "Filtra aquest tut",
|
"filter_modal.select_filter.title": "Filtra aquest tut",
|
||||||
"filter_modal.title.status": "Filtra un tut",
|
"filter_modal.title.status": "Filtra un tut",
|
||||||
"filter_warning.matches_filter": "Coincideix amb el filtre “{title}”",
|
"filter_warning.matches_filter": "Coincideix amb el filtre “<span>{title}</span>”",
|
||||||
"filtered_notifications_banner.pending_requests": "{count, plural, =0 {De ningú} one {D'una persona} other {De # persones}} que potser coneixes",
|
"filtered_notifications_banner.pending_requests": "{count, plural, =0 {De ningú} one {D'una persona} other {De # persones}} que potser coneixes",
|
||||||
"filtered_notifications_banner.title": "Notificacions filtrades",
|
"filtered_notifications_banner.title": "Notificacions filtrades",
|
||||||
"firehose.all": "Tots",
|
"firehose.all": "Tots",
|
||||||
|
@ -385,6 +386,7 @@
|
||||||
"interaction_modal.description.follow": "Amb un compte a Mastodon, pots seguir a {name} per a rebre els seus tuts en la teva línia de temps d'Inici.",
|
"interaction_modal.description.follow": "Amb un compte a Mastodon, pots seguir a {name} per a rebre els seus tuts en la teva línia de temps d'Inici.",
|
||||||
"interaction_modal.description.reblog": "Amb un compte a Mastodon, pots impulsar aquest tut per a compartir-lo amb els teus seguidors.",
|
"interaction_modal.description.reblog": "Amb un compte a Mastodon, pots impulsar aquest tut per a compartir-lo amb els teus seguidors.",
|
||||||
"interaction_modal.description.reply": "Amb un compte a Mastodon, pots respondre aquest tut.",
|
"interaction_modal.description.reply": "Amb un compte a Mastodon, pots respondre aquest tut.",
|
||||||
|
"interaction_modal.description.vote": "Si teniu compte a Mastodon, podeu votar aquesta enquesta.",
|
||||||
"interaction_modal.login.action": "Torna a l'inici",
|
"interaction_modal.login.action": "Torna a l'inici",
|
||||||
"interaction_modal.login.prompt": "Domini del teu servidor domèstic, p.ex. mastodon.social",
|
"interaction_modal.login.prompt": "Domini del teu servidor domèstic, p.ex. mastodon.social",
|
||||||
"interaction_modal.no_account_yet": "No a Mastodon?",
|
"interaction_modal.no_account_yet": "No a Mastodon?",
|
||||||
|
@ -396,6 +398,7 @@
|
||||||
"interaction_modal.title.follow": "Segueix {name}",
|
"interaction_modal.title.follow": "Segueix {name}",
|
||||||
"interaction_modal.title.reblog": "Impulsa el tut de {name}",
|
"interaction_modal.title.reblog": "Impulsa el tut de {name}",
|
||||||
"interaction_modal.title.reply": "Respon al tut de {name}",
|
"interaction_modal.title.reply": "Respon al tut de {name}",
|
||||||
|
"interaction_modal.title.vote": "Voteu l'enquesta de {name}",
|
||||||
"intervals.full.days": "{number, plural, one {# dia} other {# dies}}",
|
"intervals.full.days": "{number, plural, one {# dia} other {# dies}}",
|
||||||
"intervals.full.hours": "{number, plural, one {# hora} other {# hores}}",
|
"intervals.full.hours": "{number, plural, one {# hora} other {# hores}}",
|
||||||
"intervals.full.minutes": "{number, plural, one {# minut} other {# minuts}}",
|
"intervals.full.minutes": "{number, plural, one {# minut} other {# minuts}}",
|
||||||
|
@ -508,7 +511,7 @@
|
||||||
"notification.favourite": "{name} ha afavorit el teu tut",
|
"notification.favourite": "{name} ha afavorit el teu tut",
|
||||||
"notification.favourite.name_and_others_with_link": "{name} i <a>{count, plural, one {# altre} other {# altres}}</a> han afavorit la vostra publicació",
|
"notification.favourite.name_and_others_with_link": "{name} i <a>{count, plural, one {# altre} other {# altres}}</a> han afavorit la vostra publicació",
|
||||||
"notification.follow": "{name} et segueix",
|
"notification.follow": "{name} et segueix",
|
||||||
"notification.follow.name_and_others": "{name} i {count, plural, one {# altre} other {# altres}} us han seguit",
|
"notification.follow.name_and_others": "{name} i <a>{count, plural, one {# altre} other {# altres}}</a> us han seguit",
|
||||||
"notification.follow_request": "{name} ha sol·licitat de seguir-te",
|
"notification.follow_request": "{name} ha sol·licitat de seguir-te",
|
||||||
"notification.follow_request.name_and_others": "{name} i {count, plural, one {# altre} other {# altres}} han demanat de seguir-vos",
|
"notification.follow_request.name_and_others": "{name} i {count, plural, one {# altre} other {# altres}} han demanat de seguir-vos",
|
||||||
"notification.label.mention": "Menció",
|
"notification.label.mention": "Menció",
|
||||||
|
@ -516,6 +519,7 @@
|
||||||
"notification.label.private_reply": "Resposta en privat",
|
"notification.label.private_reply": "Resposta en privat",
|
||||||
"notification.label.reply": "Resposta",
|
"notification.label.reply": "Resposta",
|
||||||
"notification.mention": "Menció",
|
"notification.mention": "Menció",
|
||||||
|
"notification.mentioned_you": "{name} us ha mencionat",
|
||||||
"notification.moderation-warning.learn_more": "Per a saber-ne més",
|
"notification.moderation-warning.learn_more": "Per a saber-ne més",
|
||||||
"notification.moderation_warning": "Heu rebut un avís de moderació",
|
"notification.moderation_warning": "Heu rebut un avís de moderació",
|
||||||
"notification.moderation_warning.action_delete_statuses": "S'han eliminat algunes de les vostres publicacions.",
|
"notification.moderation_warning.action_delete_statuses": "S'han eliminat algunes de les vostres publicacions.",
|
||||||
|
@ -566,6 +570,7 @@
|
||||||
"notifications.column_settings.filter_bar.category": "Barra ràpida de filtres",
|
"notifications.column_settings.filter_bar.category": "Barra ràpida de filtres",
|
||||||
"notifications.column_settings.follow": "Nous seguidors:",
|
"notifications.column_settings.follow": "Nous seguidors:",
|
||||||
"notifications.column_settings.follow_request": "Noves sol·licituds de seguiment:",
|
"notifications.column_settings.follow_request": "Noves sol·licituds de seguiment:",
|
||||||
|
"notifications.column_settings.group": "Agrupa",
|
||||||
"notifications.column_settings.mention": "Mencions:",
|
"notifications.column_settings.mention": "Mencions:",
|
||||||
"notifications.column_settings.poll": "Resultats de l’enquesta:",
|
"notifications.column_settings.poll": "Resultats de l’enquesta:",
|
||||||
"notifications.column_settings.push": "Notificacions push",
|
"notifications.column_settings.push": "Notificacions push",
|
||||||
|
@ -852,6 +857,11 @@
|
||||||
"upload_error.poll": "No es permet carregar fitxers a les enquestes.",
|
"upload_error.poll": "No es permet carregar fitxers a les enquestes.",
|
||||||
"upload_form.audio_description": "Descriu-ho per a persones amb problemes d'audició",
|
"upload_form.audio_description": "Descriu-ho per a persones amb problemes d'audició",
|
||||||
"upload_form.description": "Descriu-ho per a persones amb problemes de visió",
|
"upload_form.description": "Descriu-ho per a persones amb problemes de visió",
|
||||||
|
"upload_form.drag_and_drop.instructions": "Per a agafar un fitxer multimèdia adjunt, premeu l'espai o la tecla Enter. Mentre l'arrossegueu, utilitzeu les fletxes per a moure l'adjunt en qualsevol direcció. Premeu espai o Enter un altre cop per a deixar-lo anar a la seva nova posició, o premeu la tecla d'escapament per cancel·lar.",
|
||||||
|
"upload_form.drag_and_drop.on_drag_cancel": "S'ha cancel·lat l'arrossegament. S'ha deixat anar l'adjunt multimèdia {item}.",
|
||||||
|
"upload_form.drag_and_drop.on_drag_end": "S'ha deixat anar l'adjunt multimèdia {item}.",
|
||||||
|
"upload_form.drag_and_drop.on_drag_over": "S'ha mogut l'adjunt multimèdia {item}.",
|
||||||
|
"upload_form.drag_and_drop.on_drag_start": "S'ha agafat l'adjunt multimèdia {item}.",
|
||||||
"upload_form.edit": "Edita",
|
"upload_form.edit": "Edita",
|
||||||
"upload_form.thumbnail": "Canvia la miniatura",
|
"upload_form.thumbnail": "Canvia la miniatura",
|
||||||
"upload_form.video_description": "Descriu-ho per a persones amb problemes de visió o audició",
|
"upload_form.video_description": "Descriu-ho per a persones amb problemes de visió o audició",
|
||||||
|
|
|
@ -143,7 +143,6 @@
|
||||||
"compose_form.poll.duration": "ماوەی ڕاپرسی",
|
"compose_form.poll.duration": "ماوەی ڕاپرسی",
|
||||||
"compose_form.poll.multiple": "فرە هەڵبژاردە",
|
"compose_form.poll.multiple": "فرە هەڵبژاردە",
|
||||||
"compose_form.poll.option_placeholder": "بژاردەی {number}",
|
"compose_form.poll.option_placeholder": "بژاردەی {number}",
|
||||||
"compose_form.poll.single": "یەکێك هەلبژێرە",
|
|
||||||
"compose_form.poll.switch_to_multiple": "ڕاپرسی بگۆڕە بۆ ڕێگەدان بە چەند هەڵبژاردنێک",
|
"compose_form.poll.switch_to_multiple": "ڕاپرسی بگۆڕە بۆ ڕێگەدان بە چەند هەڵبژاردنێک",
|
||||||
"compose_form.poll.switch_to_single": "گۆڕینی ڕاپرسی بۆ ڕێگەدان بە تاکە هەڵبژاردنێک",
|
"compose_form.poll.switch_to_single": "گۆڕینی ڕاپرسی بۆ ڕێگەدان بە تاکە هەڵبژاردنێک",
|
||||||
"compose_form.poll.type": "ستایڵ",
|
"compose_form.poll.type": "ستایڵ",
|
||||||
|
|
|
@ -157,7 +157,6 @@
|
||||||
"compose_form.poll.duration": "Doba trvání ankety",
|
"compose_form.poll.duration": "Doba trvání ankety",
|
||||||
"compose_form.poll.multiple": "Výběr z více možností",
|
"compose_form.poll.multiple": "Výběr z více možností",
|
||||||
"compose_form.poll.option_placeholder": "Volba {number}",
|
"compose_form.poll.option_placeholder": "Volba {number}",
|
||||||
"compose_form.poll.single": "Vyber jednu",
|
|
||||||
"compose_form.poll.switch_to_multiple": "Povolit u ankety výběr více voleb",
|
"compose_form.poll.switch_to_multiple": "Povolit u ankety výběr více voleb",
|
||||||
"compose_form.poll.switch_to_single": "Povolit u ankety výběr pouze jedné volby",
|
"compose_form.poll.switch_to_single": "Povolit u ankety výběr pouze jedné volby",
|
||||||
"compose_form.poll.type": "Styl",
|
"compose_form.poll.type": "Styl",
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
"about.rules": "Rheolau'r gweinydd",
|
"about.rules": "Rheolau'r gweinydd",
|
||||||
"account.account_note_header": "Nodyn personol",
|
"account.account_note_header": "Nodyn personol",
|
||||||
"account.add_or_remove_from_list": "Ychwanegu neu Ddileu o'r rhestrau",
|
"account.add_or_remove_from_list": "Ychwanegu neu Ddileu o'r rhestrau",
|
||||||
"account.badges.bot": "Bot",
|
"account.badges.bot": "Awtomataidd",
|
||||||
"account.badges.group": "Grŵp",
|
"account.badges.group": "Grŵp",
|
||||||
"account.block": "Blocio @{name}",
|
"account.block": "Blocio @{name}",
|
||||||
"account.block_domain": "Blocio parth {domain}",
|
"account.block_domain": "Blocio parth {domain}",
|
||||||
|
@ -36,7 +36,7 @@
|
||||||
"account.followers.empty": "Does neb yn dilyn y defnyddiwr hwn eto.",
|
"account.followers.empty": "Does neb yn dilyn y defnyddiwr hwn eto.",
|
||||||
"account.followers_counter": "{count, plural, one {{counter} dilynwr} two {{counter} ddilynwr} other {{counter} dilynwyr}}",
|
"account.followers_counter": "{count, plural, one {{counter} dilynwr} two {{counter} ddilynwr} other {{counter} dilynwyr}}",
|
||||||
"account.following": "Yn dilyn",
|
"account.following": "Yn dilyn",
|
||||||
"account.following_counter": "{count, plural, one {Yn dilyn {counter}} other {Yn dilyn {counter}}}",
|
"account.following_counter": "{count, plural, one {Yn dilyn {counter}} other {Yn dilyn {counter} arall}}",
|
||||||
"account.follows.empty": "Nid yw'r defnyddiwr hwn yn dilyn unrhyw un eto.",
|
"account.follows.empty": "Nid yw'r defnyddiwr hwn yn dilyn unrhyw un eto.",
|
||||||
"account.go_to_profile": "Mynd i'r proffil",
|
"account.go_to_profile": "Mynd i'r proffil",
|
||||||
"account.hide_reblogs": "Cuddio hybiau gan @{name}",
|
"account.hide_reblogs": "Cuddio hybiau gan @{name}",
|
||||||
|
@ -62,7 +62,7 @@
|
||||||
"account.requested_follow": "Mae {name} wedi gwneud cais i'ch dilyn",
|
"account.requested_follow": "Mae {name} wedi gwneud cais i'ch dilyn",
|
||||||
"account.share": "Rhannwch broffil @{name}",
|
"account.share": "Rhannwch broffil @{name}",
|
||||||
"account.show_reblogs": "Dangos hybiau gan @{name}",
|
"account.show_reblogs": "Dangos hybiau gan @{name}",
|
||||||
"account.statuses_counter": "{count, plural, one {{counter} post} two {{counter} bost} few {{counter} phost} many {{counter} post} other {{counter} post}}",
|
"account.statuses_counter": "{count, plural, one {{counter} postiad} two {{counter} bostiad} few {{counter} phostiad} many {{counter} postiad} other {{counter} postiad}}",
|
||||||
"account.unblock": "Dadflocio @{name}",
|
"account.unblock": "Dadflocio @{name}",
|
||||||
"account.unblock_domain": "Dadflocio parth {domain}",
|
"account.unblock_domain": "Dadflocio parth {domain}",
|
||||||
"account.unblock_short": "Dadflocio",
|
"account.unblock_short": "Dadflocio",
|
||||||
|
@ -85,6 +85,7 @@
|
||||||
"alert.rate_limited.title": "Cyfradd gyfyngedig",
|
"alert.rate_limited.title": "Cyfradd gyfyngedig",
|
||||||
"alert.unexpected.message": "Digwyddodd gwall annisgwyl.",
|
"alert.unexpected.message": "Digwyddodd gwall annisgwyl.",
|
||||||
"alert.unexpected.title": "Wps!",
|
"alert.unexpected.title": "Wps!",
|
||||||
|
"alt_text_badge.title": "Testun Amgen",
|
||||||
"announcement.announcement": "Cyhoeddiad",
|
"announcement.announcement": "Cyhoeddiad",
|
||||||
"attachments_list.unprocessed": "(heb eu prosesu)",
|
"attachments_list.unprocessed": "(heb eu prosesu)",
|
||||||
"audio.hide": "Cuddio sain",
|
"audio.hide": "Cuddio sain",
|
||||||
|
@ -157,7 +158,7 @@
|
||||||
"compose_form.poll.duration": "Cyfnod pleidlais",
|
"compose_form.poll.duration": "Cyfnod pleidlais",
|
||||||
"compose_form.poll.multiple": "Dewis lluosog",
|
"compose_form.poll.multiple": "Dewis lluosog",
|
||||||
"compose_form.poll.option_placeholder": "Dewis {number}",
|
"compose_form.poll.option_placeholder": "Dewis {number}",
|
||||||
"compose_form.poll.single": "Ddewis un",
|
"compose_form.poll.single": "Dewis unigol",
|
||||||
"compose_form.poll.switch_to_multiple": "Newid pleidlais i adael mwy nag un dewis",
|
"compose_form.poll.switch_to_multiple": "Newid pleidlais i adael mwy nag un dewis",
|
||||||
"compose_form.poll.switch_to_single": "Newid pleidlais i gyfyngu i un dewis",
|
"compose_form.poll.switch_to_single": "Newid pleidlais i gyfyngu i un dewis",
|
||||||
"compose_form.poll.type": "Arddull",
|
"compose_form.poll.type": "Arddull",
|
||||||
|
@ -196,6 +197,7 @@
|
||||||
"confirmations.unfollow.title": "Dad-ddilyn defnyddiwr?",
|
"confirmations.unfollow.title": "Dad-ddilyn defnyddiwr?",
|
||||||
"content_warning.hide": "Cuddio'r postiad",
|
"content_warning.hide": "Cuddio'r postiad",
|
||||||
"content_warning.show": "Dangos beth bynnag",
|
"content_warning.show": "Dangos beth bynnag",
|
||||||
|
"content_warning.show_more": "Dangos rhagor",
|
||||||
"conversation.delete": "Dileu sgwrs",
|
"conversation.delete": "Dileu sgwrs",
|
||||||
"conversation.mark_as_read": "Nodi fel wedi'i ddarllen",
|
"conversation.mark_as_read": "Nodi fel wedi'i ddarllen",
|
||||||
"conversation.open": "Gweld sgwrs",
|
"conversation.open": "Gweld sgwrs",
|
||||||
|
@ -221,6 +223,8 @@
|
||||||
"domain_block_modal.they_cant_follow": "Ni all neb o'r gweinydd hwn eich dilyn.",
|
"domain_block_modal.they_cant_follow": "Ni all neb o'r gweinydd hwn eich dilyn.",
|
||||||
"domain_block_modal.they_wont_know": "Fyddan nhw ddim yn gwybod eu bod wedi cael eu blocio.",
|
"domain_block_modal.they_wont_know": "Fyddan nhw ddim yn gwybod eu bod wedi cael eu blocio.",
|
||||||
"domain_block_modal.title": "Blocio parth?",
|
"domain_block_modal.title": "Blocio parth?",
|
||||||
|
"domain_block_modal.you_will_lose_num_followers": "Byddwch yn colli {followersCount, plural, one {{followersCountDisplay} dilynwr} other {{followersCountDisplay} dilynwyr}} a {followingCount, plural, one {{followingCountDisplay} person rydych yn dilyn} other {{followingCountDisplay} o bobl rydych yn eu dilyn}}.",
|
||||||
|
"domain_block_modal.you_will_lose_relationships": "Byddwch yn colli'r holl ddilynwyr a phobl rydych chi'n eu dilyn o'r gweinydd hwn.",
|
||||||
"domain_block_modal.you_wont_see_posts": "Fyddwch chi ddim yn gweld postiadau na hysbysiadau gan ddefnyddwyr ar y gweinydd hwn.",
|
"domain_block_modal.you_wont_see_posts": "Fyddwch chi ddim yn gweld postiadau na hysbysiadau gan ddefnyddwyr ar y gweinydd hwn.",
|
||||||
"domain_pill.activitypub_lets_connect": "Mae'n caniatáu ichi gysylltu a rhyngweithio â phobl nid yn unig ar Mastodon, ond ar draws gwahanol apiau cymdeithasol hefyd.",
|
"domain_pill.activitypub_lets_connect": "Mae'n caniatáu ichi gysylltu a rhyngweithio â phobl nid yn unig ar Mastodon, ond ar draws gwahanol apiau cymdeithasol hefyd.",
|
||||||
"domain_pill.activitypub_like_language": "Mae ActivityPub fel yr iaith y mae Mastodon yn ei siarad â rhwydweithiau cymdeithasol eraill.",
|
"domain_pill.activitypub_like_language": "Mae ActivityPub fel yr iaith y mae Mastodon yn ei siarad â rhwydweithiau cymdeithasol eraill.",
|
||||||
|
@ -302,8 +306,8 @@
|
||||||
"filter_modal.select_filter.subtitle": "Defnyddiwch gategori sy'n bodoli eisoes neu crëu un newydd",
|
"filter_modal.select_filter.subtitle": "Defnyddiwch gategori sy'n bodoli eisoes neu crëu un newydd",
|
||||||
"filter_modal.select_filter.title": "Hidlo'r postiad hwn",
|
"filter_modal.select_filter.title": "Hidlo'r postiad hwn",
|
||||||
"filter_modal.title.status": "Hidlo postiad",
|
"filter_modal.title.status": "Hidlo postiad",
|
||||||
"filter_warning.matches_filter": "Yn cydweddu'r hidlydd “{title}”",
|
"filter_warning.matches_filter": "Yn cyd-fynd â'r hidlydd “ <span>{title}</span> ”",
|
||||||
"filtered_notifications_banner.pending_requests": "Gan {count, plural, =0 {no one} one {un person} two {# berson} few {# pherson} other {# person}} efallai eich bod yn eu hadnabod",
|
"filtered_notifications_banner.pending_requests": "Oddi wrth {count, plural, =0 {no one} one {un person} two {# berson} few {# pherson} other {# person}} efallai eich bod yn eu hadnabod",
|
||||||
"filtered_notifications_banner.title": "Hysbysiadau wedi'u hidlo",
|
"filtered_notifications_banner.title": "Hysbysiadau wedi'u hidlo",
|
||||||
"firehose.all": "Popeth",
|
"firehose.all": "Popeth",
|
||||||
"firehose.local": "Gweinydd hwn",
|
"firehose.local": "Gweinydd hwn",
|
||||||
|
@ -346,12 +350,12 @@
|
||||||
"hashtag.column_settings.tag_mode.any": "Unrhyw un o'r rhain",
|
"hashtag.column_settings.tag_mode.any": "Unrhyw un o'r rhain",
|
||||||
"hashtag.column_settings.tag_mode.none": "Dim o'r rhain",
|
"hashtag.column_settings.tag_mode.none": "Dim o'r rhain",
|
||||||
"hashtag.column_settings.tag_toggle": "Include additional tags in this column",
|
"hashtag.column_settings.tag_toggle": "Include additional tags in this column",
|
||||||
"hashtag.counter_by_accounts": "{cyfrif, lluosog, un {{counter} cyfranogwr} arall {{counter} cyfranogwr}}",
|
"hashtag.counter_by_accounts": "{count, plural, one {{counter} cyfranogwr} other {{counter} cyfranogwr}}",
|
||||||
"hashtag.counter_by_uses": "{count, plural, one {postiad {counter}} other {postiad {counter}}}",
|
"hashtag.counter_by_uses": "{count, plural, one {postiad {counter}} other {postiad {counter}}}",
|
||||||
"hashtag.counter_by_uses_today": "{cyfrif, lluosog, un {{counter} postiad} arall {{counter} postiad}} heddiw",
|
"hashtag.counter_by_uses_today": "{count, plural, one {{counter} postiad} other {{counter} postiad}} heddiw",
|
||||||
"hashtag.follow": "Dilyn hashnod",
|
"hashtag.follow": "Dilyn hashnod",
|
||||||
"hashtag.unfollow": "Dad-ddilyn hashnod",
|
"hashtag.unfollow": "Dad-ddilyn hashnod",
|
||||||
"hashtags.and_other": "…a {count, plural, other {# more}}",
|
"hashtags.and_other": "…a {count, plural, other {# arall}}",
|
||||||
"hints.profiles.followers_may_be_missing": "Mae'n bosibl bod dilynwyr y proffil hwn ar goll.",
|
"hints.profiles.followers_may_be_missing": "Mae'n bosibl bod dilynwyr y proffil hwn ar goll.",
|
||||||
"hints.profiles.follows_may_be_missing": "Mae'n bosibl bod dilynwyr y proffil hwn ar goll.",
|
"hints.profiles.follows_may_be_missing": "Mae'n bosibl bod dilynwyr y proffil hwn ar goll.",
|
||||||
"hints.profiles.posts_may_be_missing": "Mae'n bosibl bod rhai postiadau y proffil hwn ar goll.",
|
"hints.profiles.posts_may_be_missing": "Mae'n bosibl bod rhai postiadau y proffil hwn ar goll.",
|
||||||
|
@ -382,6 +386,7 @@
|
||||||
"interaction_modal.description.follow": "Gyda chyfrif ar Mastodon, gallwch ddilyn {name} i dderbyn eu postiadau yn eich ffrwd gartref.",
|
"interaction_modal.description.follow": "Gyda chyfrif ar Mastodon, gallwch ddilyn {name} i dderbyn eu postiadau yn eich ffrwd gartref.",
|
||||||
"interaction_modal.description.reblog": "Gyda chyfrif ar Mastodon, gallwch hybu'r postiad hwn i'w rannu â'ch dilynwyr.",
|
"interaction_modal.description.reblog": "Gyda chyfrif ar Mastodon, gallwch hybu'r postiad hwn i'w rannu â'ch dilynwyr.",
|
||||||
"interaction_modal.description.reply": "Gyda chyfrif ar Mastodon, gallwch ymateb i'r postiad hwn.",
|
"interaction_modal.description.reply": "Gyda chyfrif ar Mastodon, gallwch ymateb i'r postiad hwn.",
|
||||||
|
"interaction_modal.description.vote": "Gyda chyfrif ar Mastodon, gallwch bleidleisio yn y bleidlais hon.",
|
||||||
"interaction_modal.login.action": "Mynd i'm ffrwd gartref",
|
"interaction_modal.login.action": "Mynd i'm ffrwd gartref",
|
||||||
"interaction_modal.login.prompt": "Parth eich gweinydd cartref, e.e. mastodon.social",
|
"interaction_modal.login.prompt": "Parth eich gweinydd cartref, e.e. mastodon.social",
|
||||||
"interaction_modal.no_account_yet": "Dim ar Mastodon?",
|
"interaction_modal.no_account_yet": "Dim ar Mastodon?",
|
||||||
|
@ -393,6 +398,7 @@
|
||||||
"interaction_modal.title.follow": "Dilyn {name}",
|
"interaction_modal.title.follow": "Dilyn {name}",
|
||||||
"interaction_modal.title.reblog": "Hybu postiad {name}",
|
"interaction_modal.title.reblog": "Hybu postiad {name}",
|
||||||
"interaction_modal.title.reply": "Ymateb i bostiad {name}",
|
"interaction_modal.title.reply": "Ymateb i bostiad {name}",
|
||||||
|
"interaction_modal.title.vote": "Pleidleisiwch ym mhleidlais {name}",
|
||||||
"intervals.full.days": "{number, plural, one {# diwrnod} two {# ddiwrnod} other {# diwrnod}}",
|
"intervals.full.days": "{number, plural, one {# diwrnod} two {# ddiwrnod} other {# diwrnod}}",
|
||||||
"intervals.full.hours": "{number, plural, one {# awr} other {# o oriau}}",
|
"intervals.full.hours": "{number, plural, one {# awr} other {# o oriau}}",
|
||||||
"intervals.full.minutes": "{number, plural, one {# funud} other {# o funudau}}",
|
"intervals.full.minutes": "{number, plural, one {# funud} other {# o funudau}}",
|
||||||
|
@ -439,7 +445,7 @@
|
||||||
"limited_account_hint.title": "Mae'r proffil hwn wedi cael ei guddio gan gymedrolwyr {domain}.",
|
"limited_account_hint.title": "Mae'r proffil hwn wedi cael ei guddio gan gymedrolwyr {domain}.",
|
||||||
"link_preview.author": "Gan {name}",
|
"link_preview.author": "Gan {name}",
|
||||||
"link_preview.more_from_author": "Mwy gan {name}",
|
"link_preview.more_from_author": "Mwy gan {name}",
|
||||||
"link_preview.shares": "{count, plural, one {{counter} ostiad } two {{counter} bostiad } few {{counter} postiad} many {{counter} postiad} other {{counter} postiad}}",
|
"link_preview.shares": "{count, plural, one {{counter} postiad } two {{counter} bostiad } few {{counter} postiad} many {{counter} postiad} other {{counter} postiad}}",
|
||||||
"lists.account.add": "Ychwanegu at restr",
|
"lists.account.add": "Ychwanegu at restr",
|
||||||
"lists.account.remove": "Tynnu o'r rhestr",
|
"lists.account.remove": "Tynnu o'r rhestr",
|
||||||
"lists.delete": "Dileu rhestr",
|
"lists.delete": "Dileu rhestr",
|
||||||
|
@ -496,23 +502,24 @@
|
||||||
"navigation_bar.security": "Diogelwch",
|
"navigation_bar.security": "Diogelwch",
|
||||||
"not_signed_in_indicator.not_signed_in": "Rhaid i chi fewngofnodi i weld yr adnodd hwn.",
|
"not_signed_in_indicator.not_signed_in": "Rhaid i chi fewngofnodi i weld yr adnodd hwn.",
|
||||||
"notification.admin.report": "Adroddwyd ar {name} {target}",
|
"notification.admin.report": "Adroddwyd ar {name} {target}",
|
||||||
"notification.admin.report_account": "{name} reported {count, plural, one {un postiad} other {# postiad}} from {target} for {category}",
|
"notification.admin.report_account": "Adroddodd {name} {count, plural, one {un postiad} other {# postiad}} gan {target} oherwydd {category}",
|
||||||
"notification.admin.report_account_other": "Adroddodd {name} {count, plural, one {un postiad} two {# bostiad} few {# phost} other {# postiad}} gan {target}",
|
"notification.admin.report_account_other": "Adroddodd {name} {count, plural, one {un postiad} two {# bostiad} few {# postiad} other {# postiad}} gan {target}",
|
||||||
"notification.admin.report_statuses": "Adroddodd {name} {target} ar gyfer {category}",
|
"notification.admin.report_statuses": "Adroddodd {name} {target} ar gyfer {category}",
|
||||||
"notification.admin.report_statuses_other": "Adroddodd {name} {target}",
|
"notification.admin.report_statuses_other": "Adroddodd {name} {target}",
|
||||||
"notification.admin.sign_up": "Cofrestrodd {name}",
|
"notification.admin.sign_up": "Cofrestrodd {name}",
|
||||||
"notification.admin.sign_up.name_and_others": "Cofrestrodd {name} {count, plural, one {ac # arall} other {a # eraill}}",
|
"notification.admin.sign_up.name_and_others": "Cofrestrodd {name} {count, plural, one {ac # arall} other {a # arall}}",
|
||||||
"notification.favourite": "Ffafriodd {name} eich postiad",
|
"notification.favourite": "Ffafriodd {name} eich postiad",
|
||||||
"notification.favourite.name_and_others_with_link": "Ffafriodd {name} a <a>{count, plural, one {# arall} other {# eraill}}</a> eich postiad",
|
"notification.favourite.name_and_others_with_link": "Ffafriodd {name} a <a>{count, plural, one {# arall} other {# arall}}</a> eich postiad",
|
||||||
"notification.follow": "Dilynodd {name} chi",
|
"notification.follow": "Dilynodd {name} chi",
|
||||||
"notification.follow.name_and_others": "Mae {name} a {count, plural, one {# other} other {# others}} wedi'ch dilyn chi",
|
"notification.follow.name_and_others": "Mae {name} a <a>{count, plural, zero {}one {# arall} two {# arall} few {# arall} many {# others} other {# arall}}</a> nawr yn eich dilyn chi",
|
||||||
"notification.follow_request": "Mae {name} wedi gwneud cais i'ch dilyn",
|
"notification.follow_request": "Mae {name} wedi gwneud cais i'ch dilyn",
|
||||||
"notification.follow_request.name_and_others": "Mae {name} a{count, plural, one {# other} other {# others}} wedi gofyn i'ch dilyn chi",
|
"notification.follow_request.name_and_others": "Mae {name} a{count, plural, one {# arall} other {# arall}} wedi gofyn i'ch dilyn chi",
|
||||||
"notification.label.mention": "Crybwyll",
|
"notification.label.mention": "Crybwyll",
|
||||||
"notification.label.private_mention": "Crybwyll preifat",
|
"notification.label.private_mention": "Crybwyll preifat",
|
||||||
"notification.label.private_reply": "Ateb preifat",
|
"notification.label.private_reply": "Ateb preifat",
|
||||||
"notification.label.reply": "Ateb",
|
"notification.label.reply": "Ateb",
|
||||||
"notification.mention": "Crybwyll",
|
"notification.mention": "Crybwyll",
|
||||||
|
"notification.mentioned_you": "Rydych wedi'ch crybwyll gan {name}",
|
||||||
"notification.moderation-warning.learn_more": "Dysgu mwy",
|
"notification.moderation-warning.learn_more": "Dysgu mwy",
|
||||||
"notification.moderation_warning": "Rydych wedi derbyn rhybudd gan gymedrolwr",
|
"notification.moderation_warning": "Rydych wedi derbyn rhybudd gan gymedrolwr",
|
||||||
"notification.moderation_warning.action_delete_statuses": "Mae rhai o'ch postiadau wedi'u dileu.",
|
"notification.moderation_warning.action_delete_statuses": "Mae rhai o'ch postiadau wedi'u dileu.",
|
||||||
|
@ -525,7 +532,7 @@
|
||||||
"notification.own_poll": "Mae eich pleidlais wedi dod i ben",
|
"notification.own_poll": "Mae eich pleidlais wedi dod i ben",
|
||||||
"notification.poll": "Mae arolwg y gwnaethoch bleidleisio ynddo wedi dod i ben",
|
"notification.poll": "Mae arolwg y gwnaethoch bleidleisio ynddo wedi dod i ben",
|
||||||
"notification.reblog": "Hybodd {name} eich post",
|
"notification.reblog": "Hybodd {name} eich post",
|
||||||
"notification.reblog.name_and_others_with_link": "Mae {name} a <a>{count, plural, one {# other} other {# others}}</a> wedi hybu eich postiad",
|
"notification.reblog.name_and_others_with_link": "Mae {name} a <a>{count, plural, one {# arall} other {# arall}}</a> wedi hybu eich postiad",
|
||||||
"notification.relationships_severance_event": "Wedi colli cysylltiad â {name}",
|
"notification.relationships_severance_event": "Wedi colli cysylltiad â {name}",
|
||||||
"notification.relationships_severance_event.account_suspension": "Mae gweinyddwr o {from} wedi atal {target}, sy'n golygu na allwch dderbyn diweddariadau ganddynt mwyach na rhyngweithio â nhw.",
|
"notification.relationships_severance_event.account_suspension": "Mae gweinyddwr o {from} wedi atal {target}, sy'n golygu na allwch dderbyn diweddariadau ganddynt mwyach na rhyngweithio â nhw.",
|
||||||
"notification.relationships_severance_event.domain_block": "Mae gweinyddwr o {from} wedi blocio {target}, gan gynnwys {followersCount} o'ch dilynwyr a {followingCount, plural, one {# cyfrif} other {# cyfrif}} arall rydych chi'n ei ddilyn.",
|
"notification.relationships_severance_event.domain_block": "Mae gweinyddwr o {from} wedi blocio {target}, gan gynnwys {followersCount} o'ch dilynwyr a {followingCount, plural, one {# cyfrif} other {# cyfrif}} arall rydych chi'n ei ddilyn.",
|
||||||
|
@ -534,9 +541,9 @@
|
||||||
"notification.status": "{name} newydd ei bostio",
|
"notification.status": "{name} newydd ei bostio",
|
||||||
"notification.update": "Golygodd {name} bostiad",
|
"notification.update": "Golygodd {name} bostiad",
|
||||||
"notification_requests.accept": "Derbyn",
|
"notification_requests.accept": "Derbyn",
|
||||||
"notification_requests.accept_multiple": "{count, plural, one {Accept # request…} other {Accept # requests…}}",
|
"notification_requests.accept_multiple": "{count, plural, one {Derbyn # cais…} other {Derbyn # cais…}}",
|
||||||
"notification_requests.confirm_accept_multiple.button": "{count, plural, one {Accept request} other {Accept requests}}",
|
"notification_requests.confirm_accept_multiple.button": "{count, plural, one {Derbyn cais} other {Derbyn cais}}",
|
||||||
"notification_requests.confirm_accept_multiple.message": "Rydych ar fin derbyn {count, plural, one {one notification request} other {# notification requests}}. Ydych chi'n siŵr eich bod am barhau?",
|
"notification_requests.confirm_accept_multiple.message": "Rydych ar fin derbyn {count, plural, one {un cais hysbysiad} other {# cais hysbysiad}}. Ydych chi'n siŵr eich bod am barhau?",
|
||||||
"notification_requests.confirm_accept_multiple.title": "Derbyn ceisiadau hysbysu?",
|
"notification_requests.confirm_accept_multiple.title": "Derbyn ceisiadau hysbysu?",
|
||||||
"notification_requests.confirm_dismiss_multiple.button": "{count, plural, one {Diystyru cais} other {Diystyru ceisiadau}}",
|
"notification_requests.confirm_dismiss_multiple.button": "{count, plural, one {Diystyru cais} other {Diystyru ceisiadau}}",
|
||||||
"notification_requests.confirm_dismiss_multiple.message": "Rydych ar fin diystyru {count, plural, one {un cais hysbysu} other {# cais hysbysiad}}. Fyddwch chi ddim yn gallu cyrchu {count, plural, one {it} other {them}} yn hawdd eto. Ydych chi'n yn siŵr eich bod am fwrw ymlaen?",
|
"notification_requests.confirm_dismiss_multiple.message": "Rydych ar fin diystyru {count, plural, one {un cais hysbysu} other {# cais hysbysiad}}. Fyddwch chi ddim yn gallu cyrchu {count, plural, one {it} other {them}} yn hawdd eto. Ydych chi'n yn siŵr eich bod am fwrw ymlaen?",
|
||||||
|
@ -563,6 +570,7 @@
|
||||||
"notifications.column_settings.filter_bar.category": "Bar hidlo cyflym",
|
"notifications.column_settings.filter_bar.category": "Bar hidlo cyflym",
|
||||||
"notifications.column_settings.follow": "Dilynwyr newydd:",
|
"notifications.column_settings.follow": "Dilynwyr newydd:",
|
||||||
"notifications.column_settings.follow_request": "Ceisiadau dilyn newydd:",
|
"notifications.column_settings.follow_request": "Ceisiadau dilyn newydd:",
|
||||||
|
"notifications.column_settings.group": "Grŵp",
|
||||||
"notifications.column_settings.mention": "Crybwylliadau:",
|
"notifications.column_settings.mention": "Crybwylliadau:",
|
||||||
"notifications.column_settings.poll": "Canlyniadau pleidlais:",
|
"notifications.column_settings.poll": "Canlyniadau pleidlais:",
|
||||||
"notifications.column_settings.push": "Hysbysiadau gwthiadwy",
|
"notifications.column_settings.push": "Hysbysiadau gwthiadwy",
|
||||||
|
@ -684,7 +692,7 @@
|
||||||
"relative_time.minutes": "{number} munud",
|
"relative_time.minutes": "{number} munud",
|
||||||
"relative_time.seconds": "{number} eiliad",
|
"relative_time.seconds": "{number} eiliad",
|
||||||
"relative_time.today": "heddiw",
|
"relative_time.today": "heddiw",
|
||||||
"reply_indicator.attachments": "{count, plural, one {# attachment} arall {# attachments}}",
|
"reply_indicator.attachments": "{count, plural, one {# atodiad} other {# atodiad}}",
|
||||||
"reply_indicator.cancel": "Canslo",
|
"reply_indicator.cancel": "Canslo",
|
||||||
"reply_indicator.poll": "Arolwg",
|
"reply_indicator.poll": "Arolwg",
|
||||||
"report.block": "Blocio",
|
"report.block": "Blocio",
|
||||||
|
@ -727,7 +735,7 @@
|
||||||
"report.thanks.title_actionable": "Diolch am adrodd, byddwn yn ymchwilio i hyn.",
|
"report.thanks.title_actionable": "Diolch am adrodd, byddwn yn ymchwilio i hyn.",
|
||||||
"report.unfollow": "Dad-ddilyn @{name}",
|
"report.unfollow": "Dad-ddilyn @{name}",
|
||||||
"report.unfollow_explanation": "Rydych chi'n dilyn y cyfrif hwn. I beidio â gweld eu postiadau yn eich ffrwd gartref mwyach, dad-ddilynwch nhw.",
|
"report.unfollow_explanation": "Rydych chi'n dilyn y cyfrif hwn. I beidio â gweld eu postiadau yn eich ffrwd gartref mwyach, dad-ddilynwch nhw.",
|
||||||
"report_notification.attached_statuses": "{count, plural, one {{count} postiad} arall {{count} postiad}} atodwyd",
|
"report_notification.attached_statuses": "{count, plural, one {{count} postiad} other {{count} postiad}} wedi'i atodi",
|
||||||
"report_notification.categories.legal": "Cyfreithiol",
|
"report_notification.categories.legal": "Cyfreithiol",
|
||||||
"report_notification.categories.legal_sentence": "cynnwys anghyfreithlon",
|
"report_notification.categories.legal_sentence": "cynnwys anghyfreithlon",
|
||||||
"report_notification.categories.other": "Arall",
|
"report_notification.categories.other": "Arall",
|
||||||
|
@ -807,7 +815,7 @@
|
||||||
"status.reblog": "Hybu",
|
"status.reblog": "Hybu",
|
||||||
"status.reblog_private": "Hybu i'r gynulleidfa wreiddiol",
|
"status.reblog_private": "Hybu i'r gynulleidfa wreiddiol",
|
||||||
"status.reblogged_by": "Hybodd {name}",
|
"status.reblogged_by": "Hybodd {name}",
|
||||||
"status.reblogs": "{count, plural, one {hwb} other {hwb}}",
|
"status.reblogs": "{count, plural, one {# hwb} other {# hwb}}",
|
||||||
"status.reblogs.empty": "Does neb wedi hybio'r post yma eto. Pan y bydd rhywun yn gwneud, byddent yn ymddangos yma.",
|
"status.reblogs.empty": "Does neb wedi hybio'r post yma eto. Pan y bydd rhywun yn gwneud, byddent yn ymddangos yma.",
|
||||||
"status.redraft": "Dileu ac ailddrafftio",
|
"status.redraft": "Dileu ac ailddrafftio",
|
||||||
"status.remove_bookmark": "Tynnu nod tudalen",
|
"status.remove_bookmark": "Tynnu nod tudalen",
|
||||||
|
@ -849,6 +857,11 @@
|
||||||
"upload_error.poll": "Nid oes modd llwytho ffeiliau â phleidleisiau.",
|
"upload_error.poll": "Nid oes modd llwytho ffeiliau â phleidleisiau.",
|
||||||
"upload_form.audio_description": "Disgrifio ar gyfer pobl sydd â cholled clyw",
|
"upload_form.audio_description": "Disgrifio ar gyfer pobl sydd â cholled clyw",
|
||||||
"upload_form.description": "Disgrifio i'r rheini a nam ar ei golwg",
|
"upload_form.description": "Disgrifio i'r rheini a nam ar ei golwg",
|
||||||
|
"upload_form.drag_and_drop.instructions": "I godi atodiad cyfryngau, pwyswch y space neu enter. Wrth lusgo, defnyddiwch y bysellau saeth i symud yr atodiad cyfryngau i unrhyw gyfeiriad penodol. Pwyswch space neu enter eto i ollwng yr atodiad cyfryngau yn ei safle newydd, neu pwyswch escape i ddiddymu.",
|
||||||
|
"upload_form.drag_and_drop.on_drag_cancel": "Cafodd llusgo ei ddiddymu. Cafodd atodiad cyfryngau {item} ei ollwng.",
|
||||||
|
"upload_form.drag_and_drop.on_drag_end": "Cafodd atodiad cyfryngau {item} ei ollwng.",
|
||||||
|
"upload_form.drag_and_drop.on_drag_over": "Symudwyd atodiad cyfryngau {item}.",
|
||||||
|
"upload_form.drag_and_drop.on_drag_start": "Atodiad cyfryngau godwyd {item}.",
|
||||||
"upload_form.edit": "Golygu",
|
"upload_form.edit": "Golygu",
|
||||||
"upload_form.thumbnail": "Newid llun bach",
|
"upload_form.thumbnail": "Newid llun bach",
|
||||||
"upload_form.video_description": "Disgrifio ar gyfer pobl sydd â cholled clyw neu amhariad golwg",
|
"upload_form.video_description": "Disgrifio ar gyfer pobl sydd â cholled clyw neu amhariad golwg",
|
||||||
|
|
|
@ -158,7 +158,6 @@
|
||||||
"compose_form.poll.duration": "Afstemningens varighed",
|
"compose_form.poll.duration": "Afstemningens varighed",
|
||||||
"compose_form.poll.multiple": "Multivalg",
|
"compose_form.poll.multiple": "Multivalg",
|
||||||
"compose_form.poll.option_placeholder": "Valgmulighed {number}",
|
"compose_form.poll.option_placeholder": "Valgmulighed {number}",
|
||||||
"compose_form.poll.single": "Vælg én",
|
|
||||||
"compose_form.poll.switch_to_multiple": "Ændr afstemning til flervalgstype",
|
"compose_form.poll.switch_to_multiple": "Ændr afstemning til flervalgstype",
|
||||||
"compose_form.poll.switch_to_single": "Ændr afstemning til enkeltvalgstype",
|
"compose_form.poll.switch_to_single": "Ændr afstemning til enkeltvalgstype",
|
||||||
"compose_form.poll.type": "Stil",
|
"compose_form.poll.type": "Stil",
|
||||||
|
@ -197,6 +196,7 @@
|
||||||
"confirmations.unfollow.title": "Følg ikke længere bruger?",
|
"confirmations.unfollow.title": "Følg ikke længere bruger?",
|
||||||
"content_warning.hide": "Skjul indlæg",
|
"content_warning.hide": "Skjul indlæg",
|
||||||
"content_warning.show": "Vis alligevel",
|
"content_warning.show": "Vis alligevel",
|
||||||
|
"content_warning.show_more": "Vis flere",
|
||||||
"conversation.delete": "Slet samtale",
|
"conversation.delete": "Slet samtale",
|
||||||
"conversation.mark_as_read": "Markér som læst",
|
"conversation.mark_as_read": "Markér som læst",
|
||||||
"conversation.open": "Vis samtale",
|
"conversation.open": "Vis samtale",
|
||||||
|
@ -305,7 +305,7 @@
|
||||||
"filter_modal.select_filter.subtitle": "Vælg en eksisterende kategori eller opret en ny",
|
"filter_modal.select_filter.subtitle": "Vælg en eksisterende kategori eller opret en ny",
|
||||||
"filter_modal.select_filter.title": "Filtrér dette indlæg",
|
"filter_modal.select_filter.title": "Filtrér dette indlæg",
|
||||||
"filter_modal.title.status": "Filtrér et indlæg",
|
"filter_modal.title.status": "Filtrér et indlæg",
|
||||||
"filter_warning.matches_filter": "Matcher filteret “{title}”",
|
"filter_warning.matches_filter": "Matcher filteret “<span>{title}</span>”",
|
||||||
"filtered_notifications_banner.pending_requests": "Fra {count, plural, =0 {ingen} one {én person} other {# personer}}, man måske kender",
|
"filtered_notifications_banner.pending_requests": "Fra {count, plural, =0 {ingen} one {én person} other {# personer}}, man måske kender",
|
||||||
"filtered_notifications_banner.title": "Filtrerede notifikationer",
|
"filtered_notifications_banner.title": "Filtrerede notifikationer",
|
||||||
"firehose.all": "Alle",
|
"firehose.all": "Alle",
|
||||||
|
@ -385,6 +385,7 @@
|
||||||
"interaction_modal.description.follow": "Med en konto på Mastodon kan du følge {name} for at modtage vedkommendes indlæg i dit hjemmefeed.",
|
"interaction_modal.description.follow": "Med en konto på Mastodon kan du følge {name} for at modtage vedkommendes indlæg i dit hjemmefeed.",
|
||||||
"interaction_modal.description.reblog": "Med en konto på Mastodon kan dette indlæg fremhæves så det deles med egne følgere.",
|
"interaction_modal.description.reblog": "Med en konto på Mastodon kan dette indlæg fremhæves så det deles med egne følgere.",
|
||||||
"interaction_modal.description.reply": "Med en konto på Mastodon kan dette indlæg besvares.",
|
"interaction_modal.description.reply": "Med en konto på Mastodon kan dette indlæg besvares.",
|
||||||
|
"interaction_modal.description.vote": "Med en konto på Mastodon kan man deltage i denne afstemning.",
|
||||||
"interaction_modal.login.action": "Gå til hjemmeserver",
|
"interaction_modal.login.action": "Gå til hjemmeserver",
|
||||||
"interaction_modal.login.prompt": "Hjemmeserverdomænet, f.eks. mastodon.social",
|
"interaction_modal.login.prompt": "Hjemmeserverdomænet, f.eks. mastodon.social",
|
||||||
"interaction_modal.no_account_yet": "Ikke på Mastodon?",
|
"interaction_modal.no_account_yet": "Ikke på Mastodon?",
|
||||||
|
@ -396,6 +397,7 @@
|
||||||
"interaction_modal.title.follow": "Følg {name}",
|
"interaction_modal.title.follow": "Følg {name}",
|
||||||
"interaction_modal.title.reblog": "Boost {name}s indlæg",
|
"interaction_modal.title.reblog": "Boost {name}s indlæg",
|
||||||
"interaction_modal.title.reply": "Besvar {name}s indlæg",
|
"interaction_modal.title.reply": "Besvar {name}s indlæg",
|
||||||
|
"interaction_modal.title.vote": "Deltag i {name}s afstemning",
|
||||||
"intervals.full.days": "{number, plural, one {# dag} other {# dage}}",
|
"intervals.full.days": "{number, plural, one {# dag} other {# dage}}",
|
||||||
"intervals.full.hours": "{number, plural, one {# time} other {# timer}}",
|
"intervals.full.hours": "{number, plural, one {# time} other {# timer}}",
|
||||||
"intervals.full.minutes": "{number, plural, one {# minut} other {# minutter}}",
|
"intervals.full.minutes": "{number, plural, one {# minut} other {# minutter}}",
|
||||||
|
@ -508,7 +510,7 @@
|
||||||
"notification.favourite": "{name} favoritmarkerede dit indlæg",
|
"notification.favourite": "{name} favoritmarkerede dit indlæg",
|
||||||
"notification.favourite.name_and_others_with_link": "{name} og <a>{count, plural, one {# anden} other {# andre}}</a> gjorde dit indlæg til favorit",
|
"notification.favourite.name_and_others_with_link": "{name} og <a>{count, plural, one {# anden} other {# andre}}</a> gjorde dit indlæg til favorit",
|
||||||
"notification.follow": "{name} begyndte at følge dig",
|
"notification.follow": "{name} begyndte at følge dig",
|
||||||
"notification.follow.name_and_others": "{name} og {count, plural, one {# anden} other {# andre}} følger dig",
|
"notification.follow.name_and_others": "{name} og <a>{count, plural, one {# andre} other {# andre}}</a> begyndte at følge dig",
|
||||||
"notification.follow_request": "{name} har anmodet om at følge dig",
|
"notification.follow_request": "{name} har anmodet om at følge dig",
|
||||||
"notification.follow_request.name_and_others": "{name} og {count, plural, one {# anden} other {# andre}} har anmodet om at følger dig",
|
"notification.follow_request.name_and_others": "{name} og {count, plural, one {# anden} other {# andre}} har anmodet om at følger dig",
|
||||||
"notification.label.mention": "Omtale",
|
"notification.label.mention": "Omtale",
|
||||||
|
@ -516,6 +518,7 @@
|
||||||
"notification.label.private_reply": "Privat svar",
|
"notification.label.private_reply": "Privat svar",
|
||||||
"notification.label.reply": "Besvar",
|
"notification.label.reply": "Besvar",
|
||||||
"notification.mention": "Omtale",
|
"notification.mention": "Omtale",
|
||||||
|
"notification.mentioned_you": "{name} nævnte dig",
|
||||||
"notification.moderation-warning.learn_more": "Læs mere",
|
"notification.moderation-warning.learn_more": "Læs mere",
|
||||||
"notification.moderation_warning": "Du er tildelt en moderationsadvarsel",
|
"notification.moderation_warning": "Du er tildelt en moderationsadvarsel",
|
||||||
"notification.moderation_warning.action_delete_statuses": "Nogle af dine indlæg er blevet fjernet.",
|
"notification.moderation_warning.action_delete_statuses": "Nogle af dine indlæg er blevet fjernet.",
|
||||||
|
@ -566,6 +569,7 @@
|
||||||
"notifications.column_settings.filter_bar.category": "Hurtigfiltreringsbjælke",
|
"notifications.column_settings.filter_bar.category": "Hurtigfiltreringsbjælke",
|
||||||
"notifications.column_settings.follow": "Nye følgere:",
|
"notifications.column_settings.follow": "Nye følgere:",
|
||||||
"notifications.column_settings.follow_request": "Nye følgeanmodninger:",
|
"notifications.column_settings.follow_request": "Nye følgeanmodninger:",
|
||||||
|
"notifications.column_settings.group": "Gruppere",
|
||||||
"notifications.column_settings.mention": "Omtaler:",
|
"notifications.column_settings.mention": "Omtaler:",
|
||||||
"notifications.column_settings.poll": "Afstemningsresultater:",
|
"notifications.column_settings.poll": "Afstemningsresultater:",
|
||||||
"notifications.column_settings.push": "Push-notifikationer",
|
"notifications.column_settings.push": "Push-notifikationer",
|
||||||
|
@ -852,6 +856,11 @@
|
||||||
"upload_error.poll": "Filupload ikke tilladt for afstemninger.",
|
"upload_error.poll": "Filupload ikke tilladt for afstemninger.",
|
||||||
"upload_form.audio_description": "Beskrivelse til hørehæmmede",
|
"upload_form.audio_description": "Beskrivelse til hørehæmmede",
|
||||||
"upload_form.description": "Beskrivelse til svagtseende",
|
"upload_form.description": "Beskrivelse til svagtseende",
|
||||||
|
"upload_form.drag_and_drop.instructions": "For at opsamle en medievedhæftning, tryk på Mellemrum eller Retur. Mens der trækkes, benyt piletasterne til at flytte medievedhæftningen i en given retning. Tryk på Mellemrum eller Retur igen for at slippe medievedhæftningen på den nye position, eller tryk på Escape for at afbryde.",
|
||||||
|
"upload_form.drag_and_drop.on_drag_cancel": "Træk blev afbrudt. Medievedhæftningen {item} blev sluppet.",
|
||||||
|
"upload_form.drag_and_drop.on_drag_end": "Medievedhæftningen {item} er sluppet.",
|
||||||
|
"upload_form.drag_and_drop.on_drag_over": "Medievedhæftningen {item} er flyttet.",
|
||||||
|
"upload_form.drag_and_drop.on_drag_start": "Opsamlede medievedhæftningen {item}.",
|
||||||
"upload_form.edit": "Redigér",
|
"upload_form.edit": "Redigér",
|
||||||
"upload_form.thumbnail": "Skift miniature",
|
"upload_form.thumbnail": "Skift miniature",
|
||||||
"upload_form.video_description": "Beskrivelse for hørehæmmede eller synshandicappede personer",
|
"upload_form.video_description": "Beskrivelse for hørehæmmede eller synshandicappede personer",
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
"account.go_to_profile": "Profil aufrufen",
|
"account.go_to_profile": "Profil aufrufen",
|
||||||
"account.hide_reblogs": "Geteilte Beiträge von @{name} ausblenden",
|
"account.hide_reblogs": "Geteilte Beiträge von @{name} ausblenden",
|
||||||
"account.in_memoriam": "Zum Andenken.",
|
"account.in_memoriam": "Zum Andenken.",
|
||||||
"account.joined_short": "Beigetreten",
|
"account.joined_short": "Mitglied seit",
|
||||||
"account.languages": "Ausgewählte Sprachen ändern",
|
"account.languages": "Ausgewählte Sprachen ändern",
|
||||||
"account.link_verified_on": "Das Profil mit dieser E-Mail-Adresse wurde bereits am {date} bestätigt",
|
"account.link_verified_on": "Das Profil mit dieser E-Mail-Adresse wurde bereits am {date} bestätigt",
|
||||||
"account.locked_info": "Die Privatsphäre dieses Kontos wurde auf „geschützt“ gesetzt. Die Person bestimmt manuell, wer ihrem Profil folgen darf.",
|
"account.locked_info": "Die Privatsphäre dieses Kontos wurde auf „geschützt“ gesetzt. Die Person bestimmt manuell, wer ihrem Profil folgen darf.",
|
||||||
|
@ -197,6 +197,7 @@
|
||||||
"confirmations.unfollow.title": "Profil entfolgen?",
|
"confirmations.unfollow.title": "Profil entfolgen?",
|
||||||
"content_warning.hide": "Beitrag ausblenden",
|
"content_warning.hide": "Beitrag ausblenden",
|
||||||
"content_warning.show": "Trotzdem anzeigen",
|
"content_warning.show": "Trotzdem anzeigen",
|
||||||
|
"content_warning.show_more": "Mehr anzeigen",
|
||||||
"conversation.delete": "Unterhaltung löschen",
|
"conversation.delete": "Unterhaltung löschen",
|
||||||
"conversation.mark_as_read": "Als gelesen markieren",
|
"conversation.mark_as_read": "Als gelesen markieren",
|
||||||
"conversation.open": "Unterhaltung anzeigen",
|
"conversation.open": "Unterhaltung anzeigen",
|
||||||
|
@ -229,14 +230,14 @@
|
||||||
"domain_pill.activitypub_like_language": "ActivityPub ist sozusagen die Sprache, die Mastodon mit anderen sozialen Netzwerken spricht.",
|
"domain_pill.activitypub_like_language": "ActivityPub ist sozusagen die Sprache, die Mastodon mit anderen sozialen Netzwerken spricht.",
|
||||||
"domain_pill.server": "Server",
|
"domain_pill.server": "Server",
|
||||||
"domain_pill.their_handle": "Deren Adresse:",
|
"domain_pill.their_handle": "Deren Adresse:",
|
||||||
"domain_pill.their_server": "Deren digitales Zuhause. Hier „leben“ alle Beiträge von diesem Profil.",
|
"domain_pill.their_server": "Deren digitale Heimat. Hier „leben“ alle Beiträge von diesem Profil.",
|
||||||
"domain_pill.their_username": "Deren eindeutigen Identität auf dem betreffenden Server. Es ist möglich, Profile mit dem gleichen Profilnamen auf verschiedenen Servern zu finden.",
|
"domain_pill.their_username": "Deren eindeutigen Identität auf dem betreffenden Server. Es ist möglich, Profile mit dem gleichen Profilnamen auf verschiedenen Servern zu finden.",
|
||||||
"domain_pill.username": "Profilname",
|
"domain_pill.username": "Profilname",
|
||||||
"domain_pill.whats_in_a_handle": "Was ist Teil der Adresse?",
|
"domain_pill.whats_in_a_handle": "Was ist Teil der Adresse?",
|
||||||
"domain_pill.who_they_are": "Adressen teilen mit, wer jemand ist und wo sich jemand aufhält. Daher kannst du mit Leuten im gesamten Social Web interagieren, wenn es eine durch <button>ActivityPub angetriebene Plattform</button> ist.",
|
"domain_pill.who_they_are": "Adressen teilen mit, wer jemand ist und wo sich jemand aufhält. Daher kannst du mit Leuten im gesamten Social Web interagieren, wenn es eine durch <button>ActivityPub angetriebene Plattform</button> ist.",
|
||||||
"domain_pill.who_you_are": "Deine Adresse teilt mit, wer du bist und wo du dich aufhältst. Daher können andere Leute im gesamten Social Web mit dir interagieren, wenn es eine durch <button>ActivityPub angetriebene Plattform</button> ist.",
|
"domain_pill.who_you_are": "Deine Adresse teilt mit, wer du bist und wo du dich aufhältst. Daher können andere Leute im gesamten Social Web mit dir interagieren, wenn es eine durch <button>ActivityPub angetriebene Plattform</button> ist.",
|
||||||
"domain_pill.your_handle": "Deine Adresse:",
|
"domain_pill.your_handle": "Deine Adresse:",
|
||||||
"domain_pill.your_server": "Dein digitales Zuhause. Hier „leben“ alle Beiträge von dir. Dir gefällt es hier nicht? Du kannst jederzeit den Server wechseln und ebenso deine Follower übertragen.",
|
"domain_pill.your_server": "Deine digitale Heimat. Hier „leben“ alle Beiträge von dir. Falls es dir hier nicht gefällt, kannst du jederzeit den Server wechseln und ebenso deine Follower übertragen.",
|
||||||
"domain_pill.your_username": "Deine eindeutige Identität auf diesem Server. Es ist möglich, Profile mit dem gleichen Profilnamen auf verschiedenen Servern zu finden.",
|
"domain_pill.your_username": "Deine eindeutige Identität auf diesem Server. Es ist möglich, Profile mit dem gleichen Profilnamen auf verschiedenen Servern zu finden.",
|
||||||
"embed.instructions": "Du kannst diesen Beitrag auf deiner Website einbetten, indem du den nachfolgenden Code kopierst.",
|
"embed.instructions": "Du kannst diesen Beitrag auf deiner Website einbetten, indem du den nachfolgenden Code kopierst.",
|
||||||
"embed.preview": "Vorschau:",
|
"embed.preview": "Vorschau:",
|
||||||
|
@ -305,7 +306,7 @@
|
||||||
"filter_modal.select_filter.subtitle": "Einem vorhandenen Filter hinzufügen oder einen neuen erstellen",
|
"filter_modal.select_filter.subtitle": "Einem vorhandenen Filter hinzufügen oder einen neuen erstellen",
|
||||||
"filter_modal.select_filter.title": "Diesen Beitrag filtern",
|
"filter_modal.select_filter.title": "Diesen Beitrag filtern",
|
||||||
"filter_modal.title.status": "Beitrag per Filter ausblenden",
|
"filter_modal.title.status": "Beitrag per Filter ausblenden",
|
||||||
"filter_warning.matches_filter": "Übereinstimmend mit dem Filter „{title}“",
|
"filter_warning.matches_filter": "Übereinstimmend mit dem Filter „<span>{title}</span>“",
|
||||||
"filtered_notifications_banner.pending_requests": "Von {count, plural, =0 {keinem, den} one {einer Person, die} other {# Personen, die}} du möglicherweise kennst",
|
"filtered_notifications_banner.pending_requests": "Von {count, plural, =0 {keinem, den} one {einer Person, die} other {# Personen, die}} du möglicherweise kennst",
|
||||||
"filtered_notifications_banner.title": "Gefilterte Benachrichtigungen",
|
"filtered_notifications_banner.title": "Gefilterte Benachrichtigungen",
|
||||||
"firehose.all": "Alles",
|
"firehose.all": "Alles",
|
||||||
|
@ -385,6 +386,7 @@
|
||||||
"interaction_modal.description.follow": "Mit einem Mastodon-Konto kannst du {name} folgen, um die Beiträge auf deiner Startseite zu sehen.",
|
"interaction_modal.description.follow": "Mit einem Mastodon-Konto kannst du {name} folgen, um die Beiträge auf deiner Startseite zu sehen.",
|
||||||
"interaction_modal.description.reblog": "Mit einem Mastodon-Konto kannst du die Reichweite dieses Beitrags erhöhen, indem du ihn mit deinen Followern teilst.",
|
"interaction_modal.description.reblog": "Mit einem Mastodon-Konto kannst du die Reichweite dieses Beitrags erhöhen, indem du ihn mit deinen Followern teilst.",
|
||||||
"interaction_modal.description.reply": "Mit einem Mastodon-Konto kannst du auf diesen Beitrag antworten.",
|
"interaction_modal.description.reply": "Mit einem Mastodon-Konto kannst du auf diesen Beitrag antworten.",
|
||||||
|
"interaction_modal.description.vote": "Mit einem Mastodon-Konto kannst du an dieser Umfrage teilnehmen.",
|
||||||
"interaction_modal.login.action": "Zurück zur Startseite",
|
"interaction_modal.login.action": "Zurück zur Startseite",
|
||||||
"interaction_modal.login.prompt": "Adresse deines Servers, z. B. mastodon.social",
|
"interaction_modal.login.prompt": "Adresse deines Servers, z. B. mastodon.social",
|
||||||
"interaction_modal.no_account_yet": "Nicht auf Mastodon?",
|
"interaction_modal.no_account_yet": "Nicht auf Mastodon?",
|
||||||
|
@ -396,6 +398,7 @@
|
||||||
"interaction_modal.title.follow": "Folge {name}",
|
"interaction_modal.title.follow": "Folge {name}",
|
||||||
"interaction_modal.title.reblog": "Beitrag von {name} teilen",
|
"interaction_modal.title.reblog": "Beitrag von {name} teilen",
|
||||||
"interaction_modal.title.reply": "Auf Beitrag von {name} antworten",
|
"interaction_modal.title.reply": "Auf Beitrag von {name} antworten",
|
||||||
|
"interaction_modal.title.vote": "An der Umfrage von {name} teilnehmen",
|
||||||
"intervals.full.days": "{number, plural, one {# Tag} other {# Tage}}",
|
"intervals.full.days": "{number, plural, one {# Tag} other {# Tage}}",
|
||||||
"intervals.full.hours": "{number, plural, one {# Stunde} other {# Stunden}}",
|
"intervals.full.hours": "{number, plural, one {# Stunde} other {# Stunden}}",
|
||||||
"intervals.full.minutes": "{number, plural, one {# Minute} other {# Minuten}}",
|
"intervals.full.minutes": "{number, plural, one {# Minute} other {# Minuten}}",
|
||||||
|
@ -508,7 +511,7 @@
|
||||||
"notification.favourite": "{name} favorisierte deinen Beitrag",
|
"notification.favourite": "{name} favorisierte deinen Beitrag",
|
||||||
"notification.favourite.name_and_others_with_link": "{name} und <a>{count, plural, one {# weitere Person} other {# weitere Personen}}</a> favorisierten deinen Beitrag",
|
"notification.favourite.name_and_others_with_link": "{name} und <a>{count, plural, one {# weitere Person} other {# weitere Personen}}</a> favorisierten deinen Beitrag",
|
||||||
"notification.follow": "{name} folgt dir",
|
"notification.follow": "{name} folgt dir",
|
||||||
"notification.follow.name_and_others": "{name} und {count, plural, one {# weitere Person} other {# weitere Personen}} folgen dir",
|
"notification.follow.name_and_others": "{name} und <a>{count, plural, one {# weitere Person} other {# weitere Personen}}</a> folgen dir",
|
||||||
"notification.follow_request": "{name} möchte dir folgen",
|
"notification.follow_request": "{name} möchte dir folgen",
|
||||||
"notification.follow_request.name_and_others": "{name} und {count, plural, one {# weitere Person} other {# weitere Personen}} möchten dir folgen",
|
"notification.follow_request.name_and_others": "{name} und {count, plural, one {# weitere Person} other {# weitere Personen}} möchten dir folgen",
|
||||||
"notification.label.mention": "Erwähnung",
|
"notification.label.mention": "Erwähnung",
|
||||||
|
@ -516,6 +519,7 @@
|
||||||
"notification.label.private_reply": "Private Antwort",
|
"notification.label.private_reply": "Private Antwort",
|
||||||
"notification.label.reply": "Antwort",
|
"notification.label.reply": "Antwort",
|
||||||
"notification.mention": "Erwähnung",
|
"notification.mention": "Erwähnung",
|
||||||
|
"notification.mentioned_you": "{name} erwähnte dich",
|
||||||
"notification.moderation-warning.learn_more": "Mehr erfahren",
|
"notification.moderation-warning.learn_more": "Mehr erfahren",
|
||||||
"notification.moderation_warning": "Du wurdest von den Moderator*innen verwarnt",
|
"notification.moderation_warning": "Du wurdest von den Moderator*innen verwarnt",
|
||||||
"notification.moderation_warning.action_delete_statuses": "Einige deiner Beiträge sind entfernt worden.",
|
"notification.moderation_warning.action_delete_statuses": "Einige deiner Beiträge sind entfernt worden.",
|
||||||
|
@ -534,7 +538,7 @@
|
||||||
"notification.relationships_severance_event.domain_block": "Ein Admin von {from} hat {target} blockiert – darunter {followersCount} deiner Follower und {followingCount, plural, one {# Konto, dem} other {# Konten, denen}} du folgst.",
|
"notification.relationships_severance_event.domain_block": "Ein Admin von {from} hat {target} blockiert – darunter {followersCount} deiner Follower und {followingCount, plural, one {# Konto, dem} other {# Konten, denen}} du folgst.",
|
||||||
"notification.relationships_severance_event.learn_more": "Mehr erfahren",
|
"notification.relationships_severance_event.learn_more": "Mehr erfahren",
|
||||||
"notification.relationships_severance_event.user_domain_block": "Du hast {target} blockiert – {followersCount} deiner Follower und {followingCount, plural, one {# Konto, dem} other {# Konten, denen}} du folgst, wurden entfernt.",
|
"notification.relationships_severance_event.user_domain_block": "Du hast {target} blockiert – {followersCount} deiner Follower und {followingCount, plural, one {# Konto, dem} other {# Konten, denen}} du folgst, wurden entfernt.",
|
||||||
"notification.status": "{name} hat gerade etwas gepostet",
|
"notification.status": "{name} veröffentlichte gerade",
|
||||||
"notification.update": "{name} bearbeitete einen Beitrag",
|
"notification.update": "{name} bearbeitete einen Beitrag",
|
||||||
"notification_requests.accept": "Genehmigen",
|
"notification_requests.accept": "Genehmigen",
|
||||||
"notification_requests.accept_multiple": "{count, plural, one {# Anfrage genehmigen …} other {# Anfragen genehmigen …}}",
|
"notification_requests.accept_multiple": "{count, plural, one {# Anfrage genehmigen …} other {# Anfragen genehmigen …}}",
|
||||||
|
@ -566,6 +570,7 @@
|
||||||
"notifications.column_settings.filter_bar.category": "Filterleiste",
|
"notifications.column_settings.filter_bar.category": "Filterleiste",
|
||||||
"notifications.column_settings.follow": "Neue Follower:",
|
"notifications.column_settings.follow": "Neue Follower:",
|
||||||
"notifications.column_settings.follow_request": "Neue Follower-Anfragen:",
|
"notifications.column_settings.follow_request": "Neue Follower-Anfragen:",
|
||||||
|
"notifications.column_settings.group": "Gruppieren",
|
||||||
"notifications.column_settings.mention": "Erwähnungen:",
|
"notifications.column_settings.mention": "Erwähnungen:",
|
||||||
"notifications.column_settings.poll": "Umfrageergebnisse:",
|
"notifications.column_settings.poll": "Umfrageergebnisse:",
|
||||||
"notifications.column_settings.push": "Push-Benachrichtigungen",
|
"notifications.column_settings.push": "Push-Benachrichtigungen",
|
||||||
|
@ -596,15 +601,15 @@
|
||||||
"notifications.policy.filter": "Filtern",
|
"notifications.policy.filter": "Filtern",
|
||||||
"notifications.policy.filter_hint": "An gefilterte Benachrichtigungen im Posteingang senden",
|
"notifications.policy.filter_hint": "An gefilterte Benachrichtigungen im Posteingang senden",
|
||||||
"notifications.policy.filter_limited_accounts_hint": "Durch Server-Moderator*innen eingeschränkt",
|
"notifications.policy.filter_limited_accounts_hint": "Durch Server-Moderator*innen eingeschränkt",
|
||||||
"notifications.policy.filter_limited_accounts_title": "Moderierte Konten",
|
"notifications.policy.filter_limited_accounts_title": "moderierten Konten",
|
||||||
"notifications.policy.filter_new_accounts.hint": "Innerhalb {days, plural, one {des letzten Tages} other {der letzten # Tagen}} erstellt",
|
"notifications.policy.filter_new_accounts.hint": "Innerhalb {days, plural, one {des letzten Tages} other {der letzten # Tagen}} erstellt",
|
||||||
"notifications.policy.filter_new_accounts_title": "Neuen Konten",
|
"notifications.policy.filter_new_accounts_title": "neuen Konten",
|
||||||
"notifications.policy.filter_not_followers_hint": "Einschließlich Profilen, die dir seit weniger als {days, plural, one {einem Tag} other {# Tagen}} folgen",
|
"notifications.policy.filter_not_followers_hint": "Einschließlich Profilen, die dir seit weniger als {days, plural, one {einem Tag} other {# Tagen}} folgen",
|
||||||
"notifications.policy.filter_not_followers_title": "Profilen, die mir nicht folgen",
|
"notifications.policy.filter_not_followers_title": "Profilen, die mir nicht folgen",
|
||||||
"notifications.policy.filter_not_following_hint": "Bis du sie manuell genehmigst",
|
"notifications.policy.filter_not_following_hint": "Bis du sie manuell genehmigst",
|
||||||
"notifications.policy.filter_not_following_title": "Profilen, denen ich nicht folge",
|
"notifications.policy.filter_not_following_title": "Profilen, denen ich nicht folge",
|
||||||
"notifications.policy.filter_private_mentions_hint": "Solange sie keine Antwort auf deine Erwähnung ist oder du dem Profil nicht folgst",
|
"notifications.policy.filter_private_mentions_hint": "Solange sie keine Antwort auf deine Erwähnung ist oder du dem Profil nicht folgst",
|
||||||
"notifications.policy.filter_private_mentions_title": "Unerwünschten privaten Erwähnungen",
|
"notifications.policy.filter_private_mentions_title": "unerwünschten privaten Erwähnungen",
|
||||||
"notifications.policy.title": "Benachrichtigungen verwalten von …",
|
"notifications.policy.title": "Benachrichtigungen verwalten von …",
|
||||||
"notifications_permission_banner.enable": "Aktiviere Desktop-Benachrichtigungen",
|
"notifications_permission_banner.enable": "Aktiviere Desktop-Benachrichtigungen",
|
||||||
"notifications_permission_banner.how_to_control": "Um Benachrichtigungen zu erhalten, wenn Mastodon nicht geöffnet ist, aktiviere die Desktop-Benachrichtigungen. Du kannst genau bestimmen, welche Arten von Interaktionen Desktop-Benachrichtigungen über die {icon} -Taste erzeugen, sobald diese aktiviert sind.",
|
"notifications_permission_banner.how_to_control": "Um Benachrichtigungen zu erhalten, wenn Mastodon nicht geöffnet ist, aktiviere die Desktop-Benachrichtigungen. Du kannst genau bestimmen, welche Arten von Interaktionen Desktop-Benachrichtigungen über die {icon} -Taste erzeugen, sobald diese aktiviert sind.",
|
||||||
|
@ -852,6 +857,11 @@
|
||||||
"upload_error.poll": "Medien-Anhänge sind zusammen mit Umfragen nicht erlaubt.",
|
"upload_error.poll": "Medien-Anhänge sind zusammen mit Umfragen nicht erlaubt.",
|
||||||
"upload_form.audio_description": "Beschreibe für Menschen mit Hörbehinderung",
|
"upload_form.audio_description": "Beschreibe für Menschen mit Hörbehinderung",
|
||||||
"upload_form.description": "Beschreibe für Menschen mit Sehbehinderung",
|
"upload_form.description": "Beschreibe für Menschen mit Sehbehinderung",
|
||||||
|
"upload_form.drag_and_drop.instructions": "Drücke zum Aufnehmen eines Medienanhangs die Eingabe- oder Leertaste. Verwende beim Ziehen die Pfeiltasten, um den Medienanhang zur gewünschten Position zu bewegen. Drücke erneut die Eingabe- oder Leertaste, um den Medienanhang an der gewünschten Position abzulegen. Mit der Escape-Taste kannst du den Vorgang abbrechen.",
|
||||||
|
"upload_form.drag_and_drop.on_drag_cancel": "Das Ziehen wurde abgebrochen und der Medienanhang {item} wurde abgelegt.",
|
||||||
|
"upload_form.drag_and_drop.on_drag_end": "Der Medienanhang {item} wurde abgelegt.",
|
||||||
|
"upload_form.drag_and_drop.on_drag_over": "Der Medienanhang {item} wurde bewegt.",
|
||||||
|
"upload_form.drag_and_drop.on_drag_start": "Der Medienanhang {item} wurde aufgenommen.",
|
||||||
"upload_form.edit": "Bearbeiten",
|
"upload_form.edit": "Bearbeiten",
|
||||||
"upload_form.thumbnail": "Vorschaubild ändern",
|
"upload_form.thumbnail": "Vorschaubild ändern",
|
||||||
"upload_form.video_description": "Beschreibe für Menschen mit einer Hör- oder Sehbehinderung",
|
"upload_form.video_description": "Beschreibe für Menschen mit einer Hör- oder Sehbehinderung",
|
||||||
|
|
|
@ -85,6 +85,7 @@
|
||||||
"alert.rate_limited.title": "Περιορισμός συχνότητας",
|
"alert.rate_limited.title": "Περιορισμός συχνότητας",
|
||||||
"alert.unexpected.message": "Προέκυψε απροσδόκητο σφάλμα.",
|
"alert.unexpected.message": "Προέκυψε απροσδόκητο σφάλμα.",
|
||||||
"alert.unexpected.title": "Ουπς!",
|
"alert.unexpected.title": "Ουπς!",
|
||||||
|
"alt_text_badge.title": "Εναλλακτικό κείμενο",
|
||||||
"announcement.announcement": "Ανακοίνωση",
|
"announcement.announcement": "Ανακοίνωση",
|
||||||
"attachments_list.unprocessed": "(μη επεξεργασμένο)",
|
"attachments_list.unprocessed": "(μη επεξεργασμένο)",
|
||||||
"audio.hide": "Απόκρυψη αρχείου ήχου",
|
"audio.hide": "Απόκρυψη αρχείου ήχου",
|
||||||
|
@ -157,7 +158,6 @@
|
||||||
"compose_form.poll.duration": "Διάρκεια δημοσκόπησης",
|
"compose_form.poll.duration": "Διάρκεια δημοσκόπησης",
|
||||||
"compose_form.poll.multiple": "Πολλαπλή επιλογή",
|
"compose_form.poll.multiple": "Πολλαπλή επιλογή",
|
||||||
"compose_form.poll.option_placeholder": "Επιλογή {number}",
|
"compose_form.poll.option_placeholder": "Επιλογή {number}",
|
||||||
"compose_form.poll.single": "Διάλεξε ένα",
|
|
||||||
"compose_form.poll.switch_to_multiple": "Ενημέρωση δημοσκόπησης με πολλαπλές επιλογές",
|
"compose_form.poll.switch_to_multiple": "Ενημέρωση δημοσκόπησης με πολλαπλές επιλογές",
|
||||||
"compose_form.poll.switch_to_single": "Ενημέρωση δημοσκόπησης με μοναδική επιλογή",
|
"compose_form.poll.switch_to_single": "Ενημέρωση δημοσκόπησης με μοναδική επιλογή",
|
||||||
"compose_form.poll.type": "Στυλ",
|
"compose_form.poll.type": "Στυλ",
|
||||||
|
@ -221,6 +221,8 @@
|
||||||
"domain_block_modal.they_cant_follow": "Κανείς από αυτόν τον διακομιστή δεν μπορεί να σε ακολουθήσει.",
|
"domain_block_modal.they_cant_follow": "Κανείς από αυτόν τον διακομιστή δεν μπορεί να σε ακολουθήσει.",
|
||||||
"domain_block_modal.they_wont_know": "Δεν θα ξέρουν ότι έχουν αποκλειστεί.",
|
"domain_block_modal.they_wont_know": "Δεν θα ξέρουν ότι έχουν αποκλειστεί.",
|
||||||
"domain_block_modal.title": "Αποκλεισμός τομέα;",
|
"domain_block_modal.title": "Αποκλεισμός τομέα;",
|
||||||
|
"domain_block_modal.you_will_lose_num_followers": "Θα χάσετε {followersCount, plural, one {{followersCountDisplay} ακόλουθο} other {{followersCountDisplay} ακόλουθους}} και {followingCount, plural, one {{followingCountDisplay} άτομο που ακολουθείτε} other {{followingCountDisplay} άτομα που ακολουθείτε}}.",
|
||||||
|
"domain_block_modal.you_will_lose_relationships": "Θα χάσετε όλους τους ακόλουθους και τα άτομα που ακολουθείτε από αυτόν τον διακομιστή.",
|
||||||
"domain_block_modal.you_wont_see_posts": "Δεν θα βλέπεις αναρτήσεις ή ειδοποιήσεις από χρήστες σε αυτόν το διακομιστή.",
|
"domain_block_modal.you_wont_see_posts": "Δεν θα βλέπεις αναρτήσεις ή ειδοποιήσεις από χρήστες σε αυτόν το διακομιστή.",
|
||||||
"domain_pill.activitypub_lets_connect": "Σού επιτρέπει να συνδεθείς και να αλληλεπιδράσεις με τους ανθρώπους όχι μόνο στο Mastodon, αλλά και σε διαφορετικές κοινωνικές εφαρμογές.",
|
"domain_pill.activitypub_lets_connect": "Σού επιτρέπει να συνδεθείς και να αλληλεπιδράσεις με τους ανθρώπους όχι μόνο στο Mastodon, αλλά και σε διαφορετικές κοινωνικές εφαρμογές.",
|
||||||
"domain_pill.activitypub_like_language": "Το ActivityPub είναι σαν τη γλώσσα Mastodon μιλάει με άλλα κοινωνικά δίκτυα.",
|
"domain_pill.activitypub_like_language": "Το ActivityPub είναι σαν τη γλώσσα Mastodon μιλάει με άλλα κοινωνικά δίκτυα.",
|
||||||
|
@ -302,7 +304,6 @@
|
||||||
"filter_modal.select_filter.subtitle": "Χρησιμοποιήστε μια υπάρχουσα κατηγορία ή δημιουργήστε μια νέα",
|
"filter_modal.select_filter.subtitle": "Χρησιμοποιήστε μια υπάρχουσα κατηγορία ή δημιουργήστε μια νέα",
|
||||||
"filter_modal.select_filter.title": "Φιλτράρισμα αυτής της ανάρτησης",
|
"filter_modal.select_filter.title": "Φιλτράρισμα αυτής της ανάρτησης",
|
||||||
"filter_modal.title.status": "Φιλτράρισμα μιας ανάρτησης",
|
"filter_modal.title.status": "Φιλτράρισμα μιας ανάρτησης",
|
||||||
"filter_warning.matches_filter": "Ταιριάζει με το φίλτρο “{title}”",
|
|
||||||
"filtered_notifications_banner.pending_requests": "Από {count, plural, =0 {κανένα} one {ένα άτομο} other {# άτομα}} που μπορεί να ξέρεις",
|
"filtered_notifications_banner.pending_requests": "Από {count, plural, =0 {κανένα} one {ένα άτομο} other {# άτομα}} που μπορεί να ξέρεις",
|
||||||
"filtered_notifications_banner.title": "Φιλτραρισμένες ειδοποιήσεις",
|
"filtered_notifications_banner.title": "Φιλτραρισμένες ειδοποιήσεις",
|
||||||
"firehose.all": "Όλα",
|
"firehose.all": "Όλα",
|
||||||
|
@ -505,7 +506,6 @@
|
||||||
"notification.favourite": "{name} favorited your post\n{name} προτίμησε την ανάρτηση σου",
|
"notification.favourite": "{name} favorited your post\n{name} προτίμησε την ανάρτηση σου",
|
||||||
"notification.favourite.name_and_others_with_link": "{name} και <a>{count, plural, one {# ακόμη} other {# ακόμη}}</a> αγάπησαν την ανάρτησή σου",
|
"notification.favourite.name_and_others_with_link": "{name} και <a>{count, plural, one {# ακόμη} other {# ακόμη}}</a> αγάπησαν την ανάρτησή σου",
|
||||||
"notification.follow": "Ο/Η {name} σε ακολούθησε",
|
"notification.follow": "Ο/Η {name} σε ακολούθησε",
|
||||||
"notification.follow.name_and_others": "{name} και {count, plural, one {# ακόμη} other {# ακόμη}} σε ακολούθησαν",
|
|
||||||
"notification.follow_request": "Ο/H {name} ζήτησε να σε ακολουθήσει",
|
"notification.follow_request": "Ο/H {name} ζήτησε να σε ακολουθήσει",
|
||||||
"notification.follow_request.name_and_others": "{name} και {count, plural, one {# άλλος} other {# άλλοι}} ζήτησαν να σε ακολουθήσουν",
|
"notification.follow_request.name_and_others": "{name} και {count, plural, one {# άλλος} other {# άλλοι}} ζήτησαν να σε ακολουθήσουν",
|
||||||
"notification.label.mention": "Επισήμανση",
|
"notification.label.mention": "Επισήμανση",
|
||||||
|
@ -849,6 +849,11 @@
|
||||||
"upload_error.poll": "Στις δημοσκοπήσεις δεν επιτρέπεται η μεταφόρτωση αρχείου.",
|
"upload_error.poll": "Στις δημοσκοπήσεις δεν επιτρέπεται η μεταφόρτωση αρχείου.",
|
||||||
"upload_form.audio_description": "Περιγραφή για άτομα με προβλήματα ακοής",
|
"upload_form.audio_description": "Περιγραφή για άτομα με προβλήματα ακοής",
|
||||||
"upload_form.description": "Περιγραφή για άτομα με προβλήματα όρασης",
|
"upload_form.description": "Περιγραφή για άτομα με προβλήματα όρασης",
|
||||||
|
"upload_form.drag_and_drop.instructions": "Για να επιλέξετε ένα συνημμένο αρχείο πολυμέσων, πατήστε το Space ή το Enter. Ενώ το σέρνετε, χρησιμοποιήστε τα πλήκτρα βέλους για να μετακινήσετε το συνημμένο αρχείο πολυμέσων προς οποιαδήποτε κατεύθυνση. Πατήστε ξανά το Space ή το Enter για να αποθέσετε το συνημμένο αρχείο πολυμέσων στη νέα του θέση ή πατήστε το Escape για ακύρωση.",
|
||||||
|
"upload_form.drag_and_drop.on_drag_cancel": "Η μετακίνηση ακυρώθηκε. Έγινε απόθεση του συνημμένου αρχείου πολυμέσων «{item}».",
|
||||||
|
"upload_form.drag_and_drop.on_drag_end": "Έγινε απόθεση του συνημμένου αρχείου πολυμέσων «{item}».",
|
||||||
|
"upload_form.drag_and_drop.on_drag_over": "Έγινε μετακίνηση του συνημμένου αρχείου πολυμέσων «{item}».",
|
||||||
|
"upload_form.drag_and_drop.on_drag_start": "Έγινε επιλογή του συνημμένου αρχείου πολυμέσων «{item}».",
|
||||||
"upload_form.edit": "Επεξεργασία",
|
"upload_form.edit": "Επεξεργασία",
|
||||||
"upload_form.thumbnail": "Αλλαγή μικρογραφίας",
|
"upload_form.thumbnail": "Αλλαγή μικρογραφίας",
|
||||||
"upload_form.video_description": "Περιγραφή για άτομα με προβλήματα ακοής ή όρασης",
|
"upload_form.video_description": "Περιγραφή για άτομα με προβλήματα ακοής ή όρασης",
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue