mirror of
https://github.com/mastodon/mastodon.git
synced 2024-11-21 21:57:19 +00:00
Merge branch 'main' into search-warnings
This commit is contained in:
commit
5577bb5526
|
@ -45,6 +45,17 @@ ES_PASS=password
|
|||
SECRET_KEY_BASE=
|
||||
OTP_SECRET=
|
||||
|
||||
# Encryption secrets
|
||||
# ------------------
|
||||
# Must be available (and set to same values) for all server processes
|
||||
# These are private/secret values, do not share outside hosting environment
|
||||
# Use `bin/rails db:encryption:init` to generate fresh secrets
|
||||
# Do not change these secrets once in use, as this would cause data loss and other issues
|
||||
# ------------------
|
||||
# ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=
|
||||
# ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=
|
||||
# ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=
|
||||
|
||||
# Web Push
|
||||
# --------
|
||||
# Generate with `bundle exec rails mastodon:webpush:generate_vapid_key`
|
||||
|
|
|
@ -64,7 +64,6 @@ module.exports = defineConfig({
|
|||
'indent': ['error', 2],
|
||||
'jsx-quotes': ['error', 'prefer-single'],
|
||||
'semi': ['error', 'always'],
|
||||
'no-case-declarations': 'off',
|
||||
'no-catch-shadow': 'error',
|
||||
'no-console': [
|
||||
'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)
|
||||
description: If you are using Mastodon's web interface and something is not working as expected
|
||||
labels: [bug, 'status/to triage', 'area/web interface']
|
||||
description: There is a problem using Mastodon's web interface.
|
||||
labels: ['status/to triage', 'area/web interface']
|
||||
type: Bug
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
|
@ -47,8 +48,8 @@ body:
|
|||
attributes:
|
||||
label: Mastodon version
|
||||
description: |
|
||||
This is displayed at the bottom of the About page, eg. `v4.1.2+nightly-20230627`
|
||||
placeholder: v4.1.2
|
||||
This is displayed at the bottom of the About page, eg. `v4.4.0-alpha.1`
|
||||
placeholder: v4.3.0
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
|
@ -56,7 +57,7 @@ body:
|
|||
label: Browser name and version
|
||||
description: |
|
||||
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:
|
||||
required: true
|
||||
- type: input
|
||||
|
@ -64,7 +65,7 @@ body:
|
|||
label: Operating system
|
||||
description: |
|
||||
What OS are you running? Please specify the version as well.
|
||||
placeholder: macOS 13.4.1
|
||||
placeholder: macOS 15.0.1
|
||||
validations:
|
||||
required: true
|
||||
- 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)
|
||||
description: |
|
||||
If something is not working as expected, but is not from using the web interface.
|
||||
labels: [bug, 'status/to triage']
|
||||
There is a problem with the HTTP server, REST API, ActivityPub interaction, etc.
|
||||
labels: ['status/to triage']
|
||||
type: 'Bug'
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
|
@ -48,8 +49,8 @@ body:
|
|||
attributes:
|
||||
label: Mastodon version
|
||||
description: |
|
||||
This is displayed at the bottom of the About page, eg. `v4.1.2+nightly-20230627`
|
||||
placeholder: v4.1.2
|
||||
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
|
||||
|
@ -59,7 +60,7 @@ body:
|
|||
Any additional technical details you may have, like logs or error traces
|
||||
value: |
|
||||
If this is happening on your own Mastodon server, please fill out those:
|
||||
- Ruby version: (from `ruby --version`, eg. v3.1.2)
|
||||
- Node.js version: (from `node --version`, eg. v18.16.0)
|
||||
- Ruby version: (from `ruby --version`, eg. v3.3.5)
|
||||
- Node.js version: (from `node --version`, eg. v20.18.0)
|
||||
validations:
|
||||
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
|
||||
description: I have a suggestion
|
||||
labels: [suggestion]
|
||||
type: Suggestion
|
||||
body:
|
||||
- type: markdown
|
||||
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
|
||||
- id: version_vars
|
||||
run: |
|
||||
echo mastodon_version_metadata=pr-${{ github.event.pull_request.number }}-$(git rev-parse --short HEAD) >> $GITHUB_OUTPUT
|
||||
echo mastodon_version_metadata=pr-${{ github.event.pull_request.number }}-$(git rev-parse --short ${{github.event.pull_request.head.sha}}) >> $GITHUB_OUTPUT
|
||||
echo mastodon_short_sha=$(git rev-parse --short ${{github.event.pull_request.head.sha}}) >> $GITHUB_OUTPUT
|
||||
outputs:
|
||||
metadata: ${{ steps.version_vars.outputs.mastodon_version_metadata }}
|
||||
short_sha: ${{ steps.version_vars.outputs.mastodon_short_sha }}
|
||||
|
||||
build-image:
|
||||
needs: compute-suffix
|
||||
|
@ -39,6 +41,7 @@ jobs:
|
|||
latest=auto
|
||||
tags: |
|
||||
type=ref,event=pr
|
||||
type=ref,event=pr,suffix=-${{ needs.compute-suffix.outputs.short_sha }}
|
||||
secrets: inherit
|
||||
|
||||
build-image-streaming:
|
||||
|
@ -55,4 +58,5 @@ jobs:
|
|||
latest=auto
|
||||
tags: |
|
||||
type=ref,event=pr
|
||||
type=ref,event=pr,suffix=-${{ needs.compute-suffix.outputs.short_sha }}
|
||||
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
|
||||
# This needs to be updated after each minor version release
|
||||
flavor: |
|
||||
latest=${{ startsWith(github.ref, 'refs/tags/v4.2.') }}
|
||||
latest=${{ startsWith(github.ref, 'refs/tags/v4.3.') }}
|
||||
tags: |
|
||||
type=pep440,pattern={{raw}}
|
||||
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:
|
||||
check-i18n:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
steps:
|
||||
- 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
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v7.0.1
|
||||
uses: peter-evans/create-pull-request@v7.0.5
|
||||
with:
|
||||
commit-message: 'New Crowdin translations'
|
||||
title: 'New Crowdin Translations (automated)'
|
||||
|
|
3
.github/workflows/crowdin-upload.yml
vendored
3
.github/workflows/crowdin-upload.yml
vendored
|
@ -1,7 +1,6 @@
|
|||
name: Crowdin / Upload translations
|
||||
|
||||
on:
|
||||
merge_group:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
|
@ -31,7 +30,7 @@ jobs:
|
|||
upload_sources: true
|
||||
upload_translations: false
|
||||
download_translations: false
|
||||
crowdin_branch_name: main
|
||||
crowdin_branch_name: ${{ github.base_ref || github.ref_name }}
|
||||
|
||||
env:
|
||||
CROWDIN_PROJECT_ID: ${{ vars.CROWDIN_PROJECT_ID }}
|
||||
|
|
2
.github/workflows/test-migrations.yml
vendored
2
.github/workflows/test-migrations.yml
vendored
|
@ -32,6 +32,8 @@ jobs:
|
|||
postgres:
|
||||
- 14-alpine
|
||||
- 15-alpine
|
||||
- 16-alpine
|
||||
- 17-alpine
|
||||
|
||||
services:
|
||||
postgres:
|
||||
|
|
12
.github/workflows/test-ruby.yml
vendored
12
.github/workflows/test-ruby.yml
vendored
|
@ -124,7 +124,6 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
ruby-version:
|
||||
- '3.1'
|
||||
- '3.2'
|
||||
- '.ruby-version'
|
||||
steps:
|
||||
|
@ -143,7 +142,7 @@ jobs:
|
|||
uses: ./.github/actions/setup-ruby
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby-version}}
|
||||
additional-system-dependencies: ffmpeg libpam-dev
|
||||
additional-system-dependencies: ffmpeg imagemagick libpam-dev
|
||||
|
||||
- name: Load database schema
|
||||
run: |
|
||||
|
@ -226,7 +225,6 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
ruby-version:
|
||||
- '3.1'
|
||||
- '3.2'
|
||||
- '.ruby-version'
|
||||
steps:
|
||||
|
@ -245,7 +243,7 @@ jobs:
|
|||
uses: ./.github/actions/setup-ruby
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby-version}}
|
||||
additional-system-dependencies: ffmpeg libpam-dev libyaml-dev
|
||||
additional-system-dependencies: ffmpeg libpam-dev
|
||||
|
||||
- name: Load database schema
|
||||
run: './bin/rails db:create db:schema:load db:seed'
|
||||
|
@ -305,7 +303,6 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
ruby-version:
|
||||
- '3.1'
|
||||
- '3.2'
|
||||
- '.ruby-version'
|
||||
|
||||
|
@ -325,7 +322,7 @@ jobs:
|
|||
uses: ./.github/actions/setup-ruby
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby-version}}
|
||||
additional-system-dependencies: ffmpeg
|
||||
additional-system-dependencies: ffmpeg imagemagick
|
||||
|
||||
- name: Set up Javascript environment
|
||||
uses: ./.github/actions/setup-javascript
|
||||
|
@ -422,7 +419,6 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
ruby-version:
|
||||
- '3.1'
|
||||
- '3.2'
|
||||
- '.ruby-version'
|
||||
search-image:
|
||||
|
@ -445,7 +441,7 @@ jobs:
|
|||
uses: ./.github/actions/setup-ruby
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby-version}}
|
||||
additional-system-dependencies: ffmpeg
|
||||
additional-system-dependencies: ffmpeg imagemagick
|
||||
|
||||
- name: Set up Javascript environment
|
||||
uses: ./.github/actions/setup-javascript
|
||||
|
|
|
@ -8,7 +8,7 @@ AllCops:
|
|||
- lib/mastodon/migration_helpers.rb
|
||||
ExtraDetails: true
|
||||
NewCops: enable
|
||||
TargetRubyVersion: 3.1 # Oldest supported ruby version
|
||||
TargetRubyVersion: 3.2 # Oldest supported ruby version
|
||||
|
||||
inherit_from:
|
||||
- .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.
|
||||
|
||||
## [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.
|
||||
|
||||
|
@ -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)\
|
||||
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
|
||||
|
||||
### 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.\
|
||||
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.\
|
||||
|
@ -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
|
||||
- `POST /api/v2/notifications/:group_key/dimsiss`: https://docs.joinmastodon.org/methods/grouped_notifications/#dismiss-group
|
||||
- `GET /api/v2/notifications/:unread_count`: https://docs.joinmastodon.org/methods/grouped_notifications/#unread-group-count
|
||||
- **Add notification policies, filtered notifications and notification requests** (#29366, #29529, #29433, #29565, #29567, #29572, #29575, #29588, #29646, #29652, #29658, #29666, #29693, #29699, #29737, #29706, #29570, #29752, #29810, #29826, #30114, #30251, #30559, #29868, #31008, #31011, #30996, #31149, #31220, #31222, #31225, #31242, #31262, #31250, #31273, #31310, #31316, #31322, #31329, #31324, #31331, #31343, #31342, #31309, #31358, #31378, #31406, #31256, #31456, #31419, #31457, #31508, #31540, #31541, 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.\
|
||||
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.\
|
||||
|
@ -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)\
|
||||
You can now see public posts mentioning currently-trending articles from people who have opted into discovery features.\
|
||||
This adds a new REST API endpoint: https://docs.joinmastodon.org/methods/timelines/#link
|
||||
- **Add author highlight for news articles whose authors are on the fediverse** (#30398, #30670, #30521, #30846, #31819, and #31900 by @Gargron and @oneiros)\
|
||||
- **Add author highlight for news articles whose authors are on the fediverse** (#30398, #30670, #30521, #30846, #31819, #31900 and #32188 by @Gargron, @mjankowski and @oneiros)\
|
||||
This adds a mechanism to [highlight the author of news articles](https://blog.joinmastodon.org/2024/07/highlighting-journalism-on-mastodon/) shared on Mastodon.\
|
||||
Articles hosted outside the fediverse can indicate a fediverse author with a meta tag:
|
||||
```html
|
||||
<meta name="fediverse:creator" content="username@domain" />
|
||||
```
|
||||
On the API side, this is represented by a new `authors` attribute to the `PreviewCard` entity: https://docs.joinmastodon.org/entities/PreviewCard/#authors\
|
||||
On the API side, this is represented by a new `authors` attribute to the `PreviewCard` entity: https://docs.joinmastodon.org/entities/PreviewCard/#authors \
|
||||
Users can allow arbitrary domains to use `fediverse:creator` to credit them by visiting `/settings/verification`.\
|
||||
This is federated as a new `attributionDomains` property in the `http://joinmastodon.org/ns` namespace, containing an array of domain names: https://docs.joinmastodon.org/spec/activitypub/#properties-used-1
|
||||
- **Add in-app notifications for moderation actions and warnings** (#30065, #30082, and #30081 by @ClearlyClaire)\
|
||||
|
@ -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.
|
||||
- **Add support for Redis sentinel** (#31694, #31623, #31744, #31767, and #31768 by @ThisIsMissEm and @oneiros)\
|
||||
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 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
|
||||
|
@ -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 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 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.\
|
||||
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.
|
||||
- Add validations to `Web::PushSubscription` (#30540 and #30542 by @ThisIsMissEm)
|
||||
- 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 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
|
||||
- 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
|
||||
|
@ -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 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 global Regexp timeout (#31928 by @ClearlyClaire)
|
||||
- Add the role ID to the badge component (#29707 by @renchap)
|
||||
- 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)
|
||||
|
@ -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)\
|
||||
This lays the groundwork for a “year-in-review”/“wrapped” style report for local users, but is currently not in use.
|
||||
- Add notification email on invalid second authenticator (#28822 by @ClearlyClaire)
|
||||
- Add date of account deletion in list of accounts in the admin interface (#25640 by @tribela)
|
||||
- Add new emojis from `jdecked/twemoji` 15.0 (#28404 by @TheEssem)
|
||||
- Add configurable error handling in attachment batch deletion (#28184 by @vmstan)\
|
||||
This makes the S3 batch size configurable through the `S3_BATCH_DELETE_LIMIT` environment variable (defaults to 1000), and adds some retry logic, configurable through the `S3_BATCH_DELETE_RETRY` environment variable (defaults to 3).
|
||||
- Add VAPID public key to instance serializer (#28006 by @ThisIsMissEm)
|
||||
- Add support for serving JRD `/.well-known/host-meta.json` in addition to XRD host-meta (#32206 by @c960657)
|
||||
- Add `nodeName` and `nodeDescription` to nodeinfo `metadata` (#28079 by @6543)
|
||||
- Add Thai diacritics and tone marks in `HASHTAG_INVALID_CHARS_RE` (#26576 by @ppnplus)
|
||||
- Add variable delay before link verification of remote account links (#27774 by @ClearlyClaire)
|
||||
|
@ -164,18 +170,18 @@ The following changelog entries focus on changes visible to users, administrator
|
|||
|
||||
### Changed
|
||||
|
||||
- **Change icons throughout the web interface** (#27385, #27539, #27555, #27579, #27700, #27817, #28519, #28709, #28064, #28775, #28780, #27924, #29294, #29395, #29537, #29569, #29610, #29612, #29649, #29844, #27780, #30974, #30963, #30962, #30961, #31362, #31363, #31359, #31371, #31360, #31512, #31511, and #31525 by @ClearlyClaire, @Gargron, @arbolitoloco1, @mjankowski, @nclm, @renchap, @ronilaukkarinen, and @zunda)\
|
||||
- **Change icons throughout the web interface** (#27385, #27539, #27555, #27579, #27700, #27817, #28519, #28709, #28064, #28775, #28780, #27924, #29294, #29395, #29537, #29569, #29610, #29612, #29649, #29844, #27780, #30974, #30963, #30962, #30961, #31362, #31363, #31359, #31371, #31360, #31512, #31511, #31525, #32153, and #32201 by @ClearlyClaire, @Gargron, @arbolitoloco1, @mjankowski, @nclm, @renchap, @ronilaukkarinen, and @zunda)\
|
||||
This changes all the interface icons from FontAwesome to Material Symbols for a more modern look, consistent with the official Mastodon Android app.\
|
||||
In addition, better care is given to pixel alignment, and icon variants are used to better highlight active/inactive state.
|
||||
- **Change design of compose form in web UI** (#28119, #29059, #29248, #29372, #29384, #29417, #29456, #29406, #29651, #29659, 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.\
|
||||
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)\
|
||||
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.
|
||||
- **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 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.
|
||||
- **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.\
|
||||
|
@ -188,10 +194,17 @@ The following changelog entries focus on changes visible to users, administrator
|
|||
Administrators may need to update their setup accordingly.
|
||||
- Change how content warnings and filters are displayed in web UI (#31365, and #31761 by @Gargron)
|
||||
- Change preview card processing to ignore `undefined` as canonical url (#31882 by @oneiros)
|
||||
- Change embedded posts to use web UI (#31766 by @Gargron)
|
||||
- Change embedded posts to use web UI (#31766, #32135 and #32271 by @Gargron)
|
||||
- Change inner borders in media galleries in web UI (#31852 by @Gargron)
|
||||
- Change design of 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 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 width of columns in advanced web UI (#31762 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
|
||||
|
||||
- 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 `CacheBuster` default options (#30718 by @mjankowski)
|
||||
- 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 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 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 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 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 invalid date searches returning 503 errors (#31526 by @notchairmk)
|
||||
- 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 right-to-left text in preview cards (#30930 by @ClearlyClaire)
|
||||
- Fix rack attack `match_type` value typo in logging config (#30514 by @mjankowski)
|
||||
- Fix various cases of duplicate, missing, or inconsistent borders or scrollbar styles (#31068, #31286, #31268, #31275, #31284, #31305, #31346, #31372, #31373, #31389, #31432, #31391, 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 post deletion not being delayed when those are part of an account warning (#30163 by @ClearlyClaire)
|
||||
- Fix rendering error on `/start` when not logged in (#30023 by @timothyjrogers)
|
||||
- Fix unneeded requests to blocked domains when receiving relayed signed activities from them (#31161 by @ClearlyClaire)
|
||||
- Fix logo pushing header buttons out of view on certain conditions in mobile layout (#29787 by @ClearlyClaire)
|
||||
- Fix notification-related records not being reattributed when merging accounts (#29694 by @ClearlyClaire)
|
||||
- Fix results/query in `api/v1/featured_tags/suggestions` (#29597 by @mjankowski)
|
||||
|
@ -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 filters title and keywords overflow (#29396 by @GeopJr)
|
||||
- Fix incorrect date format in “Follows and followers” (#29390 by @JasonPunyon)
|
||||
- Fix navigation item active highlight for some paths (#32159 by @mjankowski)
|
||||
- Fix “Edit media” modal sizing and layout when space-constrained (#27095 by @ronilaukkarinen)
|
||||
- Fix modal container bounds (#29185 by @nico3333fr)
|
||||
- Fix inefficient HTTP signature parsing using regexps and `StringScanner` (#29133 by @ClearlyClaire)
|
||||
|
|
|
@ -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
|
||||
# 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"
|
||||
# # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"]
|
||||
# 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"]
|
||||
ARG DEBIAN_VERSION="bookworm"
|
||||
# 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"]
|
||||
# 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"]
|
||||
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"]
|
||||
# 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"]
|
||||
ARG FFMPEG_URL=https://ffmpeg.org/releases
|
||||
|
||||
|
|
12
Gemfile
12
Gemfile
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
source 'https://rubygems.org'
|
||||
ruby '>= 3.1.0'
|
||||
ruby '>= 3.2.0'
|
||||
|
||||
gem 'propshaft'
|
||||
gem 'puma', '~> 6.3'
|
||||
|
@ -16,10 +16,10 @@ gem 'pghero'
|
|||
|
||||
gem 'aws-sdk-s3', '~> 1.123', require: false
|
||||
gem 'blurhash', '~> 0.1'
|
||||
gem 'fog-core', '<= 2.5.0'
|
||||
gem 'fog-core', '<= 2.6.0'
|
||||
gem 'fog-openstack', '~> 1.0', require: false
|
||||
gem 'jd-paperclip-azure', '~> 3.0', require: false
|
||||
gem 'kt-paperclip', '~> 7.2'
|
||||
gem 'md-paperclip-azure', '~> 2.2', require: false
|
||||
gem 'ruby-vips', '~> 2.2', require: false
|
||||
|
||||
gem 'active_model_serializers', '~> 0.10'
|
||||
|
@ -61,7 +61,7 @@ gem 'irb', '~> 1.8'
|
|||
gem 'kaminari', '~> 1.2'
|
||||
gem 'link_header', '~> 0.0'
|
||||
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 'oj', '~> 3.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-net_http', '~> 0.22.4', require: false
|
||||
gem 'opentelemetry-instrumentation-pg', '~> 0.29.0', require: false
|
||||
gem 'opentelemetry-instrumentation-rack', '~> 0.24.1', require: false
|
||||
gem 'opentelemetry-instrumentation-rails', '~> 0.31.0', require: false
|
||||
gem 'opentelemetry-instrumentation-rack', '~> 0.25.0', require: false
|
||||
gem 'opentelemetry-instrumentation-rails', '~> 0.32.0', require: false
|
||||
gem 'opentelemetry-instrumentation-redis', '~> 0.25.3', require: false
|
||||
gem 'opentelemetry-instrumentation-sidekiq', '~> 0.25.2', require: false
|
||||
gem 'opentelemetry-sdk', '~> 1.4', require: false
|
||||
|
|
243
Gemfile.lock
243
Gemfile.lock
|
@ -10,35 +10,35 @@ GIT
|
|||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
actioncable (7.1.4)
|
||||
actionpack (= 7.1.4)
|
||||
activesupport (= 7.1.4)
|
||||
actioncable (7.1.4.2)
|
||||
actionpack (= 7.1.4.2)
|
||||
activesupport (= 7.1.4.2)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (>= 0.6.1)
|
||||
zeitwerk (~> 2.6)
|
||||
actionmailbox (7.1.4)
|
||||
actionpack (= 7.1.4)
|
||||
activejob (= 7.1.4)
|
||||
activerecord (= 7.1.4)
|
||||
activestorage (= 7.1.4)
|
||||
activesupport (= 7.1.4)
|
||||
actionmailbox (7.1.4.2)
|
||||
actionpack (= 7.1.4.2)
|
||||
activejob (= 7.1.4.2)
|
||||
activerecord (= 7.1.4.2)
|
||||
activestorage (= 7.1.4.2)
|
||||
activesupport (= 7.1.4.2)
|
||||
mail (>= 2.7.1)
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
actionmailer (7.1.4)
|
||||
actionpack (= 7.1.4)
|
||||
actionview (= 7.1.4)
|
||||
activejob (= 7.1.4)
|
||||
activesupport (= 7.1.4)
|
||||
actionmailer (7.1.4.2)
|
||||
actionpack (= 7.1.4.2)
|
||||
actionview (= 7.1.4.2)
|
||||
activejob (= 7.1.4.2)
|
||||
activesupport (= 7.1.4.2)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
rails-dom-testing (~> 2.2)
|
||||
actionpack (7.1.4)
|
||||
actionview (= 7.1.4)
|
||||
activesupport (= 7.1.4)
|
||||
actionpack (7.1.4.2)
|
||||
actionview (= 7.1.4.2)
|
||||
activesupport (= 7.1.4.2)
|
||||
nokogiri (>= 1.8.5)
|
||||
racc
|
||||
rack (>= 2.2.4)
|
||||
|
@ -46,15 +46,15 @@ GEM
|
|||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.2)
|
||||
rails-html-sanitizer (~> 1.6)
|
||||
actiontext (7.1.4)
|
||||
actionpack (= 7.1.4)
|
||||
activerecord (= 7.1.4)
|
||||
activestorage (= 7.1.4)
|
||||
activesupport (= 7.1.4)
|
||||
actiontext (7.1.4.2)
|
||||
actionpack (= 7.1.4.2)
|
||||
activerecord (= 7.1.4.2)
|
||||
activestorage (= 7.1.4.2)
|
||||
activesupport (= 7.1.4.2)
|
||||
globalid (>= 0.6.0)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (7.1.4)
|
||||
activesupport (= 7.1.4)
|
||||
actionview (7.1.4.2)
|
||||
activesupport (= 7.1.4.2)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.11)
|
||||
rails-dom-testing (~> 2.2)
|
||||
|
@ -64,22 +64,22 @@ GEM
|
|||
activemodel (>= 4.1)
|
||||
case_transform (>= 0.2)
|
||||
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
|
||||
activejob (7.1.4)
|
||||
activesupport (= 7.1.4)
|
||||
activejob (7.1.4.2)
|
||||
activesupport (= 7.1.4.2)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (7.1.4)
|
||||
activesupport (= 7.1.4)
|
||||
activerecord (7.1.4)
|
||||
activemodel (= 7.1.4)
|
||||
activesupport (= 7.1.4)
|
||||
activemodel (7.1.4.2)
|
||||
activesupport (= 7.1.4.2)
|
||||
activerecord (7.1.4.2)
|
||||
activemodel (= 7.1.4.2)
|
||||
activesupport (= 7.1.4.2)
|
||||
timeout (>= 0.4.0)
|
||||
activestorage (7.1.4)
|
||||
actionpack (= 7.1.4)
|
||||
activejob (= 7.1.4)
|
||||
activerecord (= 7.1.4)
|
||||
activesupport (= 7.1.4)
|
||||
activestorage (7.1.4.2)
|
||||
actionpack (= 7.1.4.2)
|
||||
activejob (= 7.1.4.2)
|
||||
activerecord (= 7.1.4.2)
|
||||
activesupport (= 7.1.4.2)
|
||||
marcel (~> 1.0)
|
||||
activesupport (7.1.4)
|
||||
activesupport (7.1.4.2)
|
||||
base64
|
||||
bigdecimal
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
|
@ -100,29 +100,23 @@ GEM
|
|||
attr_required (1.0.2)
|
||||
awrence (1.2.1)
|
||||
aws-eventstream (1.3.0)
|
||||
aws-partitions (1.978.0)
|
||||
aws-sdk-core (3.209.0)
|
||||
aws-partitions (1.997.0)
|
||||
aws-sdk-core (3.211.0)
|
||||
aws-eventstream (~> 1, >= 1.3.0)
|
||||
aws-partitions (~> 1, >= 1.651.0)
|
||||
aws-partitions (~> 1, >= 1.992.0)
|
||||
aws-sigv4 (~> 1.9)
|
||||
jmespath (~> 1, >= 1.6.1)
|
||||
aws-sdk-kms (1.94.0)
|
||||
aws-sdk-core (~> 3, >= 3.207.0)
|
||||
aws-sdk-kms (1.95.0)
|
||||
aws-sdk-core (~> 3, >= 3.210.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sdk-s3 (1.166.0)
|
||||
aws-sdk-core (~> 3, >= 3.207.0)
|
||||
aws-sdk-s3 (1.169.0)
|
||||
aws-sdk-core (~> 3, >= 3.210.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sigv4 (1.10.0)
|
||||
aws-sigv4 (1.10.1)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
azure-storage-blob (2.0.3)
|
||||
azure-storage-common (~> 2.0)
|
||||
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)
|
||||
azure-blob (0.5.2)
|
||||
rexml
|
||||
base64 (0.2.0)
|
||||
bcp47_spec (0.2.1)
|
||||
bcrypt (3.1.20)
|
||||
|
@ -137,7 +131,7 @@ GEM
|
|||
blurhash (0.1.8)
|
||||
bootsnap (1.18.4)
|
||||
msgpack (~> 1.2)
|
||||
brakeman (6.2.1)
|
||||
brakeman (6.2.2)
|
||||
racc
|
||||
browser (5.3.1)
|
||||
brpoplpush-redis_script (0.1.3)
|
||||
|
@ -179,7 +173,7 @@ GEM
|
|||
bigdecimal
|
||||
rexml
|
||||
crass (1.0.6)
|
||||
css_parser (1.19.0)
|
||||
css_parser (1.19.1)
|
||||
addressable
|
||||
csv (3.3.0)
|
||||
database_cleaner-active_record (2.2.0)
|
||||
|
@ -231,9 +225,9 @@ GEM
|
|||
erubi (1.13.0)
|
||||
et-orbi (1.2.11)
|
||||
tzinfo
|
||||
excon (0.111.0)
|
||||
excon (0.112.0)
|
||||
fabrication (2.31.0)
|
||||
faker (3.4.2)
|
||||
faker (3.5.1)
|
||||
i18n (>= 1.8.11, < 2)
|
||||
faraday (1.10.3)
|
||||
faraday-em_http (~> 1.0)
|
||||
|
@ -258,11 +252,9 @@ GEM
|
|||
faraday-patron (1.0.0)
|
||||
faraday-rack (1.0.0)
|
||||
faraday-retry (1.0.3)
|
||||
faraday_middleware (1.2.0)
|
||||
faraday (~> 1.0)
|
||||
fast_blank (1.0.1)
|
||||
fastimage (2.3.1)
|
||||
ffi (1.16.3)
|
||||
ffi (1.17.0)
|
||||
ffi-compiler (1.3.2)
|
||||
ffi (>= 1.15.5)
|
||||
rake
|
||||
|
@ -301,7 +293,7 @@ GEM
|
|||
activesupport (>= 5.1)
|
||||
haml (>= 4.0.6)
|
||||
railties (>= 5.1)
|
||||
haml_lint (0.58.0)
|
||||
haml_lint (0.59.0)
|
||||
haml (>= 5.0)
|
||||
parallel (~> 1.10)
|
||||
rainbow
|
||||
|
@ -347,11 +339,15 @@ GEM
|
|||
activesupport (>= 3.0)
|
||||
nokogiri (>= 1.6)
|
||||
io-console (0.7.2)
|
||||
irb (1.14.0)
|
||||
irb (1.14.1)
|
||||
rdoc (>= 4.0.0)
|
||||
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)
|
||||
json (2.7.2)
|
||||
json (2.7.4)
|
||||
json-canonicalization (1.0.0)
|
||||
json-jwt (1.15.3.1)
|
||||
activesupport (>= 4.2)
|
||||
|
@ -369,7 +365,7 @@ GEM
|
|||
json-ld-preloaded (3.3.0)
|
||||
json-ld (~> 3.3)
|
||||
rdf (~> 3.3)
|
||||
json-schema (5.0.0)
|
||||
json-schema (5.0.1)
|
||||
addressable (~> 2.8)
|
||||
jsonapi-renderer (0.2.2)
|
||||
jwt (2.7.1)
|
||||
|
@ -412,7 +408,7 @@ GEM
|
|||
activesupport (>= 4)
|
||||
railties (>= 4)
|
||||
request_store (~> 1.0)
|
||||
loofah (2.22.0)
|
||||
loofah (2.23.1)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.12.0)
|
||||
mail (2.8.1)
|
||||
|
@ -424,26 +420,21 @@ GEM
|
|||
mario-redis-lock (1.2.1)
|
||||
redis (>= 3.0.5)
|
||||
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)
|
||||
mime-types (3.5.2)
|
||||
mime-types (3.6.0)
|
||||
logger
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2024.0820)
|
||||
mime-types-data (3.2024.1001)
|
||||
mini_mime (1.1.5)
|
||||
mini_portile2 (2.8.7)
|
||||
minitest (5.25.1)
|
||||
msgpack (1.7.2)
|
||||
msgpack (1.7.3)
|
||||
multi_json (1.15.0)
|
||||
multipart-post (2.4.1)
|
||||
mutex_m (0.2.0)
|
||||
net-http (0.4.1)
|
||||
uri
|
||||
net-http-persistent (4.0.2)
|
||||
connection_pool (~> 2.2)
|
||||
net-imap (0.4.15)
|
||||
net-imap (0.5.0)
|
||||
date
|
||||
net-protocol
|
||||
net-ldap (0.19.0)
|
||||
|
@ -503,7 +494,7 @@ GEM
|
|||
opentelemetry-semantic_conventions
|
||||
opentelemetry-helpers-sql-obfuscation (0.2.0)
|
||||
opentelemetry-common (~> 0.21)
|
||||
opentelemetry-instrumentation-action_mailer (0.1.0)
|
||||
opentelemetry-instrumentation-action_mailer (0.2.0)
|
||||
opentelemetry-api (~> 1.0)
|
||||
opentelemetry-instrumentation-active_support (~> 0.1)
|
||||
opentelemetry-instrumentation-base (~> 0.22.1)
|
||||
|
@ -515,13 +506,13 @@ GEM
|
|||
opentelemetry-api (~> 1.0)
|
||||
opentelemetry-instrumentation-active_support (~> 0.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-instrumentation-base (~> 0.22.1)
|
||||
opentelemetry-instrumentation-active_model_serializers (0.20.2)
|
||||
opentelemetry-api (~> 1.0)
|
||||
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-instrumentation-base (~> 0.22.1)
|
||||
opentelemetry-instrumentation-active_support (0.6.0)
|
||||
|
@ -553,16 +544,16 @@ GEM
|
|||
opentelemetry-api (~> 1.0)
|
||||
opentelemetry-helpers-sql-obfuscation
|
||||
opentelemetry-instrumentation-base (~> 0.22.1)
|
||||
opentelemetry-instrumentation-rack (0.24.6)
|
||||
opentelemetry-instrumentation-rack (0.25.0)
|
||||
opentelemetry-api (~> 1.0)
|
||||
opentelemetry-instrumentation-base (~> 0.22.1)
|
||||
opentelemetry-instrumentation-rails (0.31.2)
|
||||
opentelemetry-instrumentation-rails (0.32.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_view (~> 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-base (~> 0.22.1)
|
||||
opentelemetry-instrumentation-redis (0.25.7)
|
||||
|
@ -590,8 +581,8 @@ GEM
|
|||
parslet (2.0.0)
|
||||
pastel (0.8.0)
|
||||
tty-color (~> 0.5)
|
||||
pg (1.5.8)
|
||||
pghero (3.6.0)
|
||||
pg (1.5.9)
|
||||
pghero (3.6.1)
|
||||
activerecord (>= 6.1)
|
||||
premailer (1.27.0)
|
||||
addressable
|
||||
|
@ -601,7 +592,7 @@ GEM
|
|||
actionmailer (>= 3)
|
||||
net-smtp
|
||||
premailer (~> 1.7, >= 1.7.9)
|
||||
propshaft (1.0.0)
|
||||
propshaft (1.1.0)
|
||||
actionpack (>= 7.0.0)
|
||||
activesupport (>= 7.0.0)
|
||||
rack
|
||||
|
@ -615,7 +606,7 @@ GEM
|
|||
activesupport (>= 3.0.0)
|
||||
raabro (1.4.0)
|
||||
racc (1.8.1)
|
||||
rack (2.2.9)
|
||||
rack (2.2.10)
|
||||
rack-attack (6.7.0)
|
||||
rack (>= 1.0, < 4)
|
||||
rack-cors (2.0.2)
|
||||
|
@ -638,20 +629,20 @@ GEM
|
|||
rackup (1.0.0)
|
||||
rack (< 3)
|
||||
webrick
|
||||
rails (7.1.4)
|
||||
actioncable (= 7.1.4)
|
||||
actionmailbox (= 7.1.4)
|
||||
actionmailer (= 7.1.4)
|
||||
actionpack (= 7.1.4)
|
||||
actiontext (= 7.1.4)
|
||||
actionview (= 7.1.4)
|
||||
activejob (= 7.1.4)
|
||||
activemodel (= 7.1.4)
|
||||
activerecord (= 7.1.4)
|
||||
activestorage (= 7.1.4)
|
||||
activesupport (= 7.1.4)
|
||||
rails (7.1.4.2)
|
||||
actioncable (= 7.1.4.2)
|
||||
actionmailbox (= 7.1.4.2)
|
||||
actionmailer (= 7.1.4.2)
|
||||
actionpack (= 7.1.4.2)
|
||||
actiontext (= 7.1.4.2)
|
||||
actionview (= 7.1.4.2)
|
||||
activejob (= 7.1.4.2)
|
||||
activemodel (= 7.1.4.2)
|
||||
activerecord (= 7.1.4.2)
|
||||
activestorage (= 7.1.4.2)
|
||||
activesupport (= 7.1.4.2)
|
||||
bundler (>= 1.15.0)
|
||||
railties (= 7.1.4)
|
||||
railties (= 7.1.4.2)
|
||||
rails-controller-testing (1.0.5)
|
||||
actionpack (>= 5.0.1.rc1)
|
||||
actionview (>= 5.0.1.rc1)
|
||||
|
@ -663,12 +654,12 @@ GEM
|
|||
rails-html-sanitizer (1.6.0)
|
||||
loofah (~> 2.21)
|
||||
nokogiri (~> 1.14)
|
||||
rails-i18n (7.0.9)
|
||||
rails-i18n (7.0.10)
|
||||
i18n (>= 0.7, < 2)
|
||||
railties (>= 6.0.0, < 8)
|
||||
railties (7.1.4)
|
||||
actionpack (= 7.1.4)
|
||||
activesupport (= 7.1.4)
|
||||
railties (7.1.4.2)
|
||||
actionpack (= 7.1.4.2)
|
||||
activesupport (= 7.1.4.2)
|
||||
irb
|
||||
rackup (>= 1.0.0)
|
||||
rake (>= 12.2)
|
||||
|
@ -698,9 +689,9 @@ GEM
|
|||
responders (3.1.1)
|
||||
actionpack (>= 5.2)
|
||||
railties (>= 5.2)
|
||||
rexml (3.3.7)
|
||||
rexml (3.3.9)
|
||||
rotp (6.3.0)
|
||||
rouge (4.3.0)
|
||||
rouge (4.4.0)
|
||||
rpam2 (4.0.2)
|
||||
rqrcode (2.2.0)
|
||||
chunky_png (~> 1.0)
|
||||
|
@ -710,14 +701,14 @@ GEM
|
|||
rspec-core (~> 3.13.0)
|
||||
rspec-expectations (~> 3.13.0)
|
||||
rspec-mocks (~> 3.13.0)
|
||||
rspec-core (3.13.1)
|
||||
rspec-core (3.13.2)
|
||||
rspec-support (~> 3.13.0)
|
||||
rspec-expectations (3.13.2)
|
||||
rspec-expectations (3.13.3)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.13.0)
|
||||
rspec-github (2.4.0)
|
||||
rspec-core (~> 3.0)
|
||||
rspec-mocks (3.13.1)
|
||||
rspec-mocks (3.13.2)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.13.0)
|
||||
rspec-rails (7.0.1)
|
||||
|
@ -748,20 +739,20 @@ GEM
|
|||
parser (>= 3.3.1.0)
|
||||
rubocop-capybara (2.21.0)
|
||||
rubocop (~> 1.41)
|
||||
rubocop-performance (1.21.1)
|
||||
rubocop-performance (1.22.1)
|
||||
rubocop (>= 1.48.1, < 2.0)
|
||||
rubocop-ast (>= 1.31.1, < 2.0)
|
||||
rubocop-rails (2.25.1)
|
||||
rubocop-rails (2.27.0)
|
||||
activesupport (>= 4.2.0)
|
||||
rack (>= 1.1)
|
||||
rubocop (>= 1.33.0, < 2.0)
|
||||
rubocop (>= 1.52.0, < 2.0)
|
||||
rubocop-ast (>= 1.31.1, < 2.0)
|
||||
rubocop-rspec (3.0.4)
|
||||
rubocop-rspec (3.2.0)
|
||||
rubocop (~> 1.61)
|
||||
rubocop-rspec_rails (2.30.0)
|
||||
rubocop (~> 1.61)
|
||||
rubocop-rspec (~> 3, >= 3.0.1)
|
||||
ruby-prof (1.7.0)
|
||||
ruby-prof (1.7.1)
|
||||
ruby-progressbar (1.13.0)
|
||||
ruby-saml (1.17.0)
|
||||
nokogiri (>= 1.13.10)
|
||||
|
@ -781,7 +772,7 @@ GEM
|
|||
scenic (1.8.0)
|
||||
activerecord (>= 4.0.0)
|
||||
railties (>= 4.0.0)
|
||||
selenium-webdriver (4.25.0)
|
||||
selenium-webdriver (4.26.0)
|
||||
base64 (~> 0.2)
|
||||
logger (~> 1.4)
|
||||
rexml (~> 3.2, >= 3.2.5)
|
||||
|
@ -815,14 +806,14 @@ GEM
|
|||
docile (~> 1.1)
|
||||
simplecov-html (~> 0.11)
|
||||
simplecov_json_formatter (~> 0.1)
|
||||
simplecov-html (0.12.3)
|
||||
simplecov-html (0.13.1)
|
||||
simplecov-lcov (0.8.0)
|
||||
simplecov_json_formatter (0.1.4)
|
||||
stackprof (0.2.26)
|
||||
stoplight (4.1.0)
|
||||
redlock (~> 1.0)
|
||||
stringio (3.1.1)
|
||||
strong_migrations (2.0.0)
|
||||
strong_migrations (2.0.2)
|
||||
activerecord (>= 6.1)
|
||||
swd (1.3.0)
|
||||
activesupport (>= 3)
|
||||
|
@ -862,7 +853,7 @@ GEM
|
|||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.9.1)
|
||||
unicode-display_width (2.5.0)
|
||||
unicode-display_width (2.6.0)
|
||||
uri (0.13.1)
|
||||
validate_email (0.1.6)
|
||||
activemodel (>= 3.0)
|
||||
|
@ -884,7 +875,7 @@ GEM
|
|||
webfinger (1.2.0)
|
||||
activesupport
|
||||
httpclient (>= 2.4)
|
||||
webmock (3.23.1)
|
||||
webmock (3.24.0)
|
||||
addressable (>= 2.8.0)
|
||||
crack (>= 0.3.2)
|
||||
hashdiff (>= 0.4.0, < 2.0.0)
|
||||
|
@ -902,7 +893,7 @@ GEM
|
|||
xorcist (1.1.3)
|
||||
xpath (3.2.0)
|
||||
nokogiri (~> 1.8)
|
||||
zeitwerk (2.6.18)
|
||||
zeitwerk (2.7.1)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
@ -942,7 +933,7 @@ DEPENDENCIES
|
|||
fast_blank (~> 1.0)
|
||||
fastimage
|
||||
flatware-rspec
|
||||
fog-core (<= 2.5.0)
|
||||
fog-core (<= 2.6.0)
|
||||
fog-openstack (~> 1.0)
|
||||
haml-rails (~> 2.0)
|
||||
haml_lint
|
||||
|
@ -957,6 +948,7 @@ DEPENDENCIES
|
|||
idn-ruby
|
||||
inline_svg
|
||||
irb (~> 1.8)
|
||||
jd-paperclip-azure (~> 3.0)
|
||||
json-ld
|
||||
json-ld-preloaded (~> 3.2)
|
||||
json-schema (~> 5.0)
|
||||
|
@ -968,9 +960,8 @@ DEPENDENCIES
|
|||
lograge (~> 0.12)
|
||||
mail (~> 2.8)
|
||||
mario-redis-lock (~> 1.2)
|
||||
md-paperclip-azure (~> 2.2)
|
||||
memory_profiler
|
||||
mime-types (~> 3.5.0)
|
||||
mime-types (~> 3.6.0)
|
||||
net-http (~> 0.4.0)
|
||||
net-ldap (~> 0.18)
|
||||
nokogiri (~> 1.15)
|
||||
|
@ -991,8 +982,8 @@ DEPENDENCIES
|
|||
opentelemetry-instrumentation-http_client (~> 0.22.3)
|
||||
opentelemetry-instrumentation-net_http (~> 0.22.4)
|
||||
opentelemetry-instrumentation-pg (~> 0.29.0)
|
||||
opentelemetry-instrumentation-rack (~> 0.24.1)
|
||||
opentelemetry-instrumentation-rails (~> 0.31.0)
|
||||
opentelemetry-instrumentation-rack (~> 0.25.0)
|
||||
opentelemetry-instrumentation-rails (~> 0.32.0)
|
||||
opentelemetry-instrumentation-redis (~> 0.25.3)
|
||||
opentelemetry-instrumentation-sidekiq (~> 0.25.2)
|
||||
opentelemetry-sdk (~> 1.4)
|
||||
|
@ -1057,7 +1048,7 @@ DEPENDENCIES
|
|||
xorcist (~> 1.1)
|
||||
|
||||
RUBY VERSION
|
||||
ruby 3.3.4p94
|
||||
ruby 3.3.5p100
|
||||
|
||||
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+
|
||||
- **Redis** 4+
|
||||
- **Ruby** 3.1+
|
||||
- **Ruby** 3.2+
|
||||
- **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.
|
||||
|
|
11
SECURITY.md
11
SECURITY.md
|
@ -13,8 +13,9 @@ A "vulnerability in Mastodon" is a vulnerability in the code distributed through
|
|||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | --------- |
|
||||
| 4.2.x | Yes |
|
||||
| 4.1.x | Yes |
|
||||
| < 4.1 | No |
|
||||
| Version | Supported |
|
||||
| ------- | ---------------- |
|
||||
| 4.3.x | Yes |
|
||||
| 4.2.x | Yes |
|
||||
| 4.1.x | Until 2025-04-08 |
|
||||
| < 4.1 | No |
|
||||
|
|
|
@ -41,11 +41,11 @@ class ActivityPub::OutboxesController < ActivityPub::BaseController
|
|||
end
|
||||
end
|
||||
|
||||
def outbox_url(**kwargs)
|
||||
def outbox_url(**)
|
||||
if params[:account_username].present?
|
||||
account_outbox_url(@account, **kwargs)
|
||||
account_outbox_url(@account, **)
|
||||
else
|
||||
instance_actor_outbox_url(**kwargs)
|
||||
instance_actor_outbox_url(**)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ class Admin::AnnouncementsController < Admin::BaseController
|
|||
|
||||
def index
|
||||
authorize :announcement, :index?
|
||||
@published_announcements_count = Announcement.published.async_count
|
||||
end
|
||||
|
||||
def new
|
||||
|
|
|
@ -6,6 +6,7 @@ class Admin::Disputes::AppealsController < Admin::BaseController
|
|||
def index
|
||||
authorize :appeal, :index?
|
||||
|
||||
@pending_appeals_count = Appeal.pending.async_count
|
||||
@appeals = filtered_appeals.page(params[:page])
|
||||
end
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ class Admin::Trends::Links::PreviewCardProvidersController < Admin::BaseControll
|
|||
def index
|
||||
authorize :preview_card_provider, :review?
|
||||
|
||||
@pending_preview_card_providers_count = PreviewCardProvider.unreviewed.async_count
|
||||
@preview_card_providers = filtered_preview_card_providers.page(params[:page])
|
||||
@form = Trends::PreviewCardProviderBatch.new
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@ class Admin::Trends::LinksController < Admin::BaseController
|
|||
def index
|
||||
authorize :preview_card, :review?
|
||||
|
||||
@locales = PreviewCardTrend.pluck('distinct language')
|
||||
@locales = PreviewCardTrend.locales
|
||||
@preview_cards = filtered_preview_cards.page(params[:page])
|
||||
@form = Trends::PreviewCardBatch.new
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@ class Admin::Trends::StatusesController < Admin::BaseController
|
|||
def index
|
||||
authorize [:admin, :status], :review?
|
||||
|
||||
@locales = StatusTrend.pluck('distinct language')
|
||||
@locales = StatusTrend.locales
|
||||
@statuses = filtered_statuses.page(params[:page])
|
||||
@form = Trends::StatusBatch.new
|
||||
end
|
||||
|
|
|
@ -4,6 +4,7 @@ class Admin::Trends::TagsController < Admin::BaseController
|
|||
def index
|
||||
authorize :tag, :review?
|
||||
|
||||
@pending_tags_count = Tag.pending_review.async_count
|
||||
@tags = filtered_tags.page(params[:page])
|
||||
@form = Trends::TagBatch.new
|
||||
end
|
||||
|
|
|
@ -16,6 +16,7 @@ class Api::V1::AccountsController < Api::BaseController
|
|||
before_action :check_account_confirmation, except: [:index, :create]
|
||||
before_action :check_enabled_registrations, only: [:create]
|
||||
before_action :check_accounts_limit, only: [:index]
|
||||
before_action :check_following_self, only: [:follow]
|
||||
|
||||
skip_before_action :require_authenticated_user!, only: :create
|
||||
|
||||
|
@ -101,8 +102,12 @@ class Api::V1::AccountsController < Api::BaseController
|
|||
raise(Mastodon::ValidationError) if account_ids.size > DEFAULT_ACCOUNTS_LIMIT
|
||||
end
|
||||
|
||||
def relationships(**options)
|
||||
AccountRelationshipsPresenter.new([@account], current_user.account_id, **options)
|
||||
def check_following_self
|
||||
render json: { error: I18n.t('accounts.self_follow_error') }, status: 403 if current_user.account.id == @account.id
|
||||
end
|
||||
|
||||
def relationships(**)
|
||||
AccountRelationshipsPresenter.new([@account], current_user.account_id, **)
|
||||
end
|
||||
|
||||
def account_ids
|
||||
|
|
|
@ -28,8 +28,8 @@ class Api::V1::FollowRequestsController < Api::BaseController
|
|||
@account ||= Account.find(params[:id])
|
||||
end
|
||||
|
||||
def relationships(**options)
|
||||
AccountRelationshipsPresenter.new([account], current_user.account_id, **options)
|
||||
def relationships(**)
|
||||
AccountRelationshipsPresenter.new([account], current_user.account_id, **)
|
||||
end
|
||||
|
||||
def load_accounts
|
||||
|
|
|
@ -52,7 +52,7 @@ class Api::V1::Notifications::RequestsController < Api::BaseController
|
|||
private
|
||||
|
||||
def load_requests
|
||||
requests = NotificationRequest.where(account: current_account).includes(:last_status, from_account: [:account_stat, :user]).to_a_paginated_by_id(
|
||||
requests = NotificationRequest.where(account: current_account).without_suspended.includes(:last_status, from_account: [:account_stat, :user]).to_a_paginated_by_id(
|
||||
limit_param(DEFAULT_ACCOUNTS_LIMIT),
|
||||
params_slice(:max_id, :since_id, :min_id)
|
||||
)
|
||||
|
|
|
@ -23,6 +23,6 @@ class Api::V1::Statuses::TranslationsController < Api::V1::Statuses::BaseControl
|
|||
private
|
||||
|
||||
def set_translation
|
||||
@translation = TranslateStatusService.new.call(@status, content_locale)
|
||||
@translation = TranslateStatusService.new.call(@status, I18n.locale.to_s)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
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 :destroy_previous_subscriptions, only: :create, if: :prior_subscriptions?
|
||||
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
|
||||
end
|
||||
|
||||
def destroy
|
||||
push_subscription = ::Web::PushSubscription.find_by_token_for(:unsubscribe, params[:id])
|
||||
push_subscription&.destroy
|
||||
|
||||
head 200
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def active_session
|
||||
|
|
|
@ -32,7 +32,7 @@ class ApplicationController < ActionController::Base
|
|||
rescue_from ActionController::InvalidAuthenticityToken, with: :unprocessable_entity
|
||||
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 Seahorse::Client::NetworkingError do |e|
|
||||
|
|
|
@ -20,7 +20,7 @@ module Api::ErrorHandling
|
|||
render json: { error: 'Record not found' }, status: 404
|
||||
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
|
||||
end
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ module Auth::CaptchaConcern
|
|||
end
|
||||
|
||||
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
|
||||
|
||||
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']
|
||||
rescue SignatureVerificationError => e
|
||||
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}"
|
||||
rescue Mastodon::UnexpectedResponseError
|
||||
fail_with! 'Failed to fetch remote data (got unexpected reply from server)'
|
||||
|
|
|
@ -13,7 +13,7 @@ module WebAppControllerConcern
|
|||
policy = ContentSecurityPolicy.new
|
||||
|
||||
if policy.sso_host.present?
|
||||
p.form_action policy.sso_host
|
||||
p.form_action policy.sso_host, -> { "https://#{request.host}/auth/auth/" }
|
||||
else
|
||||
p.form_action :none
|
||||
end
|
||||
|
|
|
@ -13,7 +13,7 @@ class MediaProxyController < ApplicationController
|
|||
rescue_from ActiveRecord::RecordInvalid, with: :not_found
|
||||
rescue_from Mastodon::UnexpectedResponseError, 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
|
||||
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!
|
||||
|
||||
def show
|
||||
@export = Export.new(current_account)
|
||||
@export_summary = ExportSummary.new(preloaded_account)
|
||||
@backups = current_user.backups
|
||||
end
|
||||
|
||||
|
@ -25,4 +25,15 @@ class Settings::ExportsController < Settings::BaseController
|
|||
|
||||
redirect_to settings_export_path
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def preloaded_account
|
||||
current_account.tap do |account|
|
||||
ActiveRecord::Associations::Preloader.new(
|
||||
records: [account],
|
||||
associations: :account_stat
|
||||
).call
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,7 +15,7 @@ module Settings
|
|||
end
|
||||
|
||||
def create
|
||||
session[:new_otp_secret] = User.generate_otp_secret(32)
|
||||
session[:new_otp_secret] = User.generate_otp_secret
|
||||
|
||||
redirect_to new_settings_two_factor_authentication_confirmation_path
|
||||
end
|
||||
|
|
|
@ -7,7 +7,23 @@ module WellKnown
|
|||
def show
|
||||
@webfinger_template = "#{webfinger_url}?resource={uri}"
|
||||
expires_in 3.days, public: true
|
||||
render content_type: 'application/xrd+xml', formats: [:xml]
|
||||
|
||||
respond_to do |format|
|
||||
format.any do
|
||||
render content_type: 'application/xrd+xml', formats: [:xml]
|
||||
end
|
||||
|
||||
format.json do
|
||||
render json: {
|
||||
links: [
|
||||
{
|
||||
rel: 'lrdd',
|
||||
template: @webfinger_template,
|
||||
},
|
||||
],
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -35,4 +35,11 @@ module Admin::ActionLogsHelper
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
def sorted_action_log_types
|
||||
Admin::ActionLogFilter::ACTION_TYPE_MAP
|
||||
.keys
|
||||
.map { |key| [I18n.t("admin.action_logs.action_types.#{key}"), key] }
|
||||
.sort_by(&:first)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -18,6 +18,11 @@ module Admin::DashboardHelper
|
|||
end
|
||||
end
|
||||
|
||||
def date_range(range)
|
||||
[l(range.first), l(range.last)]
|
||||
.join(' - ')
|
||||
end
|
||||
|
||||
def relevant_account_timestamp(account)
|
||||
timestamp, exact = if account.user_current_sign_in_at && account.user_current_sign_in_at < 24.hours.ago
|
||||
[account.user_current_sign_in_at, true]
|
||||
|
@ -25,6 +30,8 @@ module Admin::DashboardHelper
|
|||
[account.user_current_sign_in_at, false]
|
||||
elsif account.user_pending?
|
||||
[account.user_created_at, true]
|
||||
elsif account.suspended_at.present? && account.local? && account.user.nil?
|
||||
[account.suspended_at, true]
|
||||
elsif account.last_status_at.present?
|
||||
[account.last_status_at, true]
|
||||
else
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
module Admin::SettingsHelper
|
||||
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
|
||||
|
||||
def login_activity_title(activity)
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ApplicationHelper
|
||||
DANGEROUS_SCOPES = %w(
|
||||
read
|
||||
write
|
||||
follow
|
||||
).freeze
|
||||
|
||||
RTL_LOCALES = %i(
|
||||
ar
|
||||
ckb
|
||||
|
@ -95,8 +89,11 @@ module ApplicationHelper
|
|||
Rails.env.production? ? site_title : "#{site_title} (Dev)"
|
||||
end
|
||||
|
||||
def class_for_scope(scope)
|
||||
'scope-danger' if DANGEROUS_SCOPES.include?(scope.to_s)
|
||||
def label_for_scope(scope)
|
||||
safe_join [
|
||||
tag.samp(scope, class: { 'scope-danger' => SessionActivation::DEFAULT_SCOPES.include?(scope.to_s) }),
|
||||
tag.span(t("doorkeeper.scopes.#{scope}"), class: :hint),
|
||||
]
|
||||
end
|
||||
|
||||
def can?(action, record)
|
||||
|
@ -123,18 +120,6 @@ module ApplicationHelper
|
|||
inline_svg_tag 'check.svg'
|
||||
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)
|
||||
if relationships.following[account_id] && relationships.followed_by[account_id]
|
||||
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'))
|
||||
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
|
||||
|
||||
def storage_host_var
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
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 = {})
|
||||
HtmlAwareFormatter.new(text, local, options).to_s
|
||||
end
|
||||
|
@ -19,42 +27,33 @@ module FormattingHelper
|
|||
module_function :extract_status_plain_text
|
||||
|
||||
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
|
||||
|
||||
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(
|
||||
safe_join([before_html, html, after_html]),
|
||||
wrapped_status_content_format(status),
|
||||
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
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
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)
|
||||
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
|
||||
|
|
|
@ -162,7 +162,7 @@ module LanguagesHelper
|
|||
th: ['Thai', 'ไทย'].freeze,
|
||||
ti: ['Tigrinya', 'ትግርኛ'].freeze,
|
||||
tk: ['Turkmen', 'Türkmen'].freeze,
|
||||
tl: ['Tagalog', 'Wikang Tagalog'].freeze,
|
||||
tl: ['Tagalog', 'Tagalog'].freeze,
|
||||
tn: ['Tswana', 'Setswana'].freeze,
|
||||
to: ['Tonga', 'faka Tonga'].freeze,
|
||||
tr: ['Turkish', 'Türkçe'].freeze,
|
||||
|
@ -193,6 +193,7 @@ module LanguagesHelper
|
|||
ckb: ['Sorani (Kurdish)', 'سۆرانی'].freeze,
|
||||
cnr: ['Montenegrin', 'crnogorski'].freeze,
|
||||
csb: ['Kashubian', 'Kaszëbsczi'].freeze,
|
||||
gsw: ['Swiss German', 'Schwiizertütsch'].freeze,
|
||||
jbo: ['Lojban', 'la .lojban.'].freeze,
|
||||
kab: ['Kabyle', 'Taqbaylit'].freeze,
|
||||
ldn: ['Láadan', 'Láadan'].freeze,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module MediaComponentHelper
|
||||
def render_video_component(status, **options)
|
||||
def render_video_component(status, **)
|
||||
video = status.ordered_media_attachments.first
|
||||
|
||||
meta = video.file.meta || {}
|
||||
|
@ -18,14 +18,14 @@ module MediaComponentHelper
|
|||
media: [
|
||||
serialize_media_attachment(video),
|
||||
].as_json,
|
||||
}.merge(**options)
|
||||
}.merge(**)
|
||||
|
||||
react_component :video, component_params do
|
||||
render partial: 'statuses/attachment_list', locals: { attachments: status.ordered_media_attachments }
|
||||
end
|
||||
end
|
||||
|
||||
def render_audio_component(status, **options)
|
||||
def render_audio_component(status, **)
|
||||
audio = status.ordered_media_attachments.first
|
||||
|
||||
meta = audio.file.meta || {}
|
||||
|
@ -38,19 +38,19 @@ module MediaComponentHelper
|
|||
foregroundColor: meta.dig('colors', 'foreground'),
|
||||
accentColor: meta.dig('colors', 'accent'),
|
||||
duration: meta.dig('original', 'duration'),
|
||||
}.merge(**options)
|
||||
}.merge(**)
|
||||
|
||||
react_component :audio, component_params do
|
||||
render partial: 'statuses/attachment_list', locals: { attachments: status.ordered_media_attachments }
|
||||
end
|
||||
end
|
||||
|
||||
def render_media_gallery_component(status, **options)
|
||||
def render_media_gallery_component(status, **)
|
||||
component_params = {
|
||||
sensitive: sensitive_viewer?(status, current_account),
|
||||
autoplay: prefers_autoplay?,
|
||||
media: status.ordered_media_attachments.map { |a| serialize_media_attachment(a).as_json },
|
||||
}.merge(**options)
|
||||
}.merge(**)
|
||||
|
||||
react_component :media_gallery, component_params do
|
||||
render partial: 'statuses/attachment_list', locals: { attachments: status.ordered_media_attachments }
|
||||
|
|
|
@ -14,8 +14,8 @@ module RoutingHelper
|
|||
end
|
||||
end
|
||||
|
||||
def full_asset_url(source, **options)
|
||||
source = ActionController::Base.helpers.asset_url(source, **options) unless use_storage?
|
||||
def full_asset_url(source, **)
|
||||
source = ActionController::Base.helpers.asset_url(source, **) unless use_storage?
|
||||
|
||||
URI.join(asset_host, source).to_s
|
||||
end
|
||||
|
@ -24,12 +24,12 @@ module RoutingHelper
|
|||
Rails.configuration.action_controller.asset_host || root_url
|
||||
end
|
||||
|
||||
def frontend_asset_path(source, **options)
|
||||
asset_pack_path("media/#{source}", **options)
|
||||
def frontend_asset_path(source, **)
|
||||
asset_pack_path("media/#{source}", **)
|
||||
end
|
||||
|
||||
def frontend_asset_url(source, **options)
|
||||
full_asset_url(frontend_asset_path(source, **options))
|
||||
def frontend_asset_url(source, **)
|
||||
full_asset_url(frontend_asset_path(source, **))
|
||||
end
|
||||
|
||||
def use_storage?
|
||||
|
|
|
@ -12,7 +12,7 @@ module StatusesHelper
|
|||
}.freeze
|
||||
|
||||
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')
|
||||
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;
|
||||
|
||||
const oldReadOnly = input.readOnly;
|
||||
|
||||
input.readOnly = false;
|
||||
input.focus();
|
||||
input.select();
|
||||
input.setSelectionRange(0, input.value.length);
|
||||
|
||||
try {
|
||||
if (document.execCommand('copy')) {
|
||||
input.blur();
|
||||
|
||||
navigator.clipboard
|
||||
.writeText(input.value)
|
||||
.then(() => {
|
||||
const parent = target.parentElement;
|
||||
|
||||
if (!parent) return;
|
||||
parent.classList.add('copied');
|
||||
if (parent) {
|
||||
parent.classList.add('copied');
|
||||
|
||||
setTimeout(() => {
|
||||
parent.classList.remove('copied');
|
||||
}, 700);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
setTimeout(() => {
|
||||
parent.classList.remove('copied');
|
||||
}, 700);
|
||||
}
|
||||
|
||||
input.readOnly = oldReadOnly;
|
||||
return true;
|
||||
})
|
||||
.catch((error: unknown) => {
|
||||
console.error(error);
|
||||
});
|
||||
});
|
||||
|
||||
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;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
} else if ('navigator' && 'sendBeacon' in navigator) {
|
||||
} else if ('sendBeacon' in navigator) {
|
||||
// Failing that, we can use sendBeacon, but we have to encode the data as
|
||||
// FormData for DoorKeeper to recognize the token.
|
||||
const formData = new FormData();
|
||||
|
|
|
@ -8,6 +8,7 @@ import type { ApiAccountJSON } from 'mastodon/api_types/accounts';
|
|||
import type {
|
||||
ApiNotificationGroupJSON,
|
||||
ApiNotificationJSON,
|
||||
NotificationType,
|
||||
} from 'mastodon/api_types/notifications';
|
||||
import { allNotificationTypes } from 'mastodon/api_types/notifications';
|
||||
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 {
|
||||
selectSettingsNotificationsExcludedTypes,
|
||||
selectSettingsNotificationsGroupFollows,
|
||||
selectSettingsNotificationsQuickFilterActive,
|
||||
selectSettingsNotificationsShows,
|
||||
} from 'mastodon/selectors/settings';
|
||||
|
@ -68,13 +70,19 @@ function dispatchAssociatedRecords(
|
|||
dispatch(importFetchedStatuses(fetchedStatuses));
|
||||
}
|
||||
|
||||
const supportedGroupedNotificationTypes = ['favourite', 'reblog'];
|
||||
function selectNotificationGroupedTypes(state: RootState) {
|
||||
const types: NotificationType[] = ['favourite', 'reblog'];
|
||||
|
||||
if (selectSettingsNotificationsGroupFollows(state)) types.push('follow');
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
export const fetchNotifications = createDataLoadingThunk(
|
||||
'notificationGroups/fetch',
|
||||
async (_params, { getState }) =>
|
||||
apiFetchNotificationGroups({
|
||||
grouped_types: supportedGroupedNotificationTypes,
|
||||
grouped_types: selectNotificationGroupedTypes(getState()),
|
||||
exclude_types: getExcludedTypes(getState()),
|
||||
}),
|
||||
({ notifications, accounts, statuses }, { dispatch }) => {
|
||||
|
@ -98,7 +106,7 @@ export const fetchNotificationsGap = createDataLoadingThunk(
|
|||
'notificationGroups/fetchGap',
|
||||
async (params: { gap: NotificationGap }, { getState }) =>
|
||||
apiFetchNotificationGroups({
|
||||
grouped_types: supportedGroupedNotificationTypes,
|
||||
grouped_types: selectNotificationGroupedTypes(getState()),
|
||||
max_id: params.gap.maxId,
|
||||
exclude_types: getExcludedTypes(getState()),
|
||||
}),
|
||||
|
@ -115,7 +123,7 @@ export const pollRecentNotifications = createDataLoadingThunk(
|
|||
'notificationGroups/pollRecentNotifications',
|
||||
async (_params, { getState }) => {
|
||||
return apiFetchNotificationGroups({
|
||||
grouped_types: supportedGroupedNotificationTypes,
|
||||
grouped_types: selectNotificationGroupedTypes(getState()),
|
||||
max_id: undefined,
|
||||
exclude_types: getExcludedTypes(getState()),
|
||||
// In slow mode, we don't want to include notifications that duplicate the already-displayed ones
|
||||
|
@ -164,7 +172,10 @@ export const processNewNotificationForGroups = createAppAsyncThunk(
|
|||
|
||||
dispatchAssociatedRecords(dispatch, [notification]);
|
||||
|
||||
return notification;
|
||||
return {
|
||||
notification,
|
||||
groupedTypes: selectNotificationGroupedTypes(state),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
|
|
|
@ -106,12 +106,13 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti
|
|||
dispatch(processNewNotificationForGroups(notificationJSON));
|
||||
break;
|
||||
}
|
||||
case 'notifications_merged':
|
||||
case 'notifications_merged': {
|
||||
const state = getState();
|
||||
if (state.notifications.top || !state.notifications.mounted)
|
||||
dispatch(expandNotifications({ forceLoad: true, maxId: undefined }));
|
||||
dispatch(refreshStaleNotificationGroups());
|
||||
break;
|
||||
}
|
||||
case 'conversation':
|
||||
// @ts-expect-error
|
||||
dispatch(updateConversations(JSON.parse(data.payload)));
|
||||
|
|
|
@ -13,7 +13,7 @@ export interface ApiAccountRoleJSON {
|
|||
}
|
||||
|
||||
// See app/serializers/rest/account_serializer.rb
|
||||
export interface ApiAccountJSON {
|
||||
export interface BaseApiAccountJSON {
|
||||
acct: string;
|
||||
avatar: string;
|
||||
avatar_static: string;
|
||||
|
@ -45,3 +45,12 @@ export interface ApiAccountJSON {
|
|||
memorial?: boolean;
|
||||
hide_collections: boolean;
|
||||
}
|
||||
|
||||
// See app/serializers/rest/muted_account_serializer.rb
|
||||
export interface ApiMutedAccountJSON extends BaseApiAccountJSON {
|
||||
mute_expires_at?: string | null;
|
||||
}
|
||||
|
||||
// For now, we have the same type representing both `Account` and `MutedAccount`
|
||||
// objects, but we should refactor this in the future.
|
||||
export type ApiAccountJSON = ApiMutedAccountJSON;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
exports[`<Avatar /> Autoplay renders a animated avatar 1`] = `
|
||||
<div
|
||||
className="account__avatar"
|
||||
className="account__avatar account__avatar--loading"
|
||||
onMouseEnter={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
style={
|
||||
|
@ -14,6 +14,8 @@ exports[`<Avatar /> Autoplay renders a animated avatar 1`] = `
|
|||
>
|
||||
<img
|
||||
alt=""
|
||||
onError={[Function]}
|
||||
onLoad={[Function]}
|
||||
src="/animated/alice.gif"
|
||||
/>
|
||||
</div>
|
||||
|
@ -21,7 +23,7 @@ exports[`<Avatar /> Autoplay renders a animated avatar 1`] = `
|
|||
|
||||
exports[`<Avatar /> Still renders a still avatar 1`] = `
|
||||
<div
|
||||
className="account__avatar"
|
||||
className="account__avatar account__avatar--loading"
|
||||
onMouseEnter={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
style={
|
||||
|
@ -33,6 +35,8 @@ exports[`<Avatar /> Still renders a still avatar 1`] = `
|
|||
>
|
||||
<img
|
||||
alt=""
|
||||
onError={[Function]}
|
||||
onLoad={[Function]}
|
||||
src="/static/alice.jpg"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import { useState, useCallback } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { useHovering } from 'mastodon/../hooks/useHovering';
|
||||
import { autoPlayGif } from 'mastodon/initial_state';
|
||||
import type { Account } from 'mastodon/models/account';
|
||||
|
||||
import { useHovering } from '../../hooks/useHovering';
|
||||
import { autoPlayGif } from '../initial_state';
|
||||
|
||||
interface Props {
|
||||
account: Account | undefined; // FIXME: remove `undefined` once we know for sure its always there
|
||||
size: number;
|
||||
|
@ -25,6 +26,8 @@ export const Avatar: React.FC<Props> = ({
|
|||
counterBorderColor,
|
||||
}) => {
|
||||
const { hovering, handleMouseEnter, handleMouseLeave } = useHovering(animate);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(false);
|
||||
|
||||
const style = {
|
||||
...styleFromParent,
|
||||
|
@ -37,16 +40,28 @@ export const Avatar: React.FC<Props> = ({
|
|||
? account?.get('avatar')
|
||||
: account?.get('avatar_static');
|
||||
|
||||
const handleLoad = useCallback(() => {
|
||||
setLoading(false);
|
||||
}, [setLoading]);
|
||||
|
||||
const handleError = useCallback(() => {
|
||||
setError(true);
|
||||
}, [setError]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames('account__avatar', {
|
||||
'account__avatar-inline': inline,
|
||||
'account__avatar--inline': inline,
|
||||
'account__avatar--loading': loading,
|
||||
})}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
style={style}
|
||||
>
|
||||
{src && <img src={src} alt='' />}
|
||||
{src && !error && (
|
||||
<img src={src} alt='' onLoad={handleLoad} onError={handleError} />
|
||||
)}
|
||||
|
||||
{counter && (
|
||||
<div
|
||||
className='account__avatar__counter'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { PropsWithChildren } from 'react';
|
||||
import type { PropsWithChildren, JSX } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
|
|
@ -8,7 +8,7 @@ export const ContentWarning: React.FC<{
|
|||
<StatusBanner
|
||||
expanded={expanded}
|
||||
onClick={onClick}
|
||||
variant={BannerVariant.Yellow}
|
||||
variant={BannerVariant.Warning}
|
||||
>
|
||||
<p dangerouslySetInnerHTML={{ __html: text }} />
|
||||
</StatusBanner>
|
||||
|
|
|
@ -10,13 +10,16 @@ export const FilterWarning: React.FC<{
|
|||
<StatusBanner
|
||||
expanded={expanded}
|
||||
onClick={onClick}
|
||||
variant={BannerVariant.Blue}
|
||||
variant={BannerVariant.Filter}
|
||||
>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='filter_warning.matches_filter'
|
||||
defaultMessage='Matches filter “{title}”'
|
||||
values={{ title }}
|
||||
defaultMessage='Matches filter “<span>{title}</span>”'
|
||||
values={{
|
||||
title,
|
||||
span: (chunks) => <span className='filter-name'>{chunks}</span>,
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
</StatusBanner>
|
||||
|
|
|
@ -196,7 +196,7 @@ class Item extends PureComponent {
|
|||
|
||||
{visible && thumbnail}
|
||||
|
||||
{badges && (
|
||||
{visible && badges && (
|
||||
<div className='media-gallery__item__badges'>
|
||||
{badges}
|
||||
</div>
|
||||
|
@ -336,14 +336,14 @@ class MediaGallery extends PureComponent {
|
|||
|
||||
return (
|
||||
<div className={`media-gallery media-gallery--layout-${size}`} style={style} ref={this.handleRef}>
|
||||
{children}
|
||||
|
||||
{(!visible || uncached) && (
|
||||
<div className={classNames('spoiler-button', { 'spoiler-button--click-thru': uncached })}>
|
||||
{spoilerButton}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{children}
|
||||
|
||||
{(visible && !uncached) && (
|
||||
<div className='media-gallery__actions'>
|
||||
<button className='media-gallery__actions__pill' onClick={this.handleOpen}><FormattedMessage id='media_gallery.hide' defaultMessage='Hide' /></button>
|
||||
|
|
|
@ -41,12 +41,14 @@ const makeEmojiMap = record => record.get('emojis').reduce((obj, emoji) => {
|
|||
class Poll extends ImmutablePureComponent {
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
poll: ImmutablePropTypes.map,
|
||||
poll: ImmutablePropTypes.map.isRequired,
|
||||
status: ImmutablePropTypes.map.isRequired,
|
||||
lang: PropTypes.string,
|
||||
intl: PropTypes.object.isRequired,
|
||||
disabled: PropTypes.bool,
|
||||
refresh: PropTypes.func,
|
||||
onVote: PropTypes.func,
|
||||
onInteractionModal: PropTypes.func,
|
||||
};
|
||||
|
||||
state = {
|
||||
|
@ -117,7 +119,11 @@ class Poll extends ImmutablePureComponent {
|
|||
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 = () => {
|
||||
|
@ -232,7 +238,7 @@ class Poll extends ImmutablePureComponent {
|
|||
</ul>
|
||||
|
||||
<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 && !this.props.disabled && <><button className='poll__link' onClick={this.handleRefresh}><FormattedMessage id='poll.refresh' defaultMessage='Refresh' /></button> · </>}
|
||||
{votesCount}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { memo } from 'react';
|
||||
import type { JSX } from 'react';
|
||||
|
||||
import { FormattedMessage, FormattedNumber } from 'react-intl';
|
||||
|
||||
|
|
|
@ -449,7 +449,7 @@ class Status extends ImmutablePureComponent {
|
|||
} else if (status.get('media_attachments').size > 0) {
|
||||
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 = (
|
||||
<Bundle fetchComponent={MediaGallery} loading={this.renderLoadingMediaGallery}>
|
||||
{Component => (
|
||||
|
|
|
@ -264,7 +264,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||
menu.push({ text: intl.formatMessage(messages.share), action: this.handleShareClick });
|
||||
}
|
||||
|
||||
if (publicStatus && (signedIn || !isRemote)) {
|
||||
if (publicStatus && !isRemote) {
|
||||
menu.push({ text: intl.formatMessage(messages.embed), action: this.handleEmbed });
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
export enum BannerVariant {
|
||||
Yellow = 'yellow',
|
||||
Blue = 'blue',
|
||||
Warning = 'warning',
|
||||
Filter = 'filter',
|
||||
}
|
||||
|
||||
export const StatusBanner: React.FC<{
|
||||
|
@ -11,9 +11,9 @@ export const StatusBanner: React.FC<{
|
|||
expanded?: boolean;
|
||||
onClick?: () => void;
|
||||
}> = ({ children, variant, expanded, onClick }) => (
|
||||
<div
|
||||
<label
|
||||
className={
|
||||
variant === BannerVariant.Yellow
|
||||
variant === BannerVariant.Warning
|
||||
? 'content-warning'
|
||||
: 'content-warning content-warning--filter'
|
||||
}
|
||||
|
@ -26,6 +26,11 @@ export const StatusBanner: React.FC<{
|
|||
id='content_warning.hide'
|
||||
defaultMessage='Hide post'
|
||||
/>
|
||||
) : variant === BannerVariant.Warning ? (
|
||||
<FormattedMessage
|
||||
id='content_warning.show_more'
|
||||
defaultMessage='Show more'
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
id='content_warning.show'
|
||||
|
@ -33,5 +38,5 @@ export const StatusBanner: React.FC<{
|
|||
/>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</label>
|
||||
);
|
||||
|
|
|
@ -245,7 +245,7 @@ class StatusContent extends PureComponent {
|
|||
);
|
||||
|
||||
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) {
|
||||
|
|
|
@ -2,6 +2,7 @@ import { connect } from 'react-redux';
|
|||
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
import { openModal } from 'mastodon/actions/modal';
|
||||
import { fetchPoll, vote } from 'mastodon/actions/polls';
|
||||
import Poll from 'mastodon/components/poll';
|
||||
|
||||
|
@ -17,6 +18,17 @@ const mapDispatchToProps = (dispatch, { pollId }) => ({
|
|||
onVote (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 }) => ({
|
||||
|
|
|
@ -21,9 +21,11 @@ class ColumnSettings extends PureComponent {
|
|||
|
||||
return (
|
||||
<div className='column-settings'>
|
||||
<div className='column-settings__row'>
|
||||
<SettingToggle settings={settings} settingPath={['other', 'onlyMedia']} onChange={onChange} label={<FormattedMessage id='community.column_settings.media_only' defaultMessage='Media only' />} />
|
||||
</div>
|
||||
<section>
|
||||
<div className='column-settings__row'>
|
||||
<SettingToggle settings={settings} settingPath={['other', 'onlyMedia']} onChange={onChange} label={<FormattedMessage id='community.column_settings.media_only' defaultMessage='Media only' />} />
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ const messages = defineMessages({
|
|||
minutes: { id: 'intervals.full.minutes', defaultMessage: '{number, plural, one {# minute} other {# minutes}}' },
|
||||
hours: { id: 'intervals.full.hours', defaultMessage: '{number, plural, one {# hour} other {# hours}}' },
|
||||
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' },
|
||||
});
|
||||
|
||||
|
|
|
@ -129,8 +129,13 @@ export const InlineFollowSuggestions = ({ hidden }) => {
|
|||
return;
|
||||
}
|
||||
|
||||
setCanScrollLeft(bodyRef.current.scrollLeft > 0);
|
||||
setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth);
|
||||
if (getComputedStyle(bodyRef.current).direction === 'rtl') {
|
||||
setCanScrollLeft((bodyRef.current.clientWidth - bodyRef.current.scrollLeft) < bodyRef.current.scrollWidth);
|
||||
setCanScrollRight(bodyRef.current.scrollLeft < 0);
|
||||
} else {
|
||||
setCanScrollLeft(bodyRef.current.scrollLeft > 0);
|
||||
setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth);
|
||||
}
|
||||
}, [setCanScrollRight, setCanScrollLeft, bodyRef, suggestions]);
|
||||
|
||||
const handleLeftNav = useCallback(() => {
|
||||
|
@ -146,8 +151,13 @@ export const InlineFollowSuggestions = ({ hidden }) => {
|
|||
return;
|
||||
}
|
||||
|
||||
setCanScrollLeft(bodyRef.current.scrollLeft > 0);
|
||||
setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth);
|
||||
if (getComputedStyle(bodyRef.current).direction === 'rtl') {
|
||||
setCanScrollLeft((bodyRef.current.clientWidth - bodyRef.current.scrollLeft) < bodyRef.current.scrollWidth);
|
||||
setCanScrollRight(bodyRef.current.scrollLeft < 0);
|
||||
} else {
|
||||
setCanScrollLeft(bodyRef.current.scrollLeft > 0);
|
||||
setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth);
|
||||
}
|
||||
}, [setCanScrollRight, setCanScrollLeft, bodyRef]);
|
||||
|
||||
const handleDismiss = useCallback(() => {
|
||||
|
|
|
@ -9,6 +9,7 @@ import { connect } from 'react-redux';
|
|||
|
||||
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 RepeatIcon from '@/material-icons/400-24px/repeat.svg?react';
|
||||
import ReplyIcon from '@/material-icons/400-24px/reply.svg?react';
|
||||
|
@ -340,7 +341,7 @@ class InteractionModal extends React.PureComponent {
|
|||
static propTypes = {
|
||||
displayNameHtml: PropTypes.string,
|
||||
url: PropTypes.string,
|
||||
type: PropTypes.oneOf(['reply', 'reblog', 'favourite', 'follow']),
|
||||
type: PropTypes.oneOf(['reply', 'reblog', 'favourite', 'follow', 'vote']),
|
||||
onSignupClick: PropTypes.func.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 }} />;
|
||||
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;
|
||||
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;
|
||||
|
|
|
@ -38,6 +38,7 @@ class ColumnSettings extends PureComponent {
|
|||
const alertStr = <FormattedMessage id='notifications.column_settings.alert' defaultMessage='Desktop notifications' />;
|
||||
const showStr = <FormattedMessage id='notifications.column_settings.show' defaultMessage='Show in column' />;
|
||||
const soundStr = <FormattedMessage id='notifications.column_settings.sound' defaultMessage='Play sound' />;
|
||||
const groupStr = <FormattedMessage id='notifications.column_settings.group' defaultMessage='Group' />;
|
||||
|
||||
const showPushSettings = pushSettings.get('browserSupport') && pushSettings.get('isSubscribed');
|
||||
const pushStr = showPushSettings && <FormattedMessage id='notifications.column_settings.push' defaultMessage='Push notifications' />;
|
||||
|
@ -94,6 +95,7 @@ class ColumnSettings extends PureComponent {
|
|||
{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={['sounds', 'follow']} onChange={onChange} label={soundStr} />
|
||||
<SettingToggle prefix='notifications' settings={settings} settingPath={['group', 'follow']} onChange={onChange} label={groupStr} />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
|
|
@ -56,11 +56,12 @@ const mapDispatchToProps = (dispatch) => ({
|
|||
} else {
|
||||
dispatch(changeSetting(['notifications', ...path], checked));
|
||||
}
|
||||
} else if(path[0] === 'groupingBeta') {
|
||||
dispatch(changeSetting(['notifications', ...path], checked));
|
||||
dispatch(initializeNotifications());
|
||||
} else {
|
||||
dispatch(changeSetting(['notifications', ...path], checked));
|
||||
|
||||
if(path[0] === 'group' && path[1] === 'follow') {
|
||||
dispatch(initializeNotifications());
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -1,16 +1,21 @@
|
|||
import type { JSX } from 'react';
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import PersonAddIcon from '@/material-icons/400-24px/person_add-fill.svg?react';
|
||||
import { FollowersCounter } from 'mastodon/components/counters';
|
||||
import { FollowButton } from 'mastodon/components/follow_button';
|
||||
import { ShortNumber } from 'mastodon/components/short_number';
|
||||
import { me } from 'mastodon/initial_state';
|
||||
import type { NotificationGroupFollow } from 'mastodon/models/notification_group';
|
||||
import { useAppSelector } from 'mastodon/store';
|
||||
|
||||
import type { LabelRenderer } from './notification_group_with_status';
|
||||
import { NotificationGroupWithStatus } from './notification_group_with_status';
|
||||
|
||||
const labelRenderer: LabelRenderer = (displayedName, total) => {
|
||||
const labelRenderer: LabelRenderer = (displayedName, total, seeMoreHref) => {
|
||||
if (total === 1)
|
||||
return (
|
||||
<FormattedMessage
|
||||
|
@ -23,10 +28,12 @@ const labelRenderer: LabelRenderer = (displayedName, total) => {
|
|||
return (
|
||||
<FormattedMessage
|
||||
id='notification.follow.name_and_others'
|
||||
defaultMessage='{name} and {count, plural, one {# other} other {# others}} followed you'
|
||||
defaultMessage='{name} and <a>{count, plural, one {# other} other {# others}}</a> followed you'
|
||||
values={{
|
||||
name: displayedName,
|
||||
count: total - 1,
|
||||
a: (chunks) =>
|
||||
seeMoreHref ? <Link to={seeMoreHref}>{chunks}</Link> : chunks,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
@ -46,6 +53,10 @@ export const NotificationFollow: React.FC<{
|
|||
notification: NotificationGroupFollow;
|
||||
unread: boolean;
|
||||
}> = ({ notification, unread }) => {
|
||||
const username = useAppSelector(
|
||||
(state) => state.accounts.getIn([me, 'username']) as string,
|
||||
);
|
||||
|
||||
let actions: JSX.Element | undefined;
|
||||
let additionalContent: JSX.Element | undefined;
|
||||
|
||||
|
@ -68,6 +79,7 @@ export const NotificationFollow: React.FC<{
|
|||
timestamp={notification.latest_page_notification_at}
|
||||
count={notification.notifications_count}
|
||||
labelRenderer={labelRenderer}
|
||||
labelSeeMoreHref={`/@${username}/followers`}
|
||||
unread={unread}
|
||||
actions={actions}
|
||||
additionalContent={additionalContent}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { useMemo } from 'react';
|
||||
import type { JSX } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
import type { IconProp } from 'mastodon/components/icon';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import Status from 'mastodon/containers/status_container';
|
||||
import { getStatusHidden } from 'mastodon/selectors/filters';
|
||||
import { useAppSelector, useAppDispatch } from 'mastodon/store';
|
||||
|
||||
import { DisplayedName } from './displayed_name';
|
||||
|
@ -48,6 +49,12 @@ export const NotificationWithStatus: React.FC<{
|
|||
(state) => state.statuses.getIn([statusId, 'visibility']) === 'direct',
|
||||
);
|
||||
|
||||
const isFiltered = useAppSelector(
|
||||
(state) =>
|
||||
statusId &&
|
||||
getStatusHidden(state, { id: statusId, contextType: 'notifications' }),
|
||||
);
|
||||
|
||||
const handlers = useMemo(
|
||||
() => ({
|
||||
open: () => {
|
||||
|
@ -73,7 +80,7 @@ export const NotificationWithStatus: React.FC<{
|
|||
[dispatch, statusId],
|
||||
);
|
||||
|
||||
if (!statusId) return null;
|
||||
if (!statusId || isFiltered) return null;
|
||||
|
||||
return (
|
||||
<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 ReplyAllIcon from '@/material-icons/400-24px/reply_all.svg?react';
|
||||
import StarIcon from '@/material-icons/400-24px/star.svg?react';
|
||||
import RepeatDisabledIcon from '@/svg-icons/repeat_disabled.svg?react';
|
||||
import RepeatPrivateIcon from '@/svg-icons/repeat_private.svg?react';
|
||||
import { replyCompose } from 'mastodon/actions/compose';
|
||||
import { toggleReblog, toggleFavourite } from 'mastodon/actions/interactions';
|
||||
import { openModal } from 'mastodon/actions/modal';
|
||||
|
@ -159,22 +161,26 @@ class Footer extends ImmutablePureComponent {
|
|||
replyTitle = intl.formatMessage(messages.replyAll);
|
||||
}
|
||||
|
||||
let reblogTitle = '';
|
||||
let reblogTitle, reblogIconComponent;
|
||||
|
||||
if (status.get('reblogged')) {
|
||||
reblogTitle = intl.formatMessage(messages.cancel_reblog_private);
|
||||
reblogIconComponent = publicStatus ? RepeatIcon : RepeatPrivateIcon;
|
||||
} else if (publicStatus) {
|
||||
reblogTitle = intl.formatMessage(messages.reblog);
|
||||
reblogIconComponent = RepeatIcon;
|
||||
} else if (reblogPrivate) {
|
||||
reblogTitle = intl.formatMessage(messages.reblog_private);
|
||||
reblogIconComponent = RepeatPrivateIcon;
|
||||
} else {
|
||||
reblogTitle = intl.formatMessage(messages.cannot_reblog);
|
||||
reblogIconComponent = RepeatDisabledIcon;
|
||||
}
|
||||
|
||||
return (
|
||||
<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={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={RepeatIcon} onClick={this.handleReblogClick} counter={status.get('reblogs_count')} />
|
||||
<IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' iconComponent={reblogIconComponent} onClick={this.handleReblogClick} counter={status.get('reblogs_count')} />
|
||||
<IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={StarIcon} onClick={this.handleFavouriteClick} counter={status.get('favourites_count')} />
|
||||
{withOpenButton && <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.open)} icon='external-link' iconComponent={OpenInNewIcon} onClick={this.handleOpenClick} href={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} />}
|
||||
</div>
|
||||
|
|
|
@ -152,7 +152,7 @@ export const DetailedStatus: React.FC<{
|
|||
media = <PictureInPicturePlaceholder aspectRatio={attachmentAspectRatio} />;
|
||||
} else if (status.get('media_attachments').size > 0) {
|
||||
if (
|
||||
['image', 'gifv'].includes(
|
||||
['image', 'gifv', 'unknown'].includes(
|
||||
status.getIn(['media_attachments', 0, 'type']) as string,
|
||||
) ||
|
||||
status.get('media_attachments').size > 1
|
||||
|
|
|
@ -15,7 +15,7 @@ const ColumnLink = ({ icon, activeIcon, iconComponent, activeIconComponent, text
|
|||
|
||||
if (href) {
|
||||
return (
|
||||
<a href={href} className={className} data-method={method} title={text} {...other}>
|
||||
<a href={href} className={className} data-method={method} {...other}>
|
||||
{active ? activeIconElement : iconElement}
|
||||
<span>{text}</span>
|
||||
{badgeElement}
|
||||
|
@ -23,7 +23,7 @@ const ColumnLink = ({ icon, activeIcon, iconComponent, activeIconComponent, text
|
|||
);
|
||||
} else {
|
||||
return (
|
||||
<NavLink to={to} className={className} title={text} exact {...other}>
|
||||
<NavLink to={to} className={className} exact {...other}>
|
||||
{active ? activeIconElement : iconElement}
|
||||
<span>{text}</span>
|
||||
{badgeElement}
|
||||
|
|
|
@ -116,6 +116,7 @@ export const MuteModal = ({ accountId, acct }) => {
|
|||
<div className='safety-action-modal__bottom__collapsible'>
|
||||
<div className='safety-action-modal__field-group'>
|
||||
<RadioButtonLabel name='duration' value='0' label={intl.formatMessage(messages.indefinite)} currentValue={muteDuration} onChange={handleChangeMuteDuration} />
|
||||
<RadioButtonLabel name='duration' value='21600' label={intl.formatMessage(messages.hours, { number: 6 })} currentValue={muteDuration} onChange={handleChangeMuteDuration} />
|
||||
<RadioButtonLabel name='duration' value='86400' label={intl.formatMessage(messages.hours, { number: 24 })} currentValue={muteDuration} onChange={handleChangeMuteDuration} />
|
||||
<RadioButtonLabel name='duration' value='604800' label={intl.formatMessage(messages.days, { number: 7 })} currentValue={muteDuration} onChange={handleChangeMuteDuration} />
|
||||
<RadioButtonLabel name='duration' value='2592000' label={intl.formatMessage(messages.days, { number: 30 })} currentValue={muteDuration} onChange={handleChangeMuteDuration} />
|
||||
|
|
|
@ -84,6 +84,7 @@
|
|||
"alert.rate_limited.title": "معدل الطلبات محدود",
|
||||
"alert.unexpected.message": "لقد طرأ خطأ غير متوقّع.",
|
||||
"alert.unexpected.title": "المعذرة!",
|
||||
"alt_text_badge.title": "نص بديل",
|
||||
"announcement.announcement": "إعلان",
|
||||
"attachments_list.unprocessed": "(غير معالَج)",
|
||||
"audio.hide": "إخفاء المقطع الصوتي",
|
||||
|
@ -156,7 +157,6 @@
|
|||
"compose_form.poll.duration": "مُدَّة اِستطلاع الرأي",
|
||||
"compose_form.poll.multiple": "متعدد الخيارات",
|
||||
"compose_form.poll.option_placeholder": "الخيار {number}",
|
||||
"compose_form.poll.single": "اختر واحدا",
|
||||
"compose_form.poll.switch_to_multiple": "تغيِير الاستطلاع للسماح باِخيارات مُتعدِّدة",
|
||||
"compose_form.poll.switch_to_single": "تغيِير الاستطلاع للسماح باِخيار واحد فقط",
|
||||
"compose_form.poll.type": "الطراز",
|
||||
|
@ -301,7 +301,6 @@
|
|||
"filter_modal.select_filter.subtitle": "استخدم فئة موجودة أو قم بإنشاء فئة جديدة",
|
||||
"filter_modal.select_filter.title": "تصفية هذا المنشور",
|
||||
"filter_modal.title.status": "تصفية منشور",
|
||||
"filter_warning.matches_filter": "يطابق عامل التصفية \"{title}\"",
|
||||
"filtered_notifications_banner.title": "الإشعارات المصفاة",
|
||||
"firehose.all": "الكل",
|
||||
"firehose.local": "هذا الخادم",
|
||||
|
@ -758,7 +757,7 @@
|
|||
"status.history.edited": "عدله {name} {date}",
|
||||
"status.load_more": "حمّل المزيد",
|
||||
"status.media.open": "اضغط للفتح",
|
||||
"status.media.show": "اضغط لإظهاره",
|
||||
"status.media.show": "اضغط لإظهارها",
|
||||
"status.media_hidden": "وسائط مخفية",
|
||||
"status.mention": "أذكُر @{name}",
|
||||
"status.more": "المزيد",
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
"account.followers": "Siguidores",
|
||||
"account.followers.empty": "Naide sigue a esti perfil.",
|
||||
"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.joined_short": "Data de xunión",
|
||||
"account.link_verified_on": "La propiedá d'esti enllaz comprobóse'l {date}",
|
||||
|
@ -122,6 +122,7 @@
|
|||
"conversation.open": "Ver la conversación",
|
||||
"conversation.with": "Con {names}",
|
||||
"copypaste.copied": "Copióse",
|
||||
"copypaste.copy_to_clipboard": "Copiar nel cartafueyu",
|
||||
"directory.federated": "Del fediversu conocíu",
|
||||
"directory.local": "De «{domain}» namás",
|
||||
"directory.new_arrivals": "Cuentes nueves",
|
||||
|
@ -130,7 +131,7 @@
|
|||
"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.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:",
|
||||
"emoji_button.activity": "Actividá",
|
||||
"emoji_button.flags": "Banderes",
|
||||
|
@ -213,6 +214,7 @@
|
|||
"hashtag.counter_by_accounts": "{count, plural, one {{counter} participante} other {{counter} participantes}}",
|
||||
"hashtag.follow": "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_replies": "Amosar les rempuestes",
|
||||
"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.search": "Enfocar la barra de busca",
|
||||
"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.unfocus": "Desenfocar l'área de composición/busca",
|
||||
"keyboard_shortcuts.up": "Xubir na llista",
|
||||
|
@ -299,6 +301,7 @@
|
|||
"notifications.column_settings.admin.sign_up": "Rexistros nuevos:",
|
||||
"notifications.column_settings.follow": "Siguidores nuevos:",
|
||||
"notifications.column_settings.follow_request": "Solicitúes de siguimientu nueves:",
|
||||
"notifications.column_settings.group": "Agrupar",
|
||||
"notifications.column_settings.mention": "Menciones:",
|
||||
"notifications.column_settings.poll": "Resultaos de les encuestes:",
|
||||
"notifications.column_settings.reblog": "Artículos compartíos:",
|
||||
|
@ -418,11 +421,12 @@
|
|||
"status.direct": "Mentar a @{name} per privao",
|
||||
"status.direct_indicator": "Mención privada",
|
||||
"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.history.created": "{name} creó {date}",
|
||||
"status.history.edited": "{name} editó {date}",
|
||||
"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.more": "Más",
|
||||
"status.mute": "Desactivar los avisos de @{name}",
|
||||
|
@ -468,14 +472,14 @@
|
|||
"upload_modal.applying": "Aplicando…",
|
||||
"upload_modal.detect_text": "Detectar el testu de la semeya",
|
||||
"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.processing": "Procesando…",
|
||||
"video.close": "Zarrar el videu",
|
||||
"video.download": "Baxar el ficheru",
|
||||
"video.expand": "Espander el videu",
|
||||
"video.fullscreen": "Pantalla completa",
|
||||
"video.hide": "Anubrir el videu",
|
||||
"video.hide": "Esconder el videu",
|
||||
"video.mute": "Desactivar el soníu",
|
||||
"video.pause": "Posar",
|
||||
"video.play": "Reproducir",
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
"alert.rate_limited.title": "Ліміт перавышаны",
|
||||
"alert.unexpected.message": "Узнікла нечаканая памылка.",
|
||||
"alert.unexpected.title": "Вой!",
|
||||
"alt_text_badge.title": "Альтернативный текст",
|
||||
"announcement.announcement": "Аб'ява",
|
||||
"attachments_list.unprocessed": "(неапрацаваны)",
|
||||
"audio.hide": "Схаваць аўдыя",
|
||||
|
@ -97,6 +98,8 @@
|
|||
"block_modal.title": "Заблакіраваць карыстальніка?",
|
||||
"block_modal.you_wont_see_mentions": "Вы не ўбачыце паведамленняў са згадваннем карыстальніка.",
|
||||
"boost_modal.combo": "Націсніце {combo}, каб прапусціць наступным разам",
|
||||
"boost_modal.reblog": "Пашырыць допіс?",
|
||||
"boost_modal.undo_reblog": "Прыбраць допіс?",
|
||||
"bundle_column_error.copy_stacktrace": "Скапіраваць справаздачу пра памылку",
|
||||
"bundle_column_error.error.body": "Запытаная старонка не можа быць адлюстраваная. Гэта магло стацца праз хібу ў нашым кодзе, або праз памылку сумяшчальнасці з браўзерам.",
|
||||
"bundle_column_error.error.title": "Халера!",
|
||||
|
@ -194,6 +197,7 @@
|
|||
"confirmations.unfollow.title": "Адпісацца ад карыстальніка?",
|
||||
"content_warning.hide": "Схаваць допіс",
|
||||
"content_warning.show": "Усё адно паказаць",
|
||||
"content_warning.show_more": "Паказаць усё роўна",
|
||||
"conversation.delete": "Выдаліць размову",
|
||||
"conversation.mark_as_read": "Адзначыць прачытаным",
|
||||
"conversation.open": "Прагледзець размову",
|
||||
|
@ -219,6 +223,8 @@
|
|||
"domain_block_modal.they_cant_follow": "Ніхто з гэтага сервера не зможа падпісацца на вас.",
|
||||
"domain_block_modal.they_wont_know": "Карыстальнік не будзе ведаць пра блакіроўку.",
|
||||
"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_pill.activitypub_lets_connect": "Ён дазваляе вам узаемадзейнічаць не толькі з карыстальнікамі Mastodon, але і розных іншых сацыяльных платформ.",
|
||||
"domain_pill.activitypub_like_language": "ActivityPub — гэта мова, на якой Mastodon размаўляе з іншымі сацыяльнымі сеткамі.",
|
||||
|
@ -300,7 +306,7 @@
|
|||
"filter_modal.select_filter.subtitle": "Скарыстайцеся існуючай катэгорыяй або стварыце новую",
|
||||
"filter_modal.select_filter.title": "Фільтраваць гэты допіс",
|
||||
"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.title": "Адфільтраваныя апавяшчэнні",
|
||||
"firehose.all": "Усе",
|
||||
|
@ -350,6 +356,9 @@
|
|||
"hashtag.follow": "Падпісацца на хэштэг",
|
||||
"hashtag.unfollow": "Адпісацца ад хэштэга",
|
||||
"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_replies": "Паказваць адказы",
|
||||
"home.hide_announcements": "Схаваць аб'явы",
|
||||
|
@ -434,6 +443,7 @@
|
|||
"lists.subheading": "Вашыя спісы",
|
||||
"load_pending": "{count, plural, one {# новы элемент} few {# новыя элементы} many {# новых элементаў} other {# новых элементаў}}",
|
||||
"loading_indicator.label": "Загрузка…",
|
||||
"media_gallery.hide": "Схаваць",
|
||||
"moved_to_account_banner.text": "Ваш уліковы запіс {disabledAccount} зараз адключаны таму што вы перанесены на {movedToAccount}.",
|
||||
"mute_modal.hide_from_notifications": "Схаваць з апавяшчэнняў",
|
||||
"mute_modal.hide_options": "Схаваць опцыі",
|
||||
|
@ -479,11 +489,13 @@
|
|||
"notification.favourite": "Ваш допіс упадабаны {name}",
|
||||
"notification.follow": "{name} падпісаўся на вас",
|
||||
"notification.follow_request": "{name} адправіў запыт на падпіску",
|
||||
"notification.follow_request.name_and_others": "{name} і {count, plural, one {# іншы} many {# іншых} other {# іншых}} запыталіся падпісацца на вас",
|
||||
"notification.label.mention": "Згадванне",
|
||||
"notification.label.private_mention": "Асабістае згадванне",
|
||||
"notification.label.private_reply": "Асабісты адказ",
|
||||
"notification.label.reply": "Адказ",
|
||||
"notification.mention": "Згадванне",
|
||||
"notification.mentioned_you": "{name} згадаў вас",
|
||||
"notification.moderation-warning.learn_more": "Даведацца больш",
|
||||
"notification.moderation_warning": "Вы атрымалі папярэджанне аб мадэрацыі",
|
||||
"notification.moderation_warning.action_delete_statuses": "Некаторыя вашыя допісы былі выдаленыя.",
|
||||
|
@ -496,6 +508,7 @@
|
|||
"notification.own_poll": "Ваша апытанне скончылася",
|
||||
"notification.poll": "Апытанне, дзе вы прынялі ўдзел, скончылася",
|
||||
"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.account_suspension": "Адміністратар з {from} прыпыніў працу {target}, што азначае, што вы больш не можаце атрымліваць ад іх абнаўлення ці ўзаемадзейнічаць з імі.",
|
||||
"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.follow": "Новыя падпісчыкі:",
|
||||
"notifications.column_settings.follow_request": "Новыя запыты на падпіску:",
|
||||
"notifications.column_settings.group": "Аб'яднаць апавяшчэнні ад падпісчыкаў",
|
||||
"notifications.column_settings.mention": "Згадванні:",
|
||||
"notifications.column_settings.poll": "Вынікі апытання:",
|
||||
"notifications.column_settings.push": "Push-апавяшчэнні",
|
||||
|
@ -743,6 +757,7 @@
|
|||
"status.edit": "Рэдагаваць",
|
||||
"status.edited": "Апошняе рэдагаванне {date}",
|
||||
"status.edited_x_times": "Рэдагавана {count, plural, one {{count} раз} few {{count} разы} many {{count} разоў} other {{count} разу}}",
|
||||
"status.embed": "Атрымаць убудаваны код",
|
||||
"status.favourite": "Упадабанае",
|
||||
"status.favourites": "{count, plural, one {# упадабанае} few {# упадабаныя} many {# упадабаных} other {# упадабанага}}",
|
||||
"status.filter": "Фільтраваць гэты допіс",
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
"alert.rate_limited.title": "Скоростта е ограничена",
|
||||
"alert.unexpected.message": "Възникна неочаквана грешка.",
|
||||
"alert.unexpected.title": "Опаа!",
|
||||
"alt_text_badge.title": "Алтернативен текст",
|
||||
"announcement.announcement": "Оповестяване",
|
||||
"attachments_list.unprocessed": "(необработено)",
|
||||
"audio.hide": "Скриване на звука",
|
||||
|
@ -157,7 +158,6 @@
|
|||
"compose_form.poll.duration": "Времетраене на анкетата",
|
||||
"compose_form.poll.multiple": "Множествен избор",
|
||||
"compose_form.poll.option_placeholder": "Избор {number}",
|
||||
"compose_form.poll.single": "Подберете нещо",
|
||||
"compose_form.poll.switch_to_multiple": "Промяна на анкетата, за да се позволят множество възможни избора",
|
||||
"compose_form.poll.switch_to_single": "Промяна на анкетата, за да се позволи един възможен избор",
|
||||
"compose_form.poll.type": "Стил",
|
||||
|
@ -489,7 +489,6 @@
|
|||
"notification.favourite": "{name} направи любима публикацията ви",
|
||||
"notification.favourite.name_and_others_with_link": "{name} и <a>{count, plural, one {# друг} other {# други}}</a> направиха любима ваша публикация",
|
||||
"notification.follow": "{name} ви последва",
|
||||
"notification.follow.name_and_others": "{name} и {count, plural, one {# друг} other {# други}} ви последваха",
|
||||
"notification.follow_request": "{name} поиска да ви последва",
|
||||
"notification.follow_request.name_and_others": "{name} и {count, plural, one {# друг} other {# други}} поискаха да ви последват",
|
||||
"notification.label.mention": "Споменаване",
|
||||
|
|
|
@ -145,7 +145,6 @@
|
|||
"compose_form.poll.duration": "Pad ar sontadeg",
|
||||
"compose_form.poll.multiple": "Meur a choaz",
|
||||
"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_single": "Kemmañ ar sontadeg evit aotren un dibab hepken",
|
||||
"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.unfollow.confirm": "Diheuliañ",
|
||||
"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.mark_as_read": "Merkañ evel lennet",
|
||||
"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.title": "Silañ an toud-mañ",
|
||||
"filter_modal.title.status": "Silañ un toud",
|
||||
"filter_warning.matches_filter": "A glot gant ar sil “<span>{title}</span>”",
|
||||
"firehose.all": "Pep tra",
|
||||
"firehose.local": "Ar servijer-mañ",
|
||||
"firehose.remote": "Servijerioù all",
|
||||
|
@ -385,6 +386,7 @@
|
|||
"notification.admin.report": "Disklêriet eo bet {target} gant {name}",
|
||||
"notification.admin.sign_up": "{name} en·he deus lakaet e·hec'h anv",
|
||||
"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.moderation-warning.learn_more": "Gouzout hiroc'h",
|
||||
"notification.own_poll": "Echu eo ho sontadeg",
|
||||
|
@ -399,6 +401,7 @@
|
|||
"notifications.column_settings.favourite": "Muiañ-karet:",
|
||||
"notifications.column_settings.follow": "Heulierien nevez:",
|
||||
"notifications.column_settings.follow_request": "Pedadoù heuliañ nevez :",
|
||||
"notifications.column_settings.group": "Strollañ",
|
||||
"notifications.column_settings.mention": "Menegoù:",
|
||||
"notifications.column_settings.poll": "Disoc'hoù ar sontadeg:",
|
||||
"notifications.column_settings.push": "Kemennoù push",
|
||||
|
|
|
@ -158,7 +158,7 @@
|
|||
"compose_form.poll.duration": "Durada de l'enquesta",
|
||||
"compose_form.poll.multiple": "Opcions múltiples",
|
||||
"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_single": "Canvia l’enquesta per a permetre una única opció",
|
||||
"compose_form.poll.type": "Estil",
|
||||
|
@ -197,6 +197,7 @@
|
|||
"confirmations.unfollow.title": "Deixar de seguir l'usuari?",
|
||||
"content_warning.hide": "Amaga la publicació",
|
||||
"content_warning.show": "Mostra-la igualment",
|
||||
"content_warning.show_more": "Mostra'n més",
|
||||
"conversation.delete": "Elimina la conversa",
|
||||
"conversation.mark_as_read": "Marca com a llegida",
|
||||
"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.title": "Filtra aquest 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.title": "Notificacions filtrades",
|
||||
"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.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.vote": "Si teniu compte a Mastodon, podeu votar aquesta enquesta.",
|
||||
"interaction_modal.login.action": "Torna a l'inici",
|
||||
"interaction_modal.login.prompt": "Domini del teu servidor domèstic, p.ex. mastodon.social",
|
||||
"interaction_modal.no_account_yet": "No a Mastodon?",
|
||||
|
@ -396,6 +398,7 @@
|
|||
"interaction_modal.title.follow": "Segueix {name}",
|
||||
"interaction_modal.title.reblog": "Impulsa el 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.hours": "{number, plural, one {# hora} other {# hores}}",
|
||||
"intervals.full.minutes": "{number, plural, one {# minut} other {# minuts}}",
|
||||
|
@ -508,7 +511,7 @@
|
|||
"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.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_and_others": "{name} i {count, plural, one {# altre} other {# altres}} han demanat de seguir-vos",
|
||||
"notification.label.mention": "Menció",
|
||||
|
@ -516,6 +519,7 @@
|
|||
"notification.label.private_reply": "Resposta en privat",
|
||||
"notification.label.reply": "Resposta",
|
||||
"notification.mention": "Menció",
|
||||
"notification.mentioned_you": "{name} us ha mencionat",
|
||||
"notification.moderation-warning.learn_more": "Per a saber-ne més",
|
||||
"notification.moderation_warning": "Heu rebut un avís de moderació",
|
||||
"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.follow": "Nous seguidors:",
|
||||
"notifications.column_settings.follow_request": "Noves sol·licituds de seguiment:",
|
||||
"notifications.column_settings.group": "Agrupa",
|
||||
"notifications.column_settings.mention": "Mencions:",
|
||||
"notifications.column_settings.poll": "Resultats de l’enquesta:",
|
||||
"notifications.column_settings.push": "Notificacions push",
|
||||
|
@ -852,6 +857,11 @@
|
|||
"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.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.thumbnail": "Canvia la miniatura",
|
||||
"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.multiple": "فرە هەڵبژاردە",
|
||||
"compose_form.poll.option_placeholder": "بژاردەی {number}",
|
||||
"compose_form.poll.single": "یەکێك هەلبژێرە",
|
||||
"compose_form.poll.switch_to_multiple": "ڕاپرسی بگۆڕە بۆ ڕێگەدان بە چەند هەڵبژاردنێک",
|
||||
"compose_form.poll.switch_to_single": "گۆڕینی ڕاپرسی بۆ ڕێگەدان بە تاکە هەڵبژاردنێک",
|
||||
"compose_form.poll.type": "ستایڵ",
|
||||
|
|
|
@ -157,7 +157,6 @@
|
|||
"compose_form.poll.duration": "Doba trvání ankety",
|
||||
"compose_form.poll.multiple": "Výběr z více možností",
|
||||
"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_single": "Povolit u ankety výběr pouze jedné volby",
|
||||
"compose_form.poll.type": "Styl",
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
"about.rules": "Rheolau'r gweinydd",
|
||||
"account.account_note_header": "Nodyn personol",
|
||||
"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.block": "Blocio @{name}",
|
||||
"account.block_domain": "Blocio parth {domain}",
|
||||
|
@ -36,7 +36,7 @@
|
|||
"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.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.go_to_profile": "Mynd i'r proffil",
|
||||
"account.hide_reblogs": "Cuddio hybiau gan @{name}",
|
||||
|
@ -62,7 +62,7 @@
|
|||
"account.requested_follow": "Mae {name} wedi gwneud cais i'ch dilyn",
|
||||
"account.share": "Rhannwch broffil @{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_domain": "Dadflocio parth {domain}",
|
||||
"account.unblock_short": "Dadflocio",
|
||||
|
@ -85,6 +85,7 @@
|
|||
"alert.rate_limited.title": "Cyfradd gyfyngedig",
|
||||
"alert.unexpected.message": "Digwyddodd gwall annisgwyl.",
|
||||
"alert.unexpected.title": "Wps!",
|
||||
"alt_text_badge.title": "Testun Amgen",
|
||||
"announcement.announcement": "Cyhoeddiad",
|
||||
"attachments_list.unprocessed": "(heb eu prosesu)",
|
||||
"audio.hide": "Cuddio sain",
|
||||
|
@ -157,7 +158,7 @@
|
|||
"compose_form.poll.duration": "Cyfnod pleidlais",
|
||||
"compose_form.poll.multiple": "Dewis lluosog",
|
||||
"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_single": "Newid pleidlais i gyfyngu i un dewis",
|
||||
"compose_form.poll.type": "Arddull",
|
||||
|
@ -196,6 +197,7 @@
|
|||
"confirmations.unfollow.title": "Dad-ddilyn defnyddiwr?",
|
||||
"content_warning.hide": "Cuddio'r postiad",
|
||||
"content_warning.show": "Dangos beth bynnag",
|
||||
"content_warning.show_more": "Dangos rhagor",
|
||||
"conversation.delete": "Dileu sgwrs",
|
||||
"conversation.mark_as_read": "Nodi fel wedi'i ddarllen",
|
||||
"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_wont_know": "Fyddan nhw ddim yn gwybod eu bod wedi cael eu blocio.",
|
||||
"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_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.",
|
||||
|
@ -302,8 +306,8 @@
|
|||
"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.title.status": "Hidlo postiad",
|
||||
"filter_warning.matches_filter": "Yn cydweddu'r hidlydd “{title}”",
|
||||
"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",
|
||||
"filter_warning.matches_filter": "Yn cyd-fynd â'r hidlydd “ <span>{title}</span> ”",
|
||||
"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",
|
||||
"firehose.all": "Popeth",
|
||||
"firehose.local": "Gweinydd hwn",
|
||||
|
@ -346,12 +350,12 @@
|
|||
"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_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_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.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.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.",
|
||||
|
@ -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.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.vote": "Gyda chyfrif ar Mastodon, gallwch bleidleisio yn y bleidlais hon.",
|
||||
"interaction_modal.login.action": "Mynd i'm ffrwd gartref",
|
||||
"interaction_modal.login.prompt": "Parth eich gweinydd cartref, e.e. mastodon.social",
|
||||
"interaction_modal.no_account_yet": "Dim ar Mastodon?",
|
||||
|
@ -393,6 +398,7 @@
|
|||
"interaction_modal.title.follow": "Dilyn {name}",
|
||||
"interaction_modal.title.reblog": "Hybu postiad {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.hours": "{number, plural, one {# awr} other {# o oriau}}",
|
||||
"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}.",
|
||||
"link_preview.author": "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.remove": "Tynnu o'r rhestr",
|
||||
"lists.delete": "Dileu rhestr",
|
||||
|
@ -496,23 +502,24 @@
|
|||
"navigation_bar.security": "Diogelwch",
|
||||
"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_account": "{name} reported {count, plural, one {un postiad} other {# postiad}} from {target} for {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": "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 {# postiad} other {# postiad}} gan {target}",
|
||||
"notification.admin.report_statuses": "Adroddodd {name} {target} ar gyfer {category}",
|
||||
"notification.admin.report_statuses_other": "Adroddodd {name} {target}",
|
||||
"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.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.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.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.private_mention": "Crybwyll preifat",
|
||||
"notification.label.private_reply": "Ateb preifat",
|
||||
"notification.label.reply": "Ateb",
|
||||
"notification.mention": "Crybwyll",
|
||||
"notification.mentioned_you": "Rydych wedi'ch crybwyll gan {name}",
|
||||
"notification.moderation-warning.learn_more": "Dysgu mwy",
|
||||
"notification.moderation_warning": "Rydych wedi derbyn rhybudd gan gymedrolwr",
|
||||
"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.poll": "Mae arolwg y gwnaethoch bleidleisio ynddo wedi dod i ben",
|
||||
"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.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.",
|
||||
|
@ -534,9 +541,9 @@
|
|||
"notification.status": "{name} newydd ei bostio",
|
||||
"notification.update": "Golygodd {name} bostiad",
|
||||
"notification_requests.accept": "Derbyn",
|
||||
"notification_requests.accept_multiple": "{count, plural, one {Accept # request…} other {Accept # requests…}}",
|
||||
"notification_requests.confirm_accept_multiple.button": "{count, plural, one {Accept request} other {Accept requests}}",
|
||||
"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.accept_multiple": "{count, plural, one {Derbyn # cais…} other {Derbyn # cais…}}",
|
||||
"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 {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_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?",
|
||||
|
@ -563,6 +570,7 @@
|
|||
"notifications.column_settings.filter_bar.category": "Bar hidlo cyflym",
|
||||
"notifications.column_settings.follow": "Dilynwyr newydd:",
|
||||
"notifications.column_settings.follow_request": "Ceisiadau dilyn newydd:",
|
||||
"notifications.column_settings.group": "Grŵp",
|
||||
"notifications.column_settings.mention": "Crybwylliadau:",
|
||||
"notifications.column_settings.poll": "Canlyniadau pleidlais:",
|
||||
"notifications.column_settings.push": "Hysbysiadau gwthiadwy",
|
||||
|
@ -684,7 +692,7 @@
|
|||
"relative_time.minutes": "{number} munud",
|
||||
"relative_time.seconds": "{number} eiliad",
|
||||
"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.poll": "Arolwg",
|
||||
"report.block": "Blocio",
|
||||
|
@ -727,7 +735,7 @@
|
|||
"report.thanks.title_actionable": "Diolch am adrodd, byddwn yn ymchwilio i hyn.",
|
||||
"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_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_sentence": "cynnwys anghyfreithlon",
|
||||
"report_notification.categories.other": "Arall",
|
||||
|
@ -807,7 +815,7 @@
|
|||
"status.reblog": "Hybu",
|
||||
"status.reblog_private": "Hybu i'r gynulleidfa wreiddiol",
|
||||
"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.redraft": "Dileu ac ailddrafftio",
|
||||
"status.remove_bookmark": "Tynnu nod tudalen",
|
||||
|
@ -849,6 +857,11 @@
|
|||
"upload_error.poll": "Nid oes modd llwytho ffeiliau â phleidleisiau.",
|
||||
"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.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.thumbnail": "Newid llun bach",
|
||||
"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.multiple": "Multivalg",
|
||||
"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_single": "Ændr afstemning til enkeltvalgstype",
|
||||
"compose_form.poll.type": "Stil",
|
||||
|
@ -197,6 +196,7 @@
|
|||
"confirmations.unfollow.title": "Følg ikke længere bruger?",
|
||||
"content_warning.hide": "Skjul indlæg",
|
||||
"content_warning.show": "Vis alligevel",
|
||||
"content_warning.show_more": "Vis flere",
|
||||
"conversation.delete": "Slet samtale",
|
||||
"conversation.mark_as_read": "Markér som læst",
|
||||
"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.title": "Filtrér dette 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.title": "Filtrerede notifikationer",
|
||||
"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.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.vote": "Med en konto på Mastodon kan man deltage i denne afstemning.",
|
||||
"interaction_modal.login.action": "Gå til hjemmeserver",
|
||||
"interaction_modal.login.prompt": "Hjemmeserverdomænet, f.eks. mastodon.social",
|
||||
"interaction_modal.no_account_yet": "Ikke på Mastodon?",
|
||||
|
@ -396,6 +397,7 @@
|
|||
"interaction_modal.title.follow": "Følg {name}",
|
||||
"interaction_modal.title.reblog": "Boost {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.hours": "{number, plural, one {# time} other {# timer}}",
|
||||
"intervals.full.minutes": "{number, plural, one {# minut} other {# minutter}}",
|
||||
|
@ -508,7 +510,7 @@
|
|||
"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.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_and_others": "{name} og {count, plural, one {# anden} other {# andre}} har anmodet om at følger dig",
|
||||
"notification.label.mention": "Omtale",
|
||||
|
@ -516,6 +518,7 @@
|
|||
"notification.label.private_reply": "Privat svar",
|
||||
"notification.label.reply": "Besvar",
|
||||
"notification.mention": "Omtale",
|
||||
"notification.mentioned_you": "{name} nævnte dig",
|
||||
"notification.moderation-warning.learn_more": "Læs mere",
|
||||
"notification.moderation_warning": "Du er tildelt en moderationsadvarsel",
|
||||
"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.follow": "Nye følgere:",
|
||||
"notifications.column_settings.follow_request": "Nye følgeanmodninger:",
|
||||
"notifications.column_settings.group": "Gruppere",
|
||||
"notifications.column_settings.mention": "Omtaler:",
|
||||
"notifications.column_settings.poll": "Afstemningsresultater:",
|
||||
"notifications.column_settings.push": "Push-notifikationer",
|
||||
|
@ -852,6 +856,11 @@
|
|||
"upload_error.poll": "Filupload ikke tilladt for afstemninger.",
|
||||
"upload_form.audio_description": "Beskrivelse til hørehæmmede",
|
||||
"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.thumbnail": "Skift miniature",
|
||||
"upload_form.video_description": "Beskrivelse for hørehæmmede eller synshandicappede personer",
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
"account.go_to_profile": "Profil aufrufen",
|
||||
"account.hide_reblogs": "Geteilte Beiträge von @{name} ausblenden",
|
||||
"account.in_memoriam": "Zum Andenken.",
|
||||
"account.joined_short": "Beigetreten",
|
||||
"account.joined_short": "Mitglied seit",
|
||||
"account.languages": "Ausgewählte Sprachen ändern",
|
||||
"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.",
|
||||
|
@ -197,6 +197,7 @@
|
|||
"confirmations.unfollow.title": "Profil entfolgen?",
|
||||
"content_warning.hide": "Beitrag ausblenden",
|
||||
"content_warning.show": "Trotzdem anzeigen",
|
||||
"content_warning.show_more": "Mehr anzeigen",
|
||||
"conversation.delete": "Unterhaltung löschen",
|
||||
"conversation.mark_as_read": "Als gelesen markieren",
|
||||
"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.server": "Server",
|
||||
"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.username": "Profilname",
|
||||
"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_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_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.",
|
||||
"embed.instructions": "Du kannst diesen Beitrag auf deiner Website einbetten, indem du den nachfolgenden Code kopierst.",
|
||||
"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.title": "Diesen Beitrag filtern",
|
||||
"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.title": "Gefilterte Benachrichtigungen",
|
||||
"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.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.vote": "Mit einem Mastodon-Konto kannst du an dieser Umfrage teilnehmen.",
|
||||
"interaction_modal.login.action": "Zurück zur Startseite",
|
||||
"interaction_modal.login.prompt": "Adresse deines Servers, z. B. mastodon.social",
|
||||
"interaction_modal.no_account_yet": "Nicht auf Mastodon?",
|
||||
|
@ -396,6 +398,7 @@
|
|||
"interaction_modal.title.follow": "Folge {name}",
|
||||
"interaction_modal.title.reblog": "Beitrag von {name} teilen",
|
||||
"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.hours": "{number, plural, one {# Stunde} other {# Stunden}}",
|
||||
"intervals.full.minutes": "{number, plural, one {# Minute} other {# Minuten}}",
|
||||
|
@ -508,7 +511,7 @@
|
|||
"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.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_and_others": "{name} und {count, plural, one {# weitere Person} other {# weitere Personen}} möchten dir folgen",
|
||||
"notification.label.mention": "Erwähnung",
|
||||
|
@ -516,6 +519,7 @@
|
|||
"notification.label.private_reply": "Private Antwort",
|
||||
"notification.label.reply": "Antwort",
|
||||
"notification.mention": "Erwähnung",
|
||||
"notification.mentioned_you": "{name} erwähnte dich",
|
||||
"notification.moderation-warning.learn_more": "Mehr erfahren",
|
||||
"notification.moderation_warning": "Du wurdest von den Moderator*innen verwarnt",
|
||||
"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.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.status": "{name} hat gerade etwas gepostet",
|
||||
"notification.status": "{name} veröffentlichte gerade",
|
||||
"notification.update": "{name} bearbeitete einen Beitrag",
|
||||
"notification_requests.accept": "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.follow": "Neue Follower:",
|
||||
"notifications.column_settings.follow_request": "Neue Follower-Anfragen:",
|
||||
"notifications.column_settings.group": "Gruppieren",
|
||||
"notifications.column_settings.mention": "Erwähnungen:",
|
||||
"notifications.column_settings.poll": "Umfrageergebnisse:",
|
||||
"notifications.column_settings.push": "Push-Benachrichtigungen",
|
||||
|
@ -596,15 +601,15 @@
|
|||
"notifications.policy.filter": "Filtern",
|
||||
"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_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_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_title": "Profilen, die mir nicht folgen",
|
||||
"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_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_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.",
|
||||
|
@ -852,6 +857,11 @@
|
|||
"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.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.thumbnail": "Vorschaubild ändern",
|
||||
"upload_form.video_description": "Beschreibe für Menschen mit einer Hör- oder Sehbehinderung",
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
"alert.rate_limited.title": "Περιορισμός συχνότητας",
|
||||
"alert.unexpected.message": "Προέκυψε απροσδόκητο σφάλμα.",
|
||||
"alert.unexpected.title": "Ουπς!",
|
||||
"alt_text_badge.title": "Εναλλακτικό κείμενο",
|
||||
"announcement.announcement": "Ανακοίνωση",
|
||||
"attachments_list.unprocessed": "(μη επεξεργασμένο)",
|
||||
"audio.hide": "Απόκρυψη αρχείου ήχου",
|
||||
|
@ -157,7 +158,6 @@
|
|||
"compose_form.poll.duration": "Διάρκεια δημοσκόπησης",
|
||||
"compose_form.poll.multiple": "Πολλαπλή επιλογή",
|
||||
"compose_form.poll.option_placeholder": "Επιλογή {number}",
|
||||
"compose_form.poll.single": "Διάλεξε ένα",
|
||||
"compose_form.poll.switch_to_multiple": "Ενημέρωση δημοσκόπησης με πολλαπλές επιλογές",
|
||||
"compose_form.poll.switch_to_single": "Ενημέρωση δημοσκόπησης με μοναδική επιλογή",
|
||||
"compose_form.poll.type": "Στυλ",
|
||||
|
@ -221,6 +221,8 @@
|
|||
"domain_block_modal.they_cant_follow": "Κανείς από αυτόν τον διακομιστή δεν μπορεί να σε ακολουθήσει.",
|
||||
"domain_block_modal.they_wont_know": "Δεν θα ξέρουν ότι έχουν αποκλειστεί.",
|
||||
"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_pill.activitypub_lets_connect": "Σού επιτρέπει να συνδεθείς και να αλληλεπιδράσεις με τους ανθρώπους όχι μόνο στο Mastodon, αλλά και σε διαφορετικές κοινωνικές εφαρμογές.",
|
||||
"domain_pill.activitypub_like_language": "Το ActivityPub είναι σαν τη γλώσσα Mastodon μιλάει με άλλα κοινωνικά δίκτυα.",
|
||||
|
@ -302,7 +304,6 @@
|
|||
"filter_modal.select_filter.subtitle": "Χρησιμοποιήστε μια υπάρχουσα κατηγορία ή δημιουργήστε μια νέα",
|
||||
"filter_modal.select_filter.title": "Φιλτράρισμα αυτής της ανάρτησης",
|
||||
"filter_modal.title.status": "Φιλτράρισμα μιας ανάρτησης",
|
||||
"filter_warning.matches_filter": "Ταιριάζει με το φίλτρο “{title}”",
|
||||
"filtered_notifications_banner.pending_requests": "Από {count, plural, =0 {κανένα} one {ένα άτομο} other {# άτομα}} που μπορεί να ξέρεις",
|
||||
"filtered_notifications_banner.title": "Φιλτραρισμένες ειδοποιήσεις",
|
||||
"firehose.all": "Όλα",
|
||||
|
@ -505,7 +506,6 @@
|
|||
"notification.favourite": "{name} favorited your post\n{name} προτίμησε την ανάρτηση σου",
|
||||
"notification.favourite.name_and_others_with_link": "{name} και <a>{count, plural, one {# ακόμη} other {# ακόμη}}</a> αγάπησαν την ανάρτησή σου",
|
||||
"notification.follow": "Ο/Η {name} σε ακολούθησε",
|
||||
"notification.follow.name_and_others": "{name} και {count, plural, one {# ακόμη} other {# ακόμη}} σε ακολούθησαν",
|
||||
"notification.follow_request": "Ο/H {name} ζήτησε να σε ακολουθήσει",
|
||||
"notification.follow_request.name_and_others": "{name} και {count, plural, one {# άλλος} other {# άλλοι}} ζήτησαν να σε ακολουθήσουν",
|
||||
"notification.label.mention": "Επισήμανση",
|
||||
|
@ -849,6 +849,11 @@
|
|||
"upload_error.poll": "Στις δημοσκοπήσεις δεν επιτρέπεται η μεταφόρτωση αρχείου.",
|
||||
"upload_form.audio_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.thumbnail": "Αλλαγή μικρογραφίας",
|
||||
"upload_form.video_description": "Περιγραφή για άτομα με προβλήματα ακοής ή όρασης",
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue