From e54f927149da9e2f6aebb7701f2f9ece9c4046db Mon Sep 17 00:00:00 2001 From: diondiondion Date: Thu, 21 May 2026 15:41:14 +0200 Subject: [PATCH 01/70] Accessibility: Add skip link & landmark regions to settings (#39129) --- app/javascript/styles/mastodon/admin.scss | 27 +++++++++++++++++++++++ app/views/layouts/admin.html.haml | 5 +++-- config/locales/en.yml | 1 + 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/app/javascript/styles/mastodon/admin.scss b/app/javascript/styles/mastodon/admin.scss index 5ad9576b8f3..887f14360a1 100644 --- a/app/javascript/styles/mastodon/admin.scss +++ b/app/javascript/styles/mastodon/admin.scss @@ -136,6 +136,11 @@ $content-width: 840px; transition: all 100ms linear; transition-property: color, background-color; } + + &:focus-visible { + outline: var(--outline-focus-default); + outline-offset: -2px; + } } ul { @@ -1887,6 +1892,28 @@ a.sparkline { } } +.navigation-skip-link { + position: fixed; + z-index: 100; + margin: 10px; + padding: 10px 16px; + border-radius: 10px; + font-size: 15px; + color: var(--color-text-primary); + background: var(--color-bg-primary); + box-shadow: var(--dropdown-shadow); + + /* Hide visually when not focused */ + &:not(:focus-within) { + width: 1px; + height: 1px; + margin: 0; + padding: 0; + clip-path: inset(50%); + overflow: hidden; + } +} + .section-skip-link { float: right; diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml index 6e49ed90339..039ca88f7e3 100644 --- a/app/views/layouts/admin.html.haml +++ b/app/views/layouts/admin.html.haml @@ -6,8 +6,9 @@ - content_for :body_classes, 'admin' - content_for :content do + %a.navigation-skip-link{ href: '#content' }= t('admin.skip_to_content') .admin-wrapper - .sidebar-wrapper + %nav.sidebar-wrapper .sidebar-wrapper__inner .sidebar = link_to root_path do @@ -24,7 +25,7 @@ = render_navigation - .content-wrapper + %main.content-wrapper#content .content .content__heading - if content_for?(:heading) diff --git a/config/locales/en.yml b/config/locales/en.yml index 41c80e39d09..2ed8dd1c1a7 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -979,6 +979,7 @@ en: site_uploads: delete: Delete uploaded file destroyed_msg: Site upload successfully deleted! + skip_to_content: Skip to content software_updates: critical_update: Critical — please update quickly description: It is recommended to keep your Mastodon installation up to date to benefit from the latest fixes and features. Moreover, it is sometimes critical to update Mastodon in a timely manner to avoid security issues. For these reasons, Mastodon checks for updates every 30 minutes, and will notify you according to your email notification preferences. From e18ca373ebaac162f379346c2fbbfe4d4733cd1a Mon Sep 17 00:00:00 2001 From: David Roetzel Date: Thu, 21 May 2026 15:45:09 +0200 Subject: [PATCH 02/70] Revert "Add partial accounts to collections endpoint (#38919)" (#39128) --- .../api/v1_alpha/collections_controller.rb | 6 +-- app/models/collection.rb | 1 - app/models/collection_item.rb | 9 ---- app/presenters/collections_presenter.rb | 11 ----- ...ctions_with_account_previews_serializer.rb | 10 ---- spec/models/collection_spec.rb | 12 ----- spec/presenters/collections_presenter_spec.rb | 48 ------------------- ...s_with_account_previews_serializer_spec.rb | 45 ----------------- 8 files changed, 2 insertions(+), 140 deletions(-) delete mode 100644 app/presenters/collections_presenter.rb delete mode 100644 app/serializers/rest/collections_with_account_previews_serializer.rb delete mode 100644 spec/presenters/collections_presenter_spec.rb delete mode 100644 spec/serializers/rest/collections_with_account_previews_serializer_spec.rb diff --git a/app/controllers/api/v1_alpha/collections_controller.rb b/app/controllers/api/v1_alpha/collections_controller.rb index 4e15b65ff58..1ca1cd6923f 100644 --- a/app/controllers/api/v1_alpha/collections_controller.rb +++ b/app/controllers/api/v1_alpha/collections_controller.rb @@ -28,10 +28,9 @@ class Api::V1Alpha::CollectionsController < Api::BaseController cache_if_unauthenticated! authorize @account, :index_collections? - presenter = CollectionsPresenter.new(collections: @collections) - render json: presenter, serializer: REST::CollectionsWithAccountPreviewsSerializer + render json: @collections, each_serializer: REST::CollectionSerializer, adapter: :json rescue Mastodon::NotPermittedError - render json: { collections: [], partial_accounts: [] } + render json: { collections: [] } end def show @@ -74,7 +73,6 @@ class Api::V1Alpha::CollectionsController < Api::BaseController def set_collections @collections = @account.collections .with_tag - .preload(top_items: :account) .order(created_at: :desc) .offset(offset_param) .limit(limit_param(DEFAULT_COLLECTIONS_LIMIT)) diff --git a/app/models/collection.rb b/app/models/collection.rb index be4a6ca6c27..c5082269e02 100644 --- a/app/models/collection.rb +++ b/app/models/collection.rb @@ -31,7 +31,6 @@ class Collection < ApplicationRecord has_many :collection_items, dependent: :delete_all has_many :accepted_collection_items, -> { accepted }, class_name: 'CollectionItem', inverse_of: :collection # rubocop:disable Rails/HasManyOrHasOneDependent - has_many :top_items, -> { top_items }, class_name: 'CollectionItem', inverse_of: :collection # rubocop:disable Rails/HasManyOrHasOneDependent has_many :collection_reports, dependent: :delete_all validates :name, presence: true diff --git a/app/models/collection_item.rb b/app/models/collection_item.rb index 7ecb28ddb81..8de27950f1f 100644 --- a/app/models/collection_item.rb +++ b/app/models/collection_item.rb @@ -47,15 +47,6 @@ class CollectionItem < ApplicationRecord scope :local, -> { joins(:collection).merge(Collection.local) } scope :accepted_partial, ->(account) { joins(:account).merge(Account.local).accepted.where(uri: nil, account_id: account.id) } scope :pending_or_accepted, -> { where(state: [:pending, :accepted]) } - scope :top_items, lambda { |limit = 4| - subquery = where('collection_items.collection_id = collections.id') - .accepted.ordered.limit(limit) - .arel.lateral('top_items') - collection_query = Collection - .select('top_items.*') - .from([Collection.arel_table, subquery]) - from(collection_query, 'collection_items') - } def with_local_account? account&.local? diff --git a/app/presenters/collections_presenter.rb b/app/presenters/collections_presenter.rb deleted file mode 100644 index e97d872769d..00000000000 --- a/app/presenters/collections_presenter.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -class CollectionsPresenter < ActiveModelSerializers::Model - attributes :collections - - def accounts - owners = collections.map(&:account) - top_accounts = collections.flat_map { |c| c.top_items.map(&:account) } - (owners + top_accounts).uniq - end -end diff --git a/app/serializers/rest/collections_with_account_previews_serializer.rb b/app/serializers/rest/collections_with_account_previews_serializer.rb deleted file mode 100644 index 95216ea6491..00000000000 --- a/app/serializers/rest/collections_with_account_previews_serializer.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -class REST::CollectionsWithAccountPreviewsSerializer < ActiveModel::Serializer - has_many :collections, serializer: REST::CollectionSerializer - has_many :partial_accounts, serializer: REST::PartialAccountSerializer - - def partial_accounts - object.accounts - end -end diff --git a/spec/models/collection_spec.rb b/spec/models/collection_spec.rb index 0a04473d56b..b9a54536421 100644 --- a/spec/models/collection_spec.rb +++ b/spec/models/collection_spec.rb @@ -199,16 +199,4 @@ RSpec.describe Collection do expect(subject.to_log_permalink).to eq ActivityPub::TagManager.instance.uri_for(subject) end end - - describe '#top_items' do - let(:collection) { Fabricate(:collection) } - - before do - 5.times { |i| Fabricate(:collection_item, collection:, position: i + 1) } - end - - it 'returns the topmost four items' do - expect(collection.top_items.map(&:position)).to contain_exactly(1, 2, 3, 4) - end - end end diff --git a/spec/presenters/collections_presenter_spec.rb b/spec/presenters/collections_presenter_spec.rb deleted file mode 100644 index 72076374815..00000000000 --- a/spec/presenters/collections_presenter_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe CollectionsPresenter do - subject { described_class.new(collections:) } - - let(:collection_owner_one) { Fabricate(:account) } - let(:collection_owner_two) { Fabricate(:account) } - let(:collection_one) do - Fabricate(:collection, - account: collection_owner_one, - name: 'Exquisite follows') - end - let(:collection_two) do - Fabricate(:collection, - account: collection_owner_two, - name: 'Excellent people') - end - let(:collections) { [collection_one, collection_two] } - - describe '#accounts' do - context 'when collections do not have any items' do - it 'includes only the collection owners' do - expect(subject.accounts).to contain_exactly(collection_owner_one, collection_owner_two) - end - end - - context 'when collections include accounts' do - let(:accounts) { Fabricate.times(3, :account) } - - before do - accounts[0..1].each { |a| Fabricate(:collection_item, collection: collection_one, account: a) } - accounts[1..2].each { |a| Fabricate(:collection_item, collection: collection_two, account: a) } - end - - it 'includes collection owners and unique preview accounts' do - expect(subject.accounts).to contain_exactly( - collection_owner_one, - collection_owner_two, - accounts[0], - accounts[1], - accounts[2] - ) - end - end - end -end diff --git a/spec/serializers/rest/collections_with_account_previews_serializer_spec.rb b/spec/serializers/rest/collections_with_account_previews_serializer_spec.rb deleted file mode 100644 index 3d65f6c99d9..00000000000 --- a/spec/serializers/rest/collections_with_account_previews_serializer_spec.rb +++ /dev/null @@ -1,45 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe REST::CollectionsWithAccountPreviewsSerializer do - subject do - serialized_record_json(presenter, described_class, options: { - scope_name: :current_user, scope: nil - }) - end - - let(:collection_owner_one) { Fabricate(:account) } - let(:collection_owner_two) { Fabricate(:account) } - let(:featured_account) { Fabricate(:account) } - let(:collection_one) do - Fabricate(:collection, - account: collection_owner_one, - name: 'Exquisite follows') - end - let(:collection_two) do - Fabricate(:collection, - account: collection_owner_two, - name: 'Excellent people') - end - let(:collections) { [collection_one, collection_two] } - let(:presenter) { CollectionsPresenter.new(collections:) } - - before do - Fabricate(:collection_item, collection: collection_one, account: featured_account) - end - - it 'includes collections and partial accounts with the expected attributes' do - expect(subject).to include({ - 'collections' => [ - a_hash_including({ 'name' => 'Exquisite follows' }), - a_hash_including({ 'name' => 'Excellent people' }), - ], - 'partial_accounts' => [ - a_hash_including({ 'id' => collection_owner_one.id.to_s }), - a_hash_including({ 'id' => collection_owner_two.id.to_s }), - a_hash_including({ 'id' => featured_account.id.to_s }), - ], - }) - end -end From cafe7ea35c0d3dbde2ce2dad22989b8b30a16dca Mon Sep 17 00:00:00 2001 From: Echo Date: Thu, 21 May 2026 15:59:02 +0200 Subject: [PATCH 03/70] Use display name component for empty message (#39131) --- .../account_featured/components/empty_message.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/javascript/mastodon/features/account_featured/components/empty_message.tsx b/app/javascript/mastodon/features/account_featured/components/empty_message.tsx index 19ced4ce23c..aa1dc4078ea 100644 --- a/app/javascript/mastodon/features/account_featured/components/empty_message.tsx +++ b/app/javascript/mastodon/features/account_featured/components/empty_message.tsx @@ -2,14 +2,15 @@ import { useCallback } from 'react'; import { FormattedMessage } from 'react-intl'; -import { useParams } from 'react-router'; import { Link } from 'react-router-dom'; import { openModal } from '@/mastodon/actions/modal'; import { Button } from '@/mastodon/components/button'; +import { DisplayName } from '@/mastodon/components/display_name'; import { EmptyState } from '@/mastodon/components/empty_state'; import { LimitedAccountHint } from '@/mastodon/components/limited_account_hint'; import { areCollectionsEnabled } from '@/mastodon/features/collections/utils'; +import { useAccount } from '@/mastodon/hooks/useAccount'; import { useCurrentAccountId } from '@/mastodon/hooks/useAccountId'; import { useAppDispatch } from '@/mastodon/store'; @@ -28,8 +29,8 @@ export const EmptyMessage: React.FC = ({ blockedBy, withoutAddCollectionButton, }) => { - const { acct } = useParams<{ acct?: string }>(); const me = useCurrentAccountId(); + const account = useAccount(accountId); const dispatch = useAppDispatch(); @@ -116,12 +117,12 @@ export const EmptyMessage: React.FC = ({ /> ); } else { - if (acct) { + if (account) { title = ( }} /> ); } else { From cdf721a273de89e3831c196bb0a1443531ca6a38 Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 21 May 2026 17:46:10 +0200 Subject: [PATCH 04/70] Fix remote statuses with large media descriptions being rejected (#39135) --- app/models/media_attachment.rb | 2 +- spec/lib/activitypub/activity/create_spec.rb | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index ecfaca9de40..1a65a447529 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -205,7 +205,7 @@ class MediaAttachment < ApplicationRecord remotable_attachment :thumbnail, IMAGE_LIMIT, suppress_errors: true, download_on_assign: false validates :account, presence: true - validates :description, length: { maximum: MAX_DESCRIPTION_LENGTH } + validates :description, length: { maximum: MAX_DESCRIPTION_LENGTH }, if: :local? validates :file, presence: true, if: :local? validates :thumbnail, absence: true, if: -> { local? && !audio_or_video? } diff --git a/spec/lib/activitypub/activity/create_spec.rb b/spec/lib/activitypub/activity/create_spec.rb index 8dc6d9d4254..c68e9bd64a7 100644 --- a/spec/lib/activitypub/activity/create_spec.rb +++ b/spec/lib/activitypub/activity/create_spec.rb @@ -608,19 +608,19 @@ RSpec.describe ActivityPub::Activity::Create do type: 'Document', mediaType: 'image/png', url: 'http://example.com/attachment.png', - name: '*' * MediaAttachment::MAX_DESCRIPTION_LENGTH, + name: '*' * (MediaAttachment::MAX_DESCRIPTION_HARD_LENGTH_LIMIT + 5), }, ] ) end - it 'creates status' do + it 'creates status with truncated description' do expect { subject.perform }.to change(sender.statuses, :count).by(1) status = sender.statuses.first expect(status).to_not be_nil - expect(status.media_attachments.map(&:description)).to include('*' * MediaAttachment::MAX_DESCRIPTION_LENGTH) + expect(status.media_attachments.map(&:description)).to include('*' * MediaAttachment::MAX_DESCRIPTION_HARD_LENGTH_LIMIT) end end @@ -632,19 +632,19 @@ RSpec.describe ActivityPub::Activity::Create do type: 'Document', mediaType: 'image/png', url: 'http://example.com/attachment.png', - summary: '*' * MediaAttachment::MAX_DESCRIPTION_LENGTH, + summary: '*' * (MediaAttachment::MAX_DESCRIPTION_HARD_LENGTH_LIMIT + 5), }, ] ) end - it 'creates status' do + it 'creates status with truncated description' do expect { subject.perform }.to change(sender.statuses, :count).by(1) status = sender.statuses.first expect(status).to_not be_nil - expect(status.media_attachments.map(&:description)).to include('*' * MediaAttachment::MAX_DESCRIPTION_LENGTH) + expect(status.media_attachments.map(&:description)).to include('*' * MediaAttachment::MAX_DESCRIPTION_HARD_LENGTH_LIMIT) end end From 15a7507a092073f0056a84c428caba9bdb630c9f Mon Sep 17 00:00:00 2001 From: diondiondion Date: Thu, 21 May 2026 18:55:28 +0200 Subject: [PATCH 05/70] Use radio buttons for emoji style preference (#39126) --- .../preferences/appearance/show.html.haml | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/app/views/settings/preferences/appearance/show.html.haml b/app/views/settings/preferences/appearance/show.html.haml index c024d2d515e..f521fd99b5e 100644 --- a/app/views/settings/preferences/appearance/show.html.haml +++ b/app/views/settings/preferences/appearance/show.html.haml @@ -51,17 +51,16 @@ label_method: ->(contrast) { I18n.t("contrast.#{contrast}", default: contrast) }, wrapper: :with_label, required: false - - .fields-group - = f.simple_fields_for :settings, current_user.settings do |ff| - = ff.input :'web.emoji_style', - collection: user_settings_collection('web.emoji_style'), - include_blank: false, - hint: I18n.t('simple_form.hints.defaults.setting_emoji_style'), - label: I18n.t('simple_form.labels.defaults.setting_emoji_style'), - label_method: ->(emoji_style) { I18n.t("emoji_styles.#{emoji_style}", default: emoji_style) }, - wrapper: :with_label, - required: false + .input.horizontal-options + = ff.input :'web.emoji_style', + as: :radio_buttons, + collection: user_settings_collection('web.emoji_style'), + include_blank: false, + hint: I18n.t('simple_form.hints.defaults.setting_emoji_style'), + label: I18n.t('simple_form.labels.defaults.setting_emoji_style'), + label_method: ->(emoji_style) { I18n.t("emoji_styles.#{emoji_style}", default: emoji_style) }, + wrapper: :with_label, + required: false - unless I18n.locale == :en .flash-message.translation-prompt From c337487111095785147d4d99d635cecc4dfc8887 Mon Sep 17 00:00:00 2001 From: Artemis Tosini Date: Fri, 22 May 2026 08:43:16 +0000 Subject: [PATCH 06/70] Allow HTML `lang` attribute in remote posts (#39114) --- lib/sanitize_ext/sanitize_config.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/sanitize_ext/sanitize_config.rb b/lib/sanitize_ext/sanitize_config.rb index ab166f52a86..f30eec476cc 100644 --- a/lib/sanitize_ext/sanitize_config.rb +++ b/lib/sanitize_ext/sanitize_config.rb @@ -107,6 +107,7 @@ class Sanitize elements: %w(p br span a del s pre blockquote code b strong u i em ul ol li ruby rt rp), attributes: { + :all => %w(lang), 'a' => %w(href rel class translate), 'span' => %w(class translate), 'ol' => %w(start reversed), From efa729c6d402d4fc7261bdacedcdf646775e0f11 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 22 May 2026 11:12:41 +0200 Subject: [PATCH 07/70] New Crowdin Translations (automated) (#39142) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/ar.json | 13 ++++++++++++ app/javascript/mastodon/locales/be.json | 4 ++-- app/javascript/mastodon/locales/cy.json | 2 -- app/javascript/mastodon/locales/da.json | 4 ++-- app/javascript/mastodon/locales/de.json | 8 +++---- app/javascript/mastodon/locales/el.json | 20 +++++++++--------- app/javascript/mastodon/locales/en-GB.json | 2 -- app/javascript/mastodon/locales/es-AR.json | 4 ++-- app/javascript/mastodon/locales/es-MX.json | 4 ++-- app/javascript/mastodon/locales/es.json | 4 ++-- app/javascript/mastodon/locales/et.json | 4 ++-- app/javascript/mastodon/locales/fa.json | 2 -- app/javascript/mastodon/locales/fi.json | 4 ++-- app/javascript/mastodon/locales/fo.json | 2 -- app/javascript/mastodon/locales/fr-CA.json | 4 ++-- app/javascript/mastodon/locales/fr.json | 4 ++-- app/javascript/mastodon/locales/ga.json | 11 ++++++++-- app/javascript/mastodon/locales/gd.json | 2 -- app/javascript/mastodon/locales/gl.json | 2 -- app/javascript/mastodon/locales/he.json | 4 ++-- app/javascript/mastodon/locales/hu.json | 6 ++++-- app/javascript/mastodon/locales/io.json | 2 -- app/javascript/mastodon/locales/is.json | 2 -- app/javascript/mastodon/locales/it.json | 2 -- app/javascript/mastodon/locales/ja.json | 2 -- app/javascript/mastodon/locales/nan-TW.json | 2 -- app/javascript/mastodon/locales/nl.json | 2 -- app/javascript/mastodon/locales/nn.json | 2 -- app/javascript/mastodon/locales/pt-BR.json | 2 -- app/javascript/mastodon/locales/pt-PT.json | 2 -- app/javascript/mastodon/locales/ru.json | 2 -- app/javascript/mastodon/locales/sq.json | 6 ++++-- app/javascript/mastodon/locales/sv.json | 2 -- app/javascript/mastodon/locales/tr.json | 2 -- app/javascript/mastodon/locales/vi.json | 4 ++-- app/javascript/mastodon/locales/zh-CN.json | 6 ++++-- app/javascript/mastodon/locales/zh-TW.json | 4 ++-- config/locales/be.yml | 1 + config/locales/da.yml | 1 + config/locales/de.yml | 1 + config/locales/el.yml | 23 +++++++++++---------- config/locales/es-AR.yml | 1 + config/locales/es-MX.yml | 1 + config/locales/es.yml | 1 + config/locales/et.yml | 1 + config/locales/fi.yml | 1 + config/locales/fr-CA.yml | 1 + config/locales/fr.yml | 1 + config/locales/ga.yml | 1 + config/locales/hu.yml | 1 + config/locales/pt-BR.yml | 1 + config/locales/simple_form.el.yml | 6 +++--- config/locales/sq.yml | 1 + config/locales/vi.yml | 1 + config/locales/zh-CN.yml | 1 + config/locales/zh-TW.yml | 1 + 56 files changed, 104 insertions(+), 96 deletions(-) diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json index 260b7de7412..b35f29e6b0b 100644 --- a/app/javascript/mastodon/locales/ar.json +++ b/app/javascript/mastodon/locales/ar.json @@ -42,6 +42,9 @@ "account.familiar_followers_two": "يتبعه {name1} و {name2}", "account.featured": "معروض", "account.featured.accounts": "ملفات شخصية", + "account.featured.collections": "المجموعات", + "account.featured.new_collection": "مجموعة جديدة", + "account.field_overflow": "عرض المحتوى الكامل", "account.filters.all": "جميع الأنشطة", "account.filters.boosts_toggle": "اعرض المعاد نشرها", "account.filters.posts_boosts": "المنشورات والمعاد نشرها", @@ -66,6 +69,16 @@ "account.go_to_profile": "اذهب إلى الملف الشخصي", "account.hide_reblogs": "إخفاء المعاد نشرها مِن @{name}", "account.in_memoriam": "في الذكرى.", + "account.join_modal.day": "يوم", + "account.join_modal.me": "انضممت إلى {server} في", + "account.join_modal.me_anniversary": "ذكرى سنوية سعيدة! لقد انضممت إلى {server} في", + "account.join_modal.me_today": "إنه يومك الأول على {server}!", + "account.join_modal.other": "انضمّ {name} إلى {server} في", + "account.join_modal.other_today": "إنه اليوم الأول لـ{name} على {server}!", + "account.join_modal.share.celebrate": "مشاركة منشور احتفالي", + "account.join_modal.share.intro": "مشاركة منشور تعريفي", + "account.join_modal.share.welcome": "مشاركة منشور ترحيبي", + "account.join_modal.years": "{number, plural, zero {أقل من سنة} one {سنة واحدة} two {سنتَين} few {سنوات} many {سنة} other {سنة}}", "account.joined_short": "انضم في", "account.languages": "تغيير اللغات المشترَك فيها", "account.last_active": "آخر نشاط", diff --git a/app/javascript/mastodon/locales/be.json b/app/javascript/mastodon/locales/be.json index 12be544aa0d..71cb3a553f1 100644 --- a/app/javascript/mastodon/locales/be.json +++ b/app/javascript/mastodon/locales/be.json @@ -367,8 +367,8 @@ "collection.share_modal.share_via_system": "Падзяліцца ў…", "collection.share_modal.title": "Падзяліцца калекцыяй", "collection.share_modal.title_new": "Падзяліцеся сваёй калекцыяй!", - "collection.share_template_other": "Глядзі, якая класная калекцыя: {link}", - "collection.share_template_own": "Глядзі, у мяне новая калекцыя: {link}", + "collection.share_template_other": "Глядзі, якая класная калекцыя:", + "collection.share_template_own": "Глядзі, у мяне новая калекцыя:", "collections.account_count": "{count, plural,one {# уліковы запіс} few {# уліковыя запісы} other {# уліковых запісаў}}", "collections.accounts.empty_description": "Дадайце да {count} уліковых запісаў", "collections.accounts.empty_editor_title": "У гэтай калекцыі пакуль нікога няма", diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json index 503b5051cd9..2a9a6e723c6 100644 --- a/app/javascript/mastodon/locales/cy.json +++ b/app/javascript/mastodon/locales/cy.json @@ -366,8 +366,6 @@ "collection.share_modal.share_via_system": "Rhannwch i…", "collection.share_modal.title": "Rhannu casgliad", "collection.share_modal.title_new": "Rhannwch eich casgliad newydd!", - "collection.share_template_other": "Edrychwch ar y casgliad trawiadol hwn: {link}", - "collection.share_template_own": "Edrychwch ar fy nghasgliad newydd: {link}", "collections.account_count": "{count, plural, one {# cyfrif} other {# cyfrif}}", "collections.accounts.empty_description": "Ychwanegu hyd at {count} cyfrif", "collections.accounts.empty_editor_title": "Does neb yn y casgliad hwn eto", diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json index 29efa25c18b..93b6dddbf9a 100644 --- a/app/javascript/mastodon/locales/da.json +++ b/app/javascript/mastodon/locales/da.json @@ -367,8 +367,8 @@ "collection.share_modal.share_via_system": "Del med…", "collection.share_modal.title": "Del samling", "collection.share_modal.title_new": "Del din nye samling!", - "collection.share_template_other": "Tjek denne seje samling: {link}", - "collection.share_template_own": "Tjek min nye samling: {link}", + "collection.share_template_other": "Tjek denne seje samling:", + "collection.share_template_own": "Tjek min nye samling:", "collections.account_count": "{count, plural, one {# konto} other {# konti}}", "collections.accounts.empty_description": "Tilføj op til {count} konti", "collections.accounts.empty_editor_title": "Ingen er i denne samling endnu", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index bbc4a182dba..14c4f481717 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -86,7 +86,7 @@ "account.locked_info": "Die Privatsphäre dieses Kontos wurde auf „geschützt“ gesetzt. Die Person bestimmt manuell, wer ihrem Profil folgen darf.", "account.media": "Medien", "account.mention": "@{name} erwähnen", - "account.menu.add_to_collection": "Zur Sammlung hinzufügen …", + "account.menu.add_to_collection": "Einer Sammlung hinzufügen …", "account.menu.add_to_list": "Einer Liste hinzufügen …", "account.menu.block": "Konto blockieren", "account.menu.block_domain": "{domain} blockieren", @@ -367,13 +367,13 @@ "collection.share_modal.share_via_system": "Teilen …", "collection.share_modal.title": "Sammlung teilen", "collection.share_modal.title_new": "Teile deine neue Sammlung!", - "collection.share_template_other": "Seht euch diese coole Sammlung an: {link}", - "collection.share_template_own": "Seht euch meine neue Sammlung an: {link}", + "collection.share_template_other": "Seht euch diese coole Sammlung an:", + "collection.share_template_own": "Seht euch meine neue Sammlung an:", "collections.account_count": "{count, plural, one {# Konto} other {# Konten}}", "collections.accounts.empty_description": "Füge bis zu {count} Konten hinzu", "collections.accounts.empty_editor_title": "Noch befindet sich niemand in dieser Sammlung", "collections.accounts.empty_title": "Diese Sammlung ist leer", - "collections.add_to_collection": "{name} zur Sammlung hinzufügen", + "collections.add_to_collection": "{name} einer Sammlung hinzufügen", "collections.block_collection_owner": "Konto blockieren", "collections.by_account": "von {account_handle}", "collections.collection_description": "Beschreibung", diff --git a/app/javascript/mastodon/locales/el.json b/app/javascript/mastodon/locales/el.json index 2c73499c752..c1d03903203 100644 --- a/app/javascript/mastodon/locales/el.json +++ b/app/javascript/mastodon/locales/el.json @@ -87,7 +87,7 @@ "account.media": "Πολυμέσα", "account.mention": "Επισήμανση @{name}", "account.menu.add_to_collection": "Προσθήκη σε συλλογή…", - "account.menu.add_to_list": "Προσθήκη στη λίστα…", + "account.menu.add_to_list": "Προσθήκη σε λίστα…", "account.menu.block": "Αποκλεισμός λογαριασμού", "account.menu.block_domain": "Αποκλεισμός {domain}", "account.menu.copied": "Αντιγραφή συνδέσμου λογαριασμού στο πρόχειρο", @@ -367,8 +367,8 @@ "collection.share_modal.share_via_system": "Κοινοποίηση σε…", "collection.share_modal.title": "Κοινοποίηση συλλογής", "collection.share_modal.title_new": "Μοιραστείτε τη νέα σας συλλογή!", - "collection.share_template_other": "Δείτε αυτή την ωραία συλλογή: {link}", - "collection.share_template_own": "Δείτε τη νέα μου συλλογή: {link}", + "collection.share_template_other": "Δείτε αυτή την ωραία συλλογή:", + "collection.share_template_own": "Δείτε τη νέα μου συλλογή:", "collections.account_count": "{count, plural, one {# λογαριασμός} other {# λογαριασμοί}}", "collections.accounts.empty_description": "Προσθέστε μέχρι και {count} λογαριασμούς", "collections.accounts.empty_editor_title": "Κανείς δεν είναι ακόμη σε αυτήν τη συλλογή", @@ -992,7 +992,7 @@ "notifications.clear_title": "Εκκαθάριση ειδοποιήσεων;", "notifications.column_settings.admin.report": "Νέες αναφορές:", "notifications.column_settings.admin.sign_up": "Νέες εγγραφές:", - "notifications.column_settings.alert": "Ειδοποιήσεις επιφάνειας εργασίας", + "notifications.column_settings.alert": "Ειδοποιήσεις για υπολογιστή", "notifications.column_settings.favourite": "Αγαπημένα:", "notifications.column_settings.filter_bar.advanced": "Εμφάνιση όλων των κατηγοριών", "notifications.column_settings.filter_bar.category": "Μπάρα γρήγορου φίλτρου", @@ -1020,9 +1020,9 @@ "notifications.grant_permission": "Χορήγηση άδειας.", "notifications.group": "{count} ειδοποιήσεις", "notifications.mark_as_read": "Σήμανε όλες τις ειδοποιήσεις ως αναγνωσμένες", - "notifications.permission_denied": "Οι ειδοποιήσεις στην επιφάνεια εργασίας δεν είναι διαθέσιμες διότι έχει απορριφθεί κάποιο προηγούμενο αίτημα άδειας", - "notifications.permission_denied_alert": "Δεν είναι δυνατή η ενεργοποίηση των ειδοποιήσεων της επιφάνειας εργασίας, καθώς η άδεια του προγράμματος περιήγησης έχει απορριφθεί νωρίτερα", - "notifications.permission_required": "Οι ειδοποιήσεις δεν είναι διαθέσιμες επειδή δεν έχει δοθεί η απαιτούμενη άδεια.", + "notifications.permission_denied": "Οι ειδοποιήσεις για υπολογιστή δεν είναι διαθέσιμες διότι έχει απορριφθεί κάποιο προηγούμενο αίτημα άδειας", + "notifications.permission_denied_alert": "Δεν είναι δυνατή η ενεργοποίηση των ειδοποιήσεων για υπολογιστή, καθώς η άδεια του προγράμματος περιήγησης έχει απορριφθεί προηγουμένων", + "notifications.permission_required": "Οι ειδοποιήσεις για υπολογιστή δεν είναι διαθέσιμες επειδή δεν έχει δοθεί η απαιτούμενη άδεια.", "notifications.policy.accept": "Αποδοχή", "notifications.policy.accept_hint": "Εμφάνιση στις ειδοποιήσεις", "notifications.policy.drop": "Αγνόηση", @@ -1040,8 +1040,8 @@ "notifications.policy.filter_private_mentions_hint": "Φιλτράρισμα εκτός αν είναι απάντηση σε δική σου επισήμανση ή αν ακολουθείς τον αποστολέα", "notifications.policy.filter_private_mentions_title": "Μη συναινετικές ιδιωτικές επισημάνσεις", "notifications.policy.title": "Διαχείριση ειδοποιήσεων από…", - "notifications_permission_banner.enable": "Ενεργοποίηση ειδοποιήσεων επιφάνειας εργασίας", - "notifications_permission_banner.how_to_control": "Για να λαμβάνεις ειδοποιήσεις όταν το Mastodon δεν είναι ανοιχτό, ενεργοποίησε τις ειδοποιήσεις επιφάνειας εργασίας. Μπορείς να ελέγξεις με ακρίβεια ποιοι τύποι αλληλεπιδράσεων δημιουργούν ειδοποιήσεις επιφάνειας εργασίας μέσω του κουμπιού {icon} μόλις ενεργοποιηθούν.", + "notifications_permission_banner.enable": "Ενεργοποίηση ειδοποιήσεων για υπολογιστή", + "notifications_permission_banner.how_to_control": "Για να λαμβάνεις ειδοποιήσεις όταν το Mastodon δεν είναι ανοιχτό, ενεργοποίησε τις ειδοποιήσεις για υπολογιστή. Μπορείς να ελέγξεις με ακρίβεια ποιοι τύποι αλληλεπιδράσεων δημιουργούν ειδοποιήσεις για υπολογιστή μέσω του κουμπιού {icon} μόλις ενεργοποιηθούν.", "notifications_permission_banner.title": "Μη χάσεις στιγμή", "onboarding.follows.back": "Πίσω", "onboarding.follows.empty": "Δυστυχώς, δεν μπορούν να εμφανιστούν αποτελέσματα αυτή τη στιγμή. Μπορείς να προσπαθήσεις να χρησιμοποιήσεις την αναζήτηση ή να περιηγηθείς στη σελίδα εξερεύνησης για να βρεις άτομα να ακολουθήσεις ή να δοκιμάσεις ξανά αργότερα.", @@ -1298,7 +1298,7 @@ "status.uncached_media_warning": "Μη διαθέσιμη προεπισκόπηση", "status.unmute_conversation": "Άρση σίγασης συνομιλίας", "status.unpin": "Ξεκαρφίτσωσε από το προφίλ", - "subscribed_languages.lead": "Μόνο αναρτήσεις σε επιλεγμένες γλώσσες θα εμφανίζονται στην αρχική σου και θα παραθέτονται ροές μετά την αλλαγή. Επέλεξε καμία για να λαμβάνεις αναρτήσεις σε όλες τις γλώσσες.", + "subscribed_languages.lead": "Μόνο αναρτήσεις στις επιλεγμένες γλώσσες θα εμφανίζονται στην αρχική σου και στις ροές λίστας μετά την αλλαγή. Επέλεξε καμία για να λαμβάνεις αναρτήσεις σε όλες τις γλώσσες.", "subscribed_languages.save": "Αποθήκευση αλλαγών", "subscribed_languages.target": "Αλλαγή εγγεγραμμένων γλωσσών για {target}", "tabs_bar.home": "Αρχική", diff --git a/app/javascript/mastodon/locales/en-GB.json b/app/javascript/mastodon/locales/en-GB.json index 0e40b4c0a94..04146f847fe 100644 --- a/app/javascript/mastodon/locales/en-GB.json +++ b/app/javascript/mastodon/locales/en-GB.json @@ -366,8 +366,6 @@ "collection.share_modal.share_via_system": "Share to…", "collection.share_modal.title": "Share collection", "collection.share_modal.title_new": "Share your new collection!", - "collection.share_template_other": "Check out this cool collection: {link}", - "collection.share_template_own": "Check out my new collection: {link}", "collections.account_count": "{count, plural, one {# account} other {# accounts}}", "collections.accounts.empty_description": "Add up to {count} accounts", "collections.accounts.empty_editor_title": "No one is in this collection yet", diff --git a/app/javascript/mastodon/locales/es-AR.json b/app/javascript/mastodon/locales/es-AR.json index 736adcbb456..fddee1f6d41 100644 --- a/app/javascript/mastodon/locales/es-AR.json +++ b/app/javascript/mastodon/locales/es-AR.json @@ -367,8 +367,8 @@ "collection.share_modal.share_via_system": "Compartir en…", "collection.share_modal.title": "Compartir colección", "collection.share_modal.title_new": "¡Compartí tu nueva colección!", - "collection.share_template_other": "¡Mirá qué copada está esta colección! {link}", - "collection.share_template_own": "Mirá mi nueva colección: {link}", + "collection.share_template_other": "Fijate qué copada es esta colección:", + "collection.share_template_own": "Revisá mi nueva colección:", "collections.account_count": "{count, plural, one {# hora} other {# horas}}", "collections.accounts.empty_description": "Agregá hasta {count} cuentas", "collections.accounts.empty_editor_title": "Todavía no hay nadie en esta colección", diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json index 12f16c56d30..6714d97b23f 100644 --- a/app/javascript/mastodon/locales/es-MX.json +++ b/app/javascript/mastodon/locales/es-MX.json @@ -367,8 +367,8 @@ "collection.share_modal.share_via_system": "Compartir con…", "collection.share_modal.title": "Compartir la colección", "collection.share_modal.title_new": "¡Comparte tu nueva colección!", - "collection.share_template_other": "Echa un vistazo a esta increíble colección: {link}", - "collection.share_template_own": "Echa un vistazo a mi nueva colección: {link}", + "collection.share_template_other": "Mira esta colección tan chula:", + "collection.share_template_own": "Mira mi nueva colección:", "collections.account_count": "{count, plural,one {# cuenta} other {# cuentas}}", "collections.accounts.empty_description": "Añade hasta {count} cuentas", "collections.accounts.empty_editor_title": "No hay nadie en esta colección todavía", diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json index 6667690f90d..283da08a4fc 100644 --- a/app/javascript/mastodon/locales/es.json +++ b/app/javascript/mastodon/locales/es.json @@ -367,8 +367,8 @@ "collection.share_modal.share_via_system": "Compartir con…", "collection.share_modal.title": "Compartir la colección", "collection.share_modal.title_new": "¡Comparte tu nueva colección!", - "collection.share_template_other": "Echa un vistazo a esta fantástica colección: {link}", - "collection.share_template_own": "Echa un vistazo a mi nueva colección: {link}", + "collection.share_template_other": "Mira esta colección tan chula:", + "collection.share_template_own": "Mira mi nueva colección:", "collections.account_count": "{count, plural, one {# cuenta} other {# cuentas}}", "collections.accounts.empty_description": "Añade hasta {count} cuentas", "collections.accounts.empty_editor_title": "No hay nadie en esta colección todavía", diff --git a/app/javascript/mastodon/locales/et.json b/app/javascript/mastodon/locales/et.json index 0a88daf3f01..959cdcba599 100644 --- a/app/javascript/mastodon/locales/et.json +++ b/app/javascript/mastodon/locales/et.json @@ -367,8 +367,8 @@ "collection.share_modal.share_via_system": "Jaga kohas…", "collection.share_modal.title": "Jaga kogumikku", "collection.share_modal.title_new": "Jaga oma uut kogumikku!", - "collection.share_template_other": "Vaata seda lahedat kogumikku: {link}", - "collection.share_template_own": "Vaata mu uut kogumikku: {link}", + "collection.share_template_other": "Vaata seda lahedat kogumikku:", + "collection.share_template_own": "Vaata minu uut kogumikku:", "collections.account_count": "{count, plural, one {# kasutajakonto} other {# kasutajakontot}}", "collections.accounts.empty_description": "Lisa kuni {count} kasutajakontot", "collections.accounts.empty_editor_title": "Selles kogumikus pole veel kedagi", diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json index 482ea05165c..3310a494957 100644 --- a/app/javascript/mastodon/locales/fa.json +++ b/app/javascript/mastodon/locales/fa.json @@ -366,8 +366,6 @@ "collection.share_modal.share_via_system": "هم‌رسانی در…", "collection.share_modal.title": "هم‌رسانی مجموعه", "collection.share_modal.title_new": "هم‌رسانی مجموعهٔ جدیدتان!", - "collection.share_template_other": "این مجموعهٔ باحال رو ببینید: {link}", - "collection.share_template_own": "مجموعهٔ جدیدم رو ببینید: {link}", "collections.account_count": "{count, plural, one {# حساب} other {# حساب}}", "collections.accounts.empty_description": "افزودن تا {count} حساب", "collections.accounts.empty_editor_title": "هنوز کسی در این مجموعه نیست", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index 5194e5d35b9..de639481624 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -367,8 +367,8 @@ "collection.share_modal.share_via_system": "Jaa kohteeseen…", "collection.share_modal.title": "Jaa kokoelma", "collection.share_modal.title_new": "Jaa uusi kokoelmasi!", - "collection.share_template_other": "Katso tämä siisti kokoelma: {link}", - "collection.share_template_own": "Katso uusi kokoelmani: {link}", + "collection.share_template_other": "Katso tämä siisti kokoelma:", + "collection.share_template_own": "Katso uusi kokoelmani:", "collections.account_count": "{count, plural, one {# tili} other {# tiliä}}", "collections.accounts.empty_description": "Lisää enintään {count} tiliä", "collections.accounts.empty_editor_title": "Kukaan ei ole vielä tässä kokoelmassa", diff --git a/app/javascript/mastodon/locales/fo.json b/app/javascript/mastodon/locales/fo.json index bd03f205e73..8268e443546 100644 --- a/app/javascript/mastodon/locales/fo.json +++ b/app/javascript/mastodon/locales/fo.json @@ -265,8 +265,6 @@ "collection.share_modal.share_via_system": "Deil til…", "collection.share_modal.title": "Deil savn", "collection.share_modal.title_new": "Deil títt nýggja savn!", - "collection.share_template_other": "Hygg at hesum kula savninum: {link}", - "collection.share_template_own": "Hygg at mínum nýggja savni: {link}", "collections.account_count": "{count, plural, one {# konta} other {# kontur}}", "collections.accounts.empty_title": "Hetta savnið er tómt", "collections.collection_description": "Lýsing", diff --git a/app/javascript/mastodon/locales/fr-CA.json b/app/javascript/mastodon/locales/fr-CA.json index bfefd1e0909..a2969fe6f85 100644 --- a/app/javascript/mastodon/locales/fr-CA.json +++ b/app/javascript/mastodon/locales/fr-CA.json @@ -367,8 +367,8 @@ "collection.share_modal.share_via_system": "Partager avec…", "collection.share_modal.title": "Partager la collection", "collection.share_modal.title_new": "Partager votre nouvelle collection !", - "collection.share_template_other": "Découvrez cette collection incroyable : {link}", - "collection.share_template_own": "Découvrez ma nouvelle collection : {link}", + "collection.share_template_other": "Découvrez cette collection incroyable :", + "collection.share_template_own": "Découvrez ma nouvelle collection :", "collections.account_count": "{count, plural, one {# compte} other {# comptes}}", "collections.accounts.empty_description": "Ajoutez jusqu'à {count} comptes", "collections.accounts.empty_editor_title": "Il n'y a personne dans cette collection", diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index cd628234e08..9fa31894202 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -367,8 +367,8 @@ "collection.share_modal.share_via_system": "Partager avec…", "collection.share_modal.title": "Partager la collection", "collection.share_modal.title_new": "Partager votre nouvelle collection !", - "collection.share_template_other": "Découvrez cette collection incroyable : {link}", - "collection.share_template_own": "Découvrez ma nouvelle collection : {link}", + "collection.share_template_other": "Découvrez cette collection incroyable :", + "collection.share_template_own": "Découvrez ma nouvelle collection :", "collections.account_count": "{count, plural, one {# compte} other {# comptes}}", "collections.accounts.empty_description": "Ajoutez jusqu'à {count} comptes", "collections.accounts.empty_editor_title": "Il n'y a personne dans cette collection", diff --git a/app/javascript/mastodon/locales/ga.json b/app/javascript/mastodon/locales/ga.json index a337394d34e..81ab906c87c 100644 --- a/app/javascript/mastodon/locales/ga.json +++ b/app/javascript/mastodon/locales/ga.json @@ -86,6 +86,7 @@ "account.locked_info": "Tá an socrú príobháideachais don cuntas seo curtha go 'faoi ghlas'. Déanann an t-úinéir léirmheas ar cén daoine atá ceadaithe an cuntas leanúint.", "account.media": "Meáin", "account.mention": "Luaigh @{name}", + "account.menu.add_to_collection": "Cuir leis an mbailiúchán…", "account.menu.add_to_list": "Cuir leis an liosta…", "account.menu.block": "Cuntas blocáilte", "account.menu.block_domain": "Blocáil {domain}", @@ -366,12 +367,11 @@ "collection.share_modal.share_via_system": "Comhroinn le…", "collection.share_modal.title": "Comhroinn bailiúchán", "collection.share_modal.title_new": "Roinn do bhailiúchán nua!", - "collection.share_template_other": "Féach ar an mbailiúchán fionnuar seo: {link}", - "collection.share_template_own": "Féach ar mo bhailiúchán nua: {link}", "collections.account_count": "{count, plural, one {# cuntas} two {# cuntais} few {# cuntais} many {# cuntais} other {# cuntais}}", "collections.accounts.empty_description": "Cuir suas le {count} cuntas leis", "collections.accounts.empty_editor_title": "Níl aon duine sa bhailiúchán seo fós", "collections.accounts.empty_title": "Tá an bailiúchán seo folamh", + "collections.add_to_collection": "Cuir {name} le bailiúcháin", "collections.block_collection_owner": "Cuntas blocáilte", "collections.by_account": "le {account_handle}", "collections.collection_description": "Cur síos", @@ -394,6 +394,7 @@ "collections.detail.loading": "Ag lódáil an bhailiúcháin…", "collections.detail.revoke_inclusion": "Bain mé", "collections.detail.sensitive_content": "Ábhar íogair", + "collections.detail.sensitive_note": "B’fhéidir nach mbeidh an cur síos agus na cuntais oiriúnach do gach lucht féachana.", "collections.detail.share": "Comhroinn an bailiúchán seo", "collections.detail.you_are_in_this_collection": "Tá tú le feiceáil sa bhailiúchán seo", "collections.edit_details": "Cuir sonraí in eagar", @@ -424,6 +425,11 @@ "collections.search_accounts_max_reached": "Tá an líon uasta cuntas curtha leis agat", "collections.sensitive": "Íogair", "collections.share_short": "Comhroinn", + "collections.sort_alphabetical": "Aibítre", + "collections.sort_by": "Sórtáil de réir:", + "collections.sort_date_added": "Dáta curtha leis", + "collections.sort_last_active": "Gníomhach deireanach", + "collections.sort_most_followers": "An chuid is mó leanúna", "collections.suggestions.can_not_add": "Ní féidir a chur leis", "collections.suggestions.can_not_add_desc": "B’fhéidir gur roghnaigh na cuntais seo gan a bheith san fhionnachtain, nó b’fhéidir go bhfuil siad ar fhreastalaí nach dtacaíonn le bailiúcháin.", "collections.suggestions.must_follow": "Ní mór leanúint ar dtús", @@ -635,6 +641,7 @@ "empty_column.blocks": "Níl aon úsáideoir bactha agat fós.", "empty_column.bookmarked_statuses": "Níl aon phostáil leabharmharcaithe agat fós. Nuair a dhéanann tú leabharmharc, beidh sé le feiceáil anseo.", "empty_column.collections.featured_in": "Níor cuireadh le haon bhailiúchán thú go fóill.", + "empty_column.collections.featured_in_undiscoverable": "Chun go mbeidh daoine in ann tú a chur le bailiúcháin, ní mór duit cead a thabhairt duit a bheith le feiceáil i dtaithí fionnachtana ó Sainroghanna > Príobháideacht agus raon feidhme", "empty_column.community": "Tá an amlíne áitiúil folamh. Foilsigh rud éigin go poiblí le tús a chur le cúrsaí!", "empty_column.direct": "Níl aon tagairtí príobháideacha agat fós. Nuair a sheolann tú nó a gheobhaidh tú ceann, beidh sé le feiceáil anseo.", "empty_column.disabled_feed": "Tá an fotha seo díchumasaithe ag riarthóirí do fhreastalaí.", diff --git a/app/javascript/mastodon/locales/gd.json b/app/javascript/mastodon/locales/gd.json index 5616c5fb602..d240a15ea59 100644 --- a/app/javascript/mastodon/locales/gd.json +++ b/app/javascript/mastodon/locales/gd.json @@ -361,8 +361,6 @@ "collection.share_modal.share_via_system": "Co-roinn gu…", "collection.share_modal.title": "Co-roinn an cruinneachadh", "collection.share_modal.title_new": "Co-roinn an cruinneachadh ùr agad!", - "collection.share_template_other": "Thoir sùil air an deagh-chruinneachadh seo: {link}", - "collection.share_template_own": "Thoir sùil air a’ chruinneachadh ùr agam: {link}", "collections.account_count": "{count, plural, one {# chunntas} two {# chunntas} few {# cunntasan} other {# cunntas}}", "collections.accounts.empty_editor_title": "Chan eil neach sam bith sa chruinneachadh seo fhathast", "collections.accounts.empty_title": "Tha an an cruinneachadh seo falamh", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 0e85b5c9dd8..216a6d1d1e2 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -367,8 +367,6 @@ "collection.share_modal.share_via_system": "Compartir con…", "collection.share_modal.title": "Compartir colección", "collection.share_modal.title_new": "Comparte a túa nova colección!", - "collection.share_template_other": "Mira que colección máis boa: {link}", - "collection.share_template_own": "Mira a miña nova colección: {link}", "collections.account_count": "{count, plural, one {# conta} other {# contas}}", "collections.accounts.empty_description": "Engade ate {count} contas", "collections.accounts.empty_editor_title": "Aínda non hai ninguén nesta colección", diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json index c6f95cfade8..af6e2cbdbc5 100644 --- a/app/javascript/mastodon/locales/he.json +++ b/app/javascript/mastodon/locales/he.json @@ -86,6 +86,7 @@ "account.locked_info": "החשבון הזה הוגדר כנעול. צריך לקבל אישור כדי לעקוב אחריו.", "account.media": "מדיה", "account.mention": "אזכור של @{name}", + "account.menu.add_to_collection": "הוספה לאוסף…", "account.menu.add_to_list": "הוספה לרשימה…", "account.menu.block": "חסימת חשבון", "account.menu.block_domain": "חסימת {domain}", @@ -366,12 +367,11 @@ "collection.share_modal.share_via_system": "לשתף אל…", "collection.share_modal.title": "שיתוף אוסף", "collection.share_modal.title_new": "שתפו את האוסף החדש שלכם!", - "collection.share_template_other": "הציצו על האוסף המעניין הזה: {link}", - "collection.share_template_own": "הציצו על האוסף החדש שלי: {link}", "collections.account_count": "{count, plural, one {חשבון אחד} other {# חשבונות}}", "collections.accounts.empty_description": "להוסיף עד ל־{count} חשבונות", "collections.accounts.empty_editor_title": "אוסף זה ריק כרגע", "collections.accounts.empty_title": "האוסף הזה ריק", + "collections.add_to_collection": "להוסיף את {name} לאוספים", "collections.block_collection_owner": "חסימת חשבון", "collections.by_account": "מאת {account_handle}", "collections.collection_description": "תיאור", diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index b4702e384c3..5f421e7fde8 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -86,6 +86,7 @@ "account.locked_info": "Ennek a fióknak zárolt a láthatósága. A tulajdonos kézzel engedélyezi, hogy ki követheti őt.", "account.media": "Média", "account.mention": "@{name} említése", + "account.menu.add_to_collection": "Hozzáadás gyűjteményhez…", "account.menu.add_to_list": "Hozzáadás listához…", "account.menu.block": "Fiók letiltása", "account.menu.block_domain": "{domain} letiltása", @@ -366,12 +367,13 @@ "collection.share_modal.share_via_system": "Megosztás…", "collection.share_modal.title": "Gyűjtemény megosztása", "collection.share_modal.title_new": "Oszd meg az új gyűjteményedet!", - "collection.share_template_other": "Nézd meg ezt a gyűjteményt: {link}", - "collection.share_template_own": "Nézd meg az új gyűjteményemet: {link}", + "collection.share_template_other": "Nézd meg ezt a gyűjteményt:", + "collection.share_template_own": "Nézd meg az új gyűjteményemet:", "collections.account_count": "{count, plural, one {# fiók} other {# fiók}}", "collections.accounts.empty_description": "Adj hozzá legfeljebb {count} fiókot", "collections.accounts.empty_editor_title": "Még senki sincs ebben a gyűjteményben", "collections.accounts.empty_title": "Ez a gyűjtemény üres", + "collections.add_to_collection": "{name} hozzáadása gyűjteményekhez", "collections.block_collection_owner": "Fiók letiltása", "collections.by_account": "szerző: {account_handle}", "collections.collection_description": "Leírás", diff --git a/app/javascript/mastodon/locales/io.json b/app/javascript/mastodon/locales/io.json index c287c202792..5c318f09b4d 100644 --- a/app/javascript/mastodon/locales/io.json +++ b/app/javascript/mastodon/locales/io.json @@ -199,8 +199,6 @@ "collection.share_modal.share_via_system": "Kunhavigez ad…", "collection.share_modal.title": "Kunhavigez kolektajo", "collection.share_modal.title_new": "Kunhavigez vua nova kolektajo!", - "collection.share_template_other": "Videz ca splendida kolektajo: {link}", - "collection.share_template_own": "Videz mia nova kolektajo: {link}", "collections.content_warning": "Kontenajaverto", "collections.create.accounts_title": "Quan vu estalos en ca kolektajo?", "collections.detail.share": "Kunhavigez ca kolektajo", diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json index 0923724f9e0..2ffafd985b0 100644 --- a/app/javascript/mastodon/locales/is.json +++ b/app/javascript/mastodon/locales/is.json @@ -366,8 +366,6 @@ "collection.share_modal.share_via_system": "Deila með…", "collection.share_modal.title": "Deila safni", "collection.share_modal.title_new": "Deildu nýja safninu þínu!", - "collection.share_template_other": "Kíktu á þetta áhugaverða safn: {link}", - "collection.share_template_own": "Kíktu á nýja safnið mitt: {link}", "collections.account_count": "{count, plural, one {# aðgangur} other {# aðgangar}}", "collections.accounts.empty_description": "Bættu við allt að {count} aðgöngum", "collections.accounts.empty_editor_title": "Enginn er enn í þessu safni", diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json index 7372fdf4d7f..9364e9bafb2 100644 --- a/app/javascript/mastodon/locales/it.json +++ b/app/javascript/mastodon/locales/it.json @@ -367,8 +367,6 @@ "collection.share_modal.share_via_system": "Condividi con…", "collection.share_modal.title": "Condividi la collezione", "collection.share_modal.title_new": "Condividi la tua nuova collezione!", - "collection.share_template_other": "Dai un'occhiata a questa fantastica collezione: {link}", - "collection.share_template_own": "Dai un'occhiata alla mia collezione: {link}", "collections.account_count": "{count, plural, one {# account} other {# account}}", "collections.accounts.empty_description": "Aggiungi fino a {count} account", "collections.accounts.empty_editor_title": "Nessuno è ancora in questa collezione", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index b8f10e5a764..f8d67407b2b 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -181,8 +181,6 @@ "collection.share_modal.share_via_system": "共有…", "collection.share_modal.title": "コレクションを共有", "collection.share_modal.title_new": "新しいコレクションを共有しよう!", - "collection.share_template_other": "この素敵なコレクションを見てみてください: {link}", - "collection.share_template_own": "私の新しいコレクションを見てみてください: {link}", "collections.accounts.empty_title": "このコレクションは空です", "collections.by_account": "{account_handle} による", "collections.collection_description": "詳細", diff --git a/app/javascript/mastodon/locales/nan-TW.json b/app/javascript/mastodon/locales/nan-TW.json index 0da1f615d32..450e9312883 100644 --- a/app/javascript/mastodon/locales/nan-TW.json +++ b/app/javascript/mastodon/locales/nan-TW.json @@ -366,8 +366,6 @@ "collection.share_modal.share_via_system": "分享kàu……", "collection.share_modal.title": "分享收藏", "collection.share_modal.title_new": "分享lí ê新收藏!", - "collection.share_template_other": "緊看覓chit ê時行ê收藏:{link}", - "collection.share_template_own": "緊看覓我ê收藏:{link}", "collections.account_count": "{count, plural, other {# ê口座}}", "collections.accounts.empty_description": "加上tsē {count} ê口座", "collections.accounts.empty_editor_title": "Tsit ê 收藏內底iáu無半ê lâng", diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index 3bb32635b25..0c2a59a19c8 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -367,8 +367,6 @@ "collection.share_modal.share_via_system": "Delen met…", "collection.share_modal.title": "Verzameling delen", "collection.share_modal.title_new": "Je nieuwe verzameling delen!", - "collection.share_template_other": "Bekijk deze coole verzameling: {link}", - "collection.share_template_own": "Bekijk mijn nieuwe verzameling: {link}", "collections.account_count": "{count, plural, one {# account} other {# accounts}}", "collections.accounts.empty_description": "Tot {count} accounts toevoegen", "collections.accounts.empty_editor_title": "Er is nog nog niemand in deze verzameling", diff --git a/app/javascript/mastodon/locales/nn.json b/app/javascript/mastodon/locales/nn.json index 09b8eb1e9fd..d90d4d48d53 100644 --- a/app/javascript/mastodon/locales/nn.json +++ b/app/javascript/mastodon/locales/nn.json @@ -361,8 +361,6 @@ "collection.share_modal.share_via_system": "Del med…", "collection.share_modal.title": "Del ei samling", "collection.share_modal.title_new": "Del den nye samlinga di!", - "collection.share_template_other": "Sjekk denne samlinga: {link}", - "collection.share_template_own": "Sjekk den nye samlinga mi: {link}", "collections.account_count": "{count, plural, one {# konto} other {# kontoar}}", "collections.accounts.empty_title": "Denne samlinga er tom", "collections.by_account": "av {account_handle}", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index 61baa453145..e6e97aea183 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -367,8 +367,6 @@ "collection.share_modal.share_via_system": "Enviar para…", "collection.share_modal.title": "Compartilhar coleção", "collection.share_modal.title_new": "Compartilhe sua nova coleção!", - "collection.share_template_other": "Confira esta coleção incrível: {link}", - "collection.share_template_own": "Confira minha nova coleção: {link}", "collections.account_count": "{count, plural, one {# conta} other {# conta}}", "collections.accounts.empty_description": "Adicione até {count} contas", "collections.accounts.empty_editor_title": "Ainda não há ninguém nesta coleção", diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json index b74440dbb7f..7ca9401f9ac 100644 --- a/app/javascript/mastodon/locales/pt-PT.json +++ b/app/javascript/mastodon/locales/pt-PT.json @@ -345,8 +345,6 @@ "collection.share_modal.share_via_system": "Compartilhar com…", "collection.share_modal.title": "Partilhar coleção", "collection.share_modal.title_new": "Partilhe a sua nova coleção!", - "collection.share_template_other": "Veja esta coleção interessante: {link}", - "collection.share_template_own": "Veja a minha nova coleção: {link}", "collections.account_count": "{count, plural, one {# conta} other {# contas}}", "collections.accounts.empty_description": "Adicione até {count} contas", "collections.accounts.empty_editor_title": "Ainda não há ninguém nesta coleção", diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json index dc57dc7d4df..edd0f8f6177 100644 --- a/app/javascript/mastodon/locales/ru.json +++ b/app/javascript/mastodon/locales/ru.json @@ -342,8 +342,6 @@ "collection.share_modal.share_via_system": "Поделиться…", "collection.share_modal.title": "Поделиться подборкой", "collection.share_modal.title_new": "Поделитесь вашей новой подборкой!", - "collection.share_template_other": "Зацените эту замечательную подборку: {link}", - "collection.share_template_own": "Зацените мою новую подборку: {link}", "collections.account_count": "{count, plural, one {# пользователь} few {# пользователя} other {# пользователей}}", "collections.accounts.empty_description": "Вы можете добавить максимум {count} пользователей", "collections.accounts.empty_editor_title": "В этой подборке пока никого нет", diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json index 2cbed2a77ee..6e11e0e94ec 100644 --- a/app/javascript/mastodon/locales/sq.json +++ b/app/javascript/mastodon/locales/sq.json @@ -86,6 +86,7 @@ "account.locked_info": "Gjendja e privatësisë së kësaj llogarie është caktuar si e kyçur. I zoti merr dorazi në shqyrtim cilët mund ta ndjekin.", "account.media": "Media", "account.mention": "Përmendni @{name}", + "account.menu.add_to_collection": "Shtoni në koleksion…", "account.menu.add_to_list": "Shtoni në listë…", "account.menu.block": "Bllokoje llogarinë", "account.menu.block_domain": "Bllokoje {domain}", @@ -361,12 +362,13 @@ "collection.share_modal.share_via_system": "Ndajeni me të tjerë në…", "collection.share_modal.title": "Ndani koleksionin me të tjerë", "collection.share_modal.title_new": "Ndani me të tjerë koleksionin tuaj të ri!", - "collection.share_template_other": "Shihni këtë koleksion të hijshëm: {link}", - "collection.share_template_own": "Shihni koleksionin tim të ri: {link}", + "collection.share_template_other": "Shihni këtë koleksion të hijshëm:", + "collection.share_template_own": "Shihni koleksionin tim të ri:", "collections.account_count": "{count, plural, one {# llogari} other {# llogari}}", "collections.accounts.empty_description": "Shtoni deri në {count} llogari", "collections.accounts.empty_editor_title": "Në këtë koleksion s’ka ende njeri", "collections.accounts.empty_title": "Ky koleksion është i zbrazët", + "collections.add_to_collection": "Shtoje {name} te koleksione", "collections.block_collection_owner": "Bllokoje llogarinë", "collections.by_account": "nga {account_handle}", "collections.collection_description": "Përshkrim", diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json index 8e4b006dbe9..10a037a9c68 100644 --- a/app/javascript/mastodon/locales/sv.json +++ b/app/javascript/mastodon/locales/sv.json @@ -366,8 +366,6 @@ "collection.share_modal.share_via_system": "Dela med…", "collection.share_modal.title": "Dela samling", "collection.share_modal.title_new": "Dela din nya samling!", - "collection.share_template_other": "Kolla in denna coola samling: {link}", - "collection.share_template_own": "Kolla in min nya samling: {link}", "collections.account_count": "{count, plural, one {# konto} other {# konton}}", "collections.accounts.empty_description": "Lägg till upp till {count} konton", "collections.accounts.empty_editor_title": "Ingen finns i denna samling ännu", diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json index a2b81e269d9..e7930a84f97 100644 --- a/app/javascript/mastodon/locales/tr.json +++ b/app/javascript/mastodon/locales/tr.json @@ -367,8 +367,6 @@ "collection.share_modal.share_via_system": "Paylaş…", "collection.share_modal.title": "Koleksiyonu paylaş", "collection.share_modal.title_new": "Yeni koleksiyonunuzu paylaşın!", - "collection.share_template_other": "Bu harika koleksiyona göz atın: {link}", - "collection.share_template_own": "Yeni koleksiyonuma göz atın: {link}", "collections.account_count": "{count, plural, one {# hesap} other {# hesap}}", "collections.accounts.empty_description": "{count} hesap ekleyebilirsiniz", "collections.accounts.empty_editor_title": "Koleksiyonda henüz kimse yok", diff --git a/app/javascript/mastodon/locales/vi.json b/app/javascript/mastodon/locales/vi.json index 344b4d6835e..5dccafb2af9 100644 --- a/app/javascript/mastodon/locales/vi.json +++ b/app/javascript/mastodon/locales/vi.json @@ -367,8 +367,8 @@ "collection.share_modal.share_via_system": "Chia sẻ qua…", "collection.share_modal.title": "Chia sẻ gói khởi đầu", "collection.share_modal.title_new": "Chia sẻ gói khởi đầu mới của bạn!", - "collection.share_template_other": "Xem ngay gói khởi đầu tuyệt vời này: {link}", - "collection.share_template_own": "Xem ngay gói khởi đầu mới của tôi: {link}", + "collection.share_template_other": "Xem ngay gói khởi đầu tuyệt vời này:", + "collection.share_template_own": "Xem ngay gói khởi đầu mới của tôi:", "collections.account_count": "{count, plural, other {# tài khoản}}", "collections.accounts.empty_description": "Thêm tối đa {count} tài khoản", "collections.accounts.empty_editor_title": "Chưa có ai trong gói khởi đầu này", diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json index 1162db4e94e..03237b2cbe1 100644 --- a/app/javascript/mastodon/locales/zh-CN.json +++ b/app/javascript/mastodon/locales/zh-CN.json @@ -86,6 +86,7 @@ "account.locked_info": "此账号已锁嘟。账号所有人会手动审核新关注者。", "account.media": "媒体", "account.mention": "提及 @{name}", + "account.menu.add_to_collection": "加入收藏列表…", "account.menu.add_to_list": "添加到列表…", "account.menu.block": "屏蔽账号", "account.menu.block_domain": "屏蔽 {domain}", @@ -366,12 +367,13 @@ "collection.share_modal.share_via_system": "分享到…", "collection.share_modal.title": "分享收藏列表", "collection.share_modal.title_new": "分享你的新收藏列表!", - "collection.share_template_other": "发现了个收藏列表,来看看:{link}", - "collection.share_template_own": "我的新收藏列表,来看看:{link}", + "collection.share_template_other": "发现了个收藏列表,来看看:", + "collection.share_template_own": "我的新收藏列表,来看看:", "collections.account_count": "{count, plural, other {# 个账号}}", "collections.accounts.empty_description": "添加最多 {count} 个账号", "collections.accounts.empty_editor_title": "此收藏列表中暂无用户", "collections.accounts.empty_title": "收藏列表为空", + "collections.add_to_collection": "将 {name} 添加到收藏列表", "collections.block_collection_owner": "屏蔽账号", "collections.by_account": "由 {account_handle}", "collections.collection_description": "说明", diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index 26d254e5ad5..8295c699917 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -367,8 +367,8 @@ "collection.share_modal.share_via_system": "分享至...", "collection.share_modal.title": "分享收藏名單", "collection.share_modal.title_new": "分享您的新收藏名單!", - "collection.share_template_other": "來看看這個酷酷的收藏名單:{link}", - "collection.share_template_own": "來看看我的新收藏名單:{link}", + "collection.share_template_other": "來看看這個酷酷的收藏名單:", + "collection.share_template_own": "來看看我的新收藏名單:", "collections.account_count": "{count, plural, other {# 個帳號}}", "collections.accounts.empty_description": "加入最多 {count} 個帳號", "collections.accounts.empty_editor_title": "此收藏名單尚未有任何人", diff --git a/config/locales/be.yml b/config/locales/be.yml index 2290e50f817..244857c6dd5 100644 --- a/config/locales/be.yml +++ b/config/locales/be.yml @@ -1011,6 +1011,7 @@ be: site_uploads: delete: Выдаліць запампаваны файл destroyed_msg: Загрузка сайту паспяхова выдалена! + skip_to_content: Перайсці да змесціва software_updates: critical_update: Крытычна - зрабіце абнаўленне як мага хутчэй description: Рэкамендуецца падтрымліваць усталёўку Mastodon у актуальным стане, каб карыстацца апошнімі выпраўленнямі і магчымасцямі. Акрамя таго, часам вельмі важна своечасова абнаўляць Mastodon, каб пазбегнуць праблем з бяспекай. Па гэтых прычынах Mastodon правярае наяўнасць абнаўленняў кожныя 30 хвілін і паведамляе вам пра гэта ў адпаведнасці з вашымі наладамі апавяшчэнняў па электроннай пошце. diff --git a/config/locales/da.yml b/config/locales/da.yml index fe4cc0bba04..8bbc546ad6d 100644 --- a/config/locales/da.yml +++ b/config/locales/da.yml @@ -979,6 +979,7 @@ da: site_uploads: delete: Slet uploadet fil destroyed_msg: Websteds-upload blev slettet! + skip_to_content: Gå til indhold software_updates: critical_update: Kritisk – opdatér hurtigst muligt description: Det anbefales at holde din Mastodon-installation opdateret for at drage fordel af de nyeste fejlrettelser og funktioner. Desuden er det nogle gange afgørende at opdatere Mastodon rettidigt for at undgå sikkerhedsproblemer. Af disse grunde tjekker Mastodon for opdateringer hvert 30. minut og giver dig besked i henhold til dine præferencer for e-mail-notifikationer. diff --git a/config/locales/de.yml b/config/locales/de.yml index f9346bfa794..4d20c155286 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -979,6 +979,7 @@ de: site_uploads: delete: Hochgeladene Datei löschen destroyed_msg: Upload erfolgreich gelöscht! + skip_to_content: Zum Inhalt wechseln software_updates: critical_update: Kritisch — bitte zügig aktualisieren description: Es wird empfohlen, deine Mastodon-Installation auf dem aktuellen Stand zu halten, um von den neuesten Fehlerkorrekturen und Funktionen zu profitieren. Darüber hinaus ist es wichtig, Mastodon zeitnah zu aktualisieren, um Sicherheitslücken zu schließen. Aus diesen Gründen prüft Mastodon alle 30 Minuten auf Updates und du wirst deinen Einstellungen entsprechend per E-Mail informiert. diff --git a/config/locales/el.yml b/config/locales/el.yml index af7b3e7daf7..ce46ac37a78 100644 --- a/config/locales/el.yml +++ b/config/locales/el.yml @@ -279,10 +279,10 @@ el: destroy_unavailable_domain_html: Ο/Η %{name} ξανάρχισε να τροφοδοτεί το domain %{target} destroy_user_role_html: Ο/Η %{name} διέγραψε τον ρόλο του %{target} destroy_username_block_html: "%{name} αφαίρεσε κανόνα για ονόματα χρηστών που περιέχουν %{target}" - disable_2fa_user_html: Ο/Η %{name} απενεργοποίησε την απαίτηση για ταυτοποίηση δύο παραγόντων για τον χρήστη %{target} + disable_2fa_user_html: Ο/Η %{name} απενεργοποίησε την απαίτηση για πιστοποίηση δύο παραγόντων για τον χρήστη %{target} disable_custom_emoji_html: Ο/Η %{name} απενεργοποίησε το emoji %{target} disable_relay_html: Ο χρήστης %{name} απενεργοποίησε το relay %{target} - disable_sign_in_token_auth_user_html: Ο χρήστης %{name} απενεργοποίησε την ταυτοποίηση χαρακτηριστικού μέσω e-mail για %{target} + disable_sign_in_token_auth_user_html: Ο/Η %{name} απενεργοποίησε την πιστοποίηση διακριτικού μέσω email για τον χρήστη %{target} disable_user_html: Ο/Η %{name} απενεργοποίησε τη σύνδεση για τον χρήστη %{target} enable_custom_emoji_html: Ο/Η %{name} ενεργοποίησε το emoji %{target} enable_relay_html: Ο χρήστης %{name} ενεργοποίησε το relay %{target} @@ -883,7 +883,7 @@ el: manage_taxonomies: Διαχείριση Ταξινομιών manage_taxonomies_description: Επιτρέπει στους χρήστες να εξετάζουν το δημοφιλές περιεχόμενο και να ενημερώνουν τις ρυθμίσεις ετικέτας manage_user_access: Διαχείριση Πρόσβασης Χρήστη - manage_user_access_description: Επιτρέπει στους χρήστες να απενεργοποιούν την ταυτοποίηση δύο παραγόντων άλλων χρηστών, να αλλάξουν τη διεύθυνση ηλεκτρονικού ταχυδρομείου τους και να επαναφέρουν τον κωδικό πρόσβασής τους + manage_user_access_description: Επιτρέπει στους χρήστες να απενεργοποιούν την πιστοποίηση δύο παραγόντων άλλων χρηστών, να αλλάξουν τη διεύθυνση ηλεκτρονικού ταχυδρομείου τους και να επαναφέρουν τον κωδικό πρόσβασής τους manage_users: Διαχείριση Χρηστών manage_users_description: Επιτρέπει στους χρήστες να βλέπουν τις λεπτομέρειες άλλων χρηστών και να εκτελούν ενέργειες συντονισμού εναντίον τους manage_webhooks: Διαχείριση Webhooks @@ -974,11 +974,12 @@ el: authorized_fetch: Απαίτηση ταυτόποιησης από διακομιστές σε ομοσπονδία authorized_fetch_hint: Η απαίτηση ελέγχου ταυτότητας από ομοσπονδιακούς διακομιστές επιτρέπει την αυστηρότερη επιβολή αποκλεισμού τόσο σε επίπεδο χρήστη όσο και σε επίπεδο διακομιστή. Ωστόσο, αυτό έχει το κόστος στην απόδοσης μειώνει την εμβέλεια των απαντήσεών σας και μπορεί να δημιουργήσει προβλήματα συμβατότητας με ορισμένες ομοσπονδιακές υπηρεσίες. Επιπλέον, αυτό δεν θα εμποδίσει τους αφοσιωμένους ηθοποιούς να ανακτήσουν τις δημόσιες αναρτήσεις και τους λογαριασμούς σας. authorized_fetch_overridden_hint: Προς το παρόν, δε μπορείς να αλλάξεις αυτή την ρύθμιση επειδή παρακάμπτεται από μια μεταβλητή περιβάλλοντος. - federation_authentication: Επιβολή ομοσπονδιακής ταυτοποίησης + federation_authentication: Επιβολή ομοσπονδιακής πιστοποίησης title: Ρυθμίσεις διακομιστή site_uploads: delete: Διαγραφή μεταφορτωμένου αρχείου destroyed_msg: Η μεταφόρτωση ιστότοπου διαγράφηκε επιτυχώς! + skip_to_content: Μετάβαση στο περιεχόμενο software_updates: critical_update: Κρίσιμο - παρακαλώ ενημέρωσε γρήγορα description: Συνιστάται να διατηρείς την εγκατάσταση του Mastodon ενημερωμένη για να επωφεληθείς από τις πιο πρόσφατες διορθώσεις και δυνατότητες. Επιπλέον, μερικές φορές είναι κρίσιμο να ενημερώσεις το Mastodon εγκαίρως για να αποφύγεις προβλήματα ασφαλείας. Για αυτούς τους λόγους, το Mastodon ελέγχει για ενημερώσεις κάθε 30 λεπτά και θα σε ειδοποιεί σύμφωνα με τις προτιμήσεις ειδοποίησης μέσω email. @@ -1347,7 +1348,7 @@ el: dont_have_your_security_key: Δεν έχεις κλειδί ασφαλείας; forgot_password: Ξέχασες το συνθηματικό σου; invalid_reset_password_token: Το διακριτικό επαναφοράς συνθηματικού είναι άκυρο ή ληγμένο. Παρακαλώ αιτήσου νέο. - link_to_otp: Γράψε τον κωδικό ταυτοποίησης 2 παραγόντων από το τηλέφωνό σου ή τον κωδικό επαναφοράς + link_to_otp: Γράψε τον κωδικό πιστοποίησης δύο παραγόντων από το τηλέφωνό σου ή τον κωδικό επαναφοράς link_to_webauth: Χρήση συσκευής κλειδιού ασφαλείας log_in_with: Σύνδεση με login: Σύνδεση @@ -1752,7 +1753,7 @@ el: limit: Έχεις φτάσει το μέγιστο αριθμό λιστών login_activities: authentication_methods: - otp: εφαρμογή ταυτοποίησης δύο παραγόντων + otp: εφαρμογή πιστοποίησης δύο παραγόντων password: συνθηματικό sign_in_token: κωδικός ασφαλείας email webauthn: κλειδιά ασφαλείας @@ -1887,7 +1888,7 @@ el: trillion: Τρις otp_authentication: code_hint: Για να συνεχίσεις, γράψε τον κωδικό που δημιούργησε η εφαρμογή πιστοποίησης - description_html: Αν ενεργοποιήσεις την ταυτοποίηση δύο παραγόντων χρησιμοποιώντας εφαρμογή ταυτοποίησης, για να συνδεθείς θα πρέπει να έχεις το τηλέφωνό σου, που θα σου δημιουργήσει κλειδιά εισόδου για να τα εισάγεις. + description_html: Αν ενεργοποιήσεις την πιστοποίηση δύο παραγόντων χρησιμοποιώντας εφαρμογή πιστοποίησης, για να συνδεθείς θα πρέπει να έχεις το τηλέφωνό σου, που θα σου δημιουργήσει κλειδιά εισόδου για να τα εισάγεις. enable: Ενεργοποίηση instructions_html: "Σάρωσε αυτόν τον κωδικό QR με την εφαρμογή Google Authenticator ή κάποια άλλη αντίστοιχη στο τηλέφωνό σου. Από εδώ και στο εξής, η εφαρμογή θα δημιουργεί κλειδιά που θα πρέπει να εισάγεις όταν συνδέεσαι." manual_instructions: 'Αν δεν μπορείς να σαρώσεις τον κωδικό QR και χρειάζεσαι να τον εισάγεις χειροκίνητα, ορίστε η μυστική φράση σε μορφή κειμένου:' @@ -2170,7 +2171,7 @@ el: two_factor_authentication: add: Προσθήκη disable: Απενεργοποίηση 2FA - disabled_success: Η ταυτοποίηση δύο παραγόντων απενεργοποιήθηκε επιτυχώς + disabled_success: Η πιστοποίηση δύο παραγόντων απενεργοποιήθηκε επιτυχώς edit: Επεξεργασία enabled: Η πιστοποίηση 2 παραγόντων είναι ενεργοποιημένη enabled_success: Η πιστοποίηση 2 παραγόντων ενεργοποιήθηκε επιτυχώς @@ -2231,13 +2232,13 @@ el: details: 'Εδώ είναι οι λεπτομέρειες της προσπάθειας σύνδεσης:' explanation: Κάποιος έχει προσπαθήσει να εισέλθει στον λογαριασμό σου, αλλά παρείχε έναν μη έγκυρο δεύτερο παράγοντα ελέγχου ταυτότητας. further_actions_html: Αν δεν ήσουν εσύ, σου συνιστούμε να %{action} αμέσως, καθώς μπορεί να έχει εκτεθεί. - subject: Αποτυχία ταυτοποίησης δεύτερου παράγοντα + subject: Αποτυχία πιστοποίησης δεύτερου παράγοντα title: Αποτυχία ελέγχου ταυτότητας δεύτερου παράγοντα suspicious_sign_in: change_password: άλλαξε τον κωδικό πρόσβασής σου details: 'Εδώ είναι οι λεπτομέρειες της σύνδεσης:' explanation: Εντοπίσαμε μια σύνδεση στο λογαριασμό σου από μια νέα διεύθυνση IP. - further_actions_html: Αν δεν ήσουν εσύ, σας συνιστούμε να %{action} αμέσως και να ενεργοποιήσεις τον έλεγχο ταυτοποίησης δύο παραγόντων για να διατηρήσεις τον λογαριασμό σου ασφαλή. + further_actions_html: Αν δεν ήσουν εσύ, σου συνιστούμε να %{action} αμέσως και να ενεργοποιήσεις την πιστοποίηση δύο παραγόντων για να διατηρήσεις τον λογαριασμό σου ασφαλή. subject: Ο λογαριασμός σου έχει συνδεθεί από μια νέα διεύθυνση IP title: Μια νέα σύνδεση terms_of_service_changed: @@ -2352,7 +2353,7 @@ el: nickname_hint: Βάλε το ψευδώνυμο του νέου κλειδιού ασφαλείας σου not_enabled: Δεν έχεις ενεργοποιήσει το WebAuthn ακόμη not_supported: Αυτό το πρόγραμμα περιήγησης δεν υποστηρίζει κλειδιά ασφαλείας - otp_required: Για να χρησιμοποιήσεις κλειδιά ασφαλείας, ενεργοποίησε πρώτα την ταυτοποίηση δύο παραγόντων. + otp_required: Για να χρησιμοποιήσεις κλειδιά ασφαλείας, ενεργοποίησε πρώτα την πιστοποίηση δύο παραγόντων. registered_on: Εγγραφή στις %{date} wrapstodon: description: Δείτε πώς ο/η %{name} χρησιμοποίησε το Mastodon φέτος! diff --git a/config/locales/es-AR.yml b/config/locales/es-AR.yml index 4602a66e727..e8838d5e2c0 100644 --- a/config/locales/es-AR.yml +++ b/config/locales/es-AR.yml @@ -979,6 +979,7 @@ es-AR: site_uploads: delete: Eliminar archivo subido destroyed_msg: "¡Subida al sitio eliminada exitosamente!" + skip_to_content: Saltar al contenido software_updates: critical_update: Crítica — por favor, actualizá cuanto antes description: Se recomienda mantener actualizada tu instalación de Mastodon para beneficiarte de las últimas correcciones y funciones. Además, a veces es crítico actualizar Mastodon inmediatamente para evitar problemas de seguridad. Por estas razones, Mastodon comprueba si hay actualizaciones cada 30 minutos, y te notificará de acuerdo a tu configuración de notificaciones por correo electrónico. diff --git a/config/locales/es-MX.yml b/config/locales/es-MX.yml index 726169afda1..e7e3a1d0f7d 100644 --- a/config/locales/es-MX.yml +++ b/config/locales/es-MX.yml @@ -979,6 +979,7 @@ es-MX: site_uploads: delete: Eliminar archivo subido destroyed_msg: "¡Carga del sitio eliminada con éxito!" + skip_to_content: Ir al contenido software_updates: critical_update: Crítico — por favor actualiza rápidamente description: Se recomienda mantener tu instalación de Mastodon actualizada para beneficiarte de las últimas correcciones y características. Además, a veces es crítico actualizar Mastodon a tiempo para evitar problemas de seguridad. Por estas razones, Mastodon busca actualizaciones cada 30 minutos, y le notificará de acuerdo a sus preferencias de notificación por correo electrónico. diff --git a/config/locales/es.yml b/config/locales/es.yml index 46a3e87fd80..c234628964f 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -979,6 +979,7 @@ es: site_uploads: delete: Eliminar archivo subido destroyed_msg: "¡Carga del sitio eliminada con éxito!" + skip_to_content: Ir al contenido software_updates: critical_update: Crítica— por favor actualiza rápidamente description: Se recomienda mantener actualizada tu instalación de Mastodon para beneficiarte de las últimas correcciones y características. Además, a veces es crítico actualizar Mastodon de manera oportuna para evitar problemas de seguridad. Por estas razones, Mastodon comprueba si hay actualizaciones cada 30 minutos, y te notificará de acuerdo a tus preferencias de notificación por correo electrónico. diff --git a/config/locales/et.yml b/config/locales/et.yml index eec699edc59..5c20dd2f6eb 100644 --- a/config/locales/et.yml +++ b/config/locales/et.yml @@ -979,6 +979,7 @@ et: site_uploads: delete: Kustuta üleslaetud fail destroyed_msg: Üleslaetud fail edukalt kustutatud! + skip_to_content: Hüppa sisuni software_updates: critical_update: Kriitiline — uuenda kiiresti description: Soovitatav on hoida oma Mastodoni paigaldus ajakohasena, et saada kasu viimastest parandustest ja funktsioonidest. Lisaks sellele on mõnikord oluline Mastodoni õigeaegne uuendamine, et vältida turvaprobleeme. Neil põhjustel kontrollib Mastodon uuendusi iga 30 minuti järel ja teavitab vastavalt sinu e-posti teavitamise eelistustele. diff --git a/config/locales/fi.yml b/config/locales/fi.yml index c8026caaac6..2f4ecc5bcdc 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -971,6 +971,7 @@ fi: site_uploads: delete: Poista lähetetty tiedosto destroyed_msg: Sivustolatauksen poisto onnistui! + skip_to_content: Siirry sisältöön software_updates: critical_update: Kriittinen – päivitä viivyttelemättä description: On suositeltavaa pitää Mastodon-asennus ajantasaisena ja siten hyödyntää uusimpia korjauksia sekä ominaisuuksia. Lisäksi joskus on ratkaisevan tärkeää päivittää Mastodon ajoissa tietoturvaongelmien välttämiseksi. Näistä syistä Mastodon tarkistaa päivitykset 30 minuutin välein, ja ilmoittaa sinulle sähköposti-ilmoitusasetustesi mukaisesti. diff --git a/config/locales/fr-CA.yml b/config/locales/fr-CA.yml index 32a14bd4504..11791c5d9d4 100644 --- a/config/locales/fr-CA.yml +++ b/config/locales/fr-CA.yml @@ -979,6 +979,7 @@ fr-CA: site_uploads: delete: Supprimer le fichier téléversé destroyed_msg: Téléversement sur le site supprimé avec succès ! + skip_to_content: Accéder au contenu software_updates: critical_update: Critique — veuillez mettre à jour au plus vite description: Il est recommandé de maintenir votre installation de Mastodon à jour afin de bénéficier des derniers correctifs et fonctionnalités. Par ailleurs, il est parfois critique de mettre à jour Mastodon rapidement de manière à éviter les incidents relatifs à la sécurité. Pour ces raisons, Mastodon examine la disponibilté des mises à jour toutes les 30 minutes, et vous en avisera en fonction de vos préférences de notification par courriel. diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 432026b1738..5e88e2d1c1c 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -979,6 +979,7 @@ fr: site_uploads: delete: Supprimer le fichier téléversé destroyed_msg: Téléversement sur le site supprimé avec succès ! + skip_to_content: Accéder au contenu software_updates: critical_update: Critique — veuillez mettre à jour au plus vite description: Il est recommandé de maintenir votre installation de Mastodon à jour afin de bénéficier des derniers correctifs et fonctionnalités. Par ailleurs, il est parfois critique de mettre à jour Mastodon rapidement de manière à éviter les incidents relatifs à la sécurité. Pour ces raisons, Mastodon examine la disponibilté des mises à jour toutes les 30 minutes, et vous en avisera en fonction de vos préférences de notification par courriel. diff --git a/config/locales/ga.yml b/config/locales/ga.yml index 0dec8d025c7..7b3eb3c13cb 100644 --- a/config/locales/ga.yml +++ b/config/locales/ga.yml @@ -361,6 +361,7 @@ ga: back_to_report: Ar ais chuig leathanach na tuarascála batch: add_to_report: 'Cuir le tuarascáil #%{id}' + remove_from_report: Bain den tuarascáil report: Tuairisc collection_title: Bailiúchán le %{name} contents: Ábhar diff --git a/config/locales/hu.yml b/config/locales/hu.yml index 12e824d1bcd..6f12ea2f225 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -979,6 +979,7 @@ hu: site_uploads: delete: Feltöltött fájl törlése destroyed_msg: Sikeresen töröltük a site feltöltését! + skip_to_content: Ugrás a tartalomhoz software_updates: critical_update: Kritikus - frissíts gyorsan description: Javasolt, hogy a Mastodon telepítésed naprakész legyen, hogy kihasználhasd a legújabb javításokat és funkciókat. Ezenkívül néha különösen fontos a Mastodon időben történő frissítése a biztonsági problémák elkerülése érdekében. Ezen okok miatt a Mastodon 30 percenként ellenőrzi a frissítéseket és az e-mail-értesítési beállításoknak megfelelően értesítést küld. diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 72ee7abda6a..e9cddeac988 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -979,6 +979,7 @@ pt-BR: site_uploads: delete: Excluir arquivo enviado destroyed_msg: Upload do site excluído com sucesso! + skip_to_content: Pular para o conteúdo software_updates: critical_update: Crítico — por favor, atualize rapidamente description: É recomendável que você mantenha a instalação do Mastodon atualizada para se beneficiar das correções e das novas funcionalidades. Além disso, às vezes é imprescindível atualizar o Mastodon rapidamente para evitar problemas de segurança. Por esses motivos, o Mastodon verifica se há atualizações a cada 30 minutos e notificará você de acordo com as suas preferências de notificação por e-mail. diff --git a/config/locales/simple_form.el.yml b/config/locales/simple_form.el.yml index 1ccd054a33f..346b9e320f8 100644 --- a/config/locales/simple_form.el.yml +++ b/config/locales/simple_form.el.yml @@ -66,7 +66,7 @@ el: setting_display_media_show_all: Εμφάνιση όλων των πολυμέσων χωρίς προειδοποίηση, συμπεριλαμβανομένων των πολυμέσων που σημαίνονται ως ευαίσθητα setting_emoji_style: Πώς να εμφανίσετε emojis. Το "Αυτόματο" θα προσπαθήσει να χρησιμοποιήσει εγγενή emoji, αλλά πέφτει πίσω στο Twemoji για προγράμματα περιήγησης παλαιού τύπου. setting_quick_boosting_html: Όταν ενεργοποιηθεί, κάνοντας κλικ στο εικονίδιο %{boost_icon} Ενίσχυση θα ενισχύσει αμέσως αντί να ανοίξει το αναπτυσσόμενο μενού ενίσχυσης/παράθεσης. Μετακινεί την ενέργεια παράθεσης στο μενού %{options_icon} (Επιλογές). - setting_system_scrollbars_ui: Ισχύει μόνο για προγράμματα περιήγησης υπολογιστή με βάση το Safari και το Chrome + setting_system_scrollbars_ui: Ισχύει μόνο για προγράμματα περιήγησης για υπολογιστή με βάση το Safari και το Chrome setting_use_blurhash: Οι διαβαθμίσεις βασίζονται στα χρώματα του κρυμμένου πολυμέσου αλλά θολώνουν τις λεπτομέρειες setting_use_pending_items: Εμφάνιση ενημερώσεων ροής μετά από κλικ αντί για αυτόματη κύλιση της ροής username: Μπορείς να χρησιμοποιήσεις γράμματα, αριθμούς και κάτω παύλες @@ -82,8 +82,8 @@ el: action: Επιλέξτε ποια ενέργεια θα εκτελεστεί όταν μια ανάρτηση αντιστοιχεί με το φίλτρο actions: blur: Απόκρυψη πολυμέσων πίσω από μια προειδοποίηση, χωρίς να κρύβεται το ίδιο το κείμενο - hide: Πλήρης αποκρυψη του φιλτραρισμένου περιεχομένου, συμπεριφέρεται σαν να μην υπήρχε - warn: Απόκρυψη φιλτραρισμένου περιεχομένου πίσω από μια προειδοποίηση που αναφέρει τον τίτλο του φίλτρου + hide: Πλήρης απόκρυψη του φιλτραρισμένου περιεχομένου, συμπεριφέρεται σαν να μην υπήρχε + warn: Απόκρυψη φιλτραρισμένου περιεχομένου πίσω από μια προειδοποίηση που επισημαίνει τον τίτλο του φίλτρου form_admin_settings: activity_api_enabled: Καταμέτρηση τοπικά δημοσιευμένων αναρτήσεων, ενεργών χρηστών και νέων εγγραφών σε εβδομαδιαία πακέτα app_icon: WEBP, PNG, GIF ή JPG. Παρακάμπτει το προεπιλεγμένο εικονίδιο εφαρμογής σε κινητές συσκευές με προσαρμοσμένο εικονίδιο. diff --git a/config/locales/sq.yml b/config/locales/sq.yml index db9bc4a0ab7..2580b348507 100644 --- a/config/locales/sq.yml +++ b/config/locales/sq.yml @@ -968,6 +968,7 @@ sq: site_uploads: delete: Fshi kartelën e ngarkuar destroyed_msg: Ngarkimi në sajt u fshi me sukses! + skip_to_content: Hidhu te lënda software_updates: critical_update: Kritik — ju lutemi, përditësojeni pa humbur kohë description: Rekomandohet ta mbani të përditësuar instalimin tuaj të Mastodon-it, që të përfitoni nga ndreqjet dhe veçoritë më të reja. Për më tej, ndonjëherë është kritike të përditësohet Mastodon-i në kohën e duhur, për të shmangur probleme sigurie. Për këto arsye, Mastodon-i kontrollon për përditësime çdo 30 minuta dhe do t’ju njoftojë, sipas parapëlqimeve tuaja për njoftime me email. diff --git a/config/locales/vi.yml b/config/locales/vi.yml index 5f809e9d396..edc0eaed026 100644 --- a/config/locales/vi.yml +++ b/config/locales/vi.yml @@ -963,6 +963,7 @@ vi: site_uploads: delete: Xóa tệp đã tải lên destroyed_msg: Đã xóa tệp tải lên thành công! + skip_to_content: Đến nội dung chính software_updates: critical_update: Quan trọng — vui lòng cập nhật sớm description: Bạn nên cập nhật Mastodon phiên bản mới nhất để được hưởng lợi từ các bản sửa lỗi và thêm tính năng mới. Nhất là để tránh các vấn đề bảo mật. Vì những lý do này, Mastodon sẽ kiểm tra các bản cập nhật 30 phút một lần và sẽ thông báo cho bạn theo tùy chọn thông báo qua email của bạn. diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index e618265348a..f1d56319dc9 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -963,6 +963,7 @@ zh-CN: site_uploads: delete: 删除已上传的文件 destroyed_msg: 站点上传的文件已经成功删除! + skip_to_content: 跳转到内容 software_updates: critical_update: 紧急 — 请尽快更新 description: 建议你及时更新Mastodon实例,以便获得最新修复和功能。此外,为避免安全问题,有时及时更新Mastodon是至关重要的。出于这些原因,Mastodon每30分钟检查一次更新,并根据你的邮件通知偏好向你发送通知。 diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index c85a032b4fc..0a14e2f4877 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -965,6 +965,7 @@ zh-TW: site_uploads: delete: 刪除上傳的檔案 destroyed_msg: 成功刪除站台的上傳項目! + skip_to_content: 跳轉至內容 software_updates: critical_update: 重要 — 請儘速升級 description: 建議將您的 Mastodon 伺服器升級至最新狀態,以獲得最新錯誤修正及功能更新。此外,即時更新 Mastodon 以避免偶發之安全問題非常重要。因此,Mastodon 每 30 分鐘將檢查一次更新,並依據您的電子郵件通知設定通知您。 From fd4a9c25dda80699055f3fcfbb8e28395ff3bbc8 Mon Sep 17 00:00:00 2001 From: zunda Date: Thu, 21 May 2026 23:21:29 -1000 Subject: [PATCH 08/70] Honor configuration.statuses.max_characters from /api/v2/instance (#39138) --- .../features/compose/containers/compose_form_container.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/mastodon/features/compose/containers/compose_form_container.js b/app/javascript/mastodon/features/compose/containers/compose_form_container.js index 4ace6d934de..c5cffff10d5 100644 --- a/app/javascript/mastodon/features/compose/containers/compose_form_container.js +++ b/app/javascript/mastodon/features/compose/containers/compose_form_container.js @@ -58,7 +58,7 @@ const mapStateToProps = state => ({ && !state.getIn(['settings', 'dismissed_banners', PRIVATE_QUOTE_MODAL_ID]), isInReply: state.getIn(['compose', 'in_reply_to']) !== null, lang: state.getIn(['compose', 'language']), - maxChars: state.getIn(['server', 'server', 'configuration', 'statuses', 'max_characters'], 500), + maxChars: state.getIn(['server', 'server', 'item', 'configuration', 'statuses', 'max_characters'], 500), }); const mapDispatchToProps = (dispatch, props) => ({ From ae8b794c661774125605c065ee953eea7fb39135 Mon Sep 17 00:00:00 2001 From: diondiondion Date: Fri, 22 May 2026 11:23:37 +0200 Subject: [PATCH 09/70] Accessibility: Convey selected state of filters on Follows and followers page (#39134) --- app/helpers/admin/filter_helper.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/helpers/admin/filter_helper.rb b/app/helpers/admin/filter_helper.rb index 40806a45158..a3dd83ecca6 100644 --- a/app/helpers/admin/filter_helper.rb +++ b/app/helpers/admin/filter_helper.rb @@ -20,8 +20,9 @@ module Admin::FilterHelper def filter_link_to(text, link_to_params, link_class_params = link_to_params) new_url = filtered_url_for(link_to_params) new_class = filtered_url_for(link_class_params) + is_selected = selected?(link_class_params) - link_to text, new_url, class: filter_link_class(new_class) + link_to text, new_url, class: filter_link_class(new_class), 'aria-current': (is_selected ? 'true' : nil) end def table_link_to(icon, text, path, **options) From dee85c6df9b84dfd0a2650ad9b536e9f7f03d465 Mon Sep 17 00:00:00 2001 From: David Roetzel Date: Fri, 22 May 2026 12:11:41 +0200 Subject: [PATCH 10/70] Only preload accounts in Collections when needed (#39143) --- app/models/collection.rb | 14 +++++++----- app/models/collection_item.rb | 2 +- .../collection_with_accounts_serializer.rb | 2 +- spec/models/collection_spec.rb | 22 +++++++++++++++++++ 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/app/models/collection.rb b/app/models/collection.rb index c5082269e02..ac763316598 100644 --- a/app/models/collection.rb +++ b/app/models/collection.rb @@ -64,11 +64,15 @@ class Collection < ApplicationRecord !local? end - def items_for(account = nil) - result = collection_items.with_accounts - result = account == self.account ? result.pending_or_accepted : result.accepted - result = result.not_blocked_by(account) unless account.nil? - result + def items_for(account = nil, include_accounts: false) + @items_for ||= {} + @items_for[account] ||= begin + result = collection_items + result = result.with_accounts if include_accounts + result = account == self.account ? result.pending_or_accepted : result.accepted + result = result.not_blocked_by(account) unless account.nil? + result + end end def tag_name diff --git a/app/models/collection_item.rb b/app/models/collection_item.rb index 8de27950f1f..f37e67e8fdf 100644 --- a/app/models/collection_item.rb +++ b/app/models/collection_item.rb @@ -43,7 +43,7 @@ class CollectionItem < ApplicationRecord scope :ordered, -> { order(position: :asc) } scope :with_accounts, -> { includes(account: [:account_stat, :user]) } - scope :not_blocked_by, ->(account) { where.not(accounts: { id: account.blocking }) } + scope :not_blocked_by, ->(account) { joins(:account).where.not(accounts: { id: account.blocking }) } scope :local, -> { joins(:collection).merge(Collection.local) } scope :accepted_partial, ->(account) { joins(:account).merge(Account.local).accepted.where(uri: nil, account_id: account.id) } scope :pending_or_accepted, -> { where(state: [:pending, :accepted]) } diff --git a/app/serializers/rest/collection_with_accounts_serializer.rb b/app/serializers/rest/collection_with_accounts_serializer.rb index be0b9550227..ea7602776b5 100644 --- a/app/serializers/rest/collection_with_accounts_serializer.rb +++ b/app/serializers/rest/collection_with_accounts_serializer.rb @@ -10,6 +10,6 @@ class REST::CollectionWithAccountsSerializer < ActiveModel::Serializer end def accounts - [object.account] + object.collection_items.filter_map(&:account) + [object.account] + object.items_for(current_user&.account, include_accounts: true).map(&:account) end end diff --git a/spec/models/collection_spec.rb b/spec/models/collection_spec.rb index b9a54536421..67b51fdceac 100644 --- a/spec/models/collection_spec.rb +++ b/spec/models/collection_spec.rb @@ -124,6 +124,28 @@ RSpec.describe Collection do expect(subject.items_for(account)).to match_array(accepted_items + [pending_item]) end end + + context 'when `include_accounts` is set to `true`' do + it 'preloads accounts' do + items = subject.items_for(include_accounts: true).to_a + + expect { items.first.account }.to_not execute_queries + end + end + + context 'when called multiple times' do + let(:account) { subject.account } + + it 'memoizes results' do + subject.items_for.to_a + + expect { subject.items_for.to_a }.to_not execute_queries + + expect { subject.items_for(account).to_a }.to execute_queries + + expect { subject.items_for(account).to_a }.to_not execute_queries + end + end end describe '#tag_name=' do From 90e505d295792ead6e4dd4f83bc114ed188a4946 Mon Sep 17 00:00:00 2001 From: diondiondion Date: Fri, 22 May 2026 16:08:51 +0200 Subject: [PATCH 11/70] [Accessibility] Use headings and lists in footer (#39144) --- .../mastodon/features/about/index.jsx | 2 +- .../features/getting_started/index.tsx | 2 +- .../features/ui/components/compose_panel.tsx | 2 +- .../ui/components/link_footer.module.scss | 61 +++++++ .../features/ui/components/link_footer.tsx | 170 ++++++++++-------- .../styles/mastodon/components.scss | 47 ----- 6 files changed, 157 insertions(+), 127 deletions(-) create mode 100644 app/javascript/mastodon/features/ui/components/link_footer.module.scss diff --git a/app/javascript/mastodon/features/about/index.jsx b/app/javascript/mastodon/features/about/index.jsx index 4c1ee5254ae..01ae0b16a37 100644 --- a/app/javascript/mastodon/features/about/index.jsx +++ b/app/javascript/mastodon/features/about/index.jsx @@ -164,7 +164,7 @@ class About extends PureComponent { ))} - +

diff --git a/app/javascript/mastodon/features/getting_started/index.tsx b/app/javascript/mastodon/features/getting_started/index.tsx index f4f66f1404f..84c786fa068 100644 --- a/app/javascript/mastodon/features/getting_started/index.tsx +++ b/app/javascript/mastodon/features/getting_started/index.tsx @@ -13,7 +13,7 @@ const GettingStarted: React.FC = () => { - + diff --git a/app/javascript/mastodon/features/ui/components/compose_panel.tsx b/app/javascript/mastodon/features/ui/components/compose_panel.tsx index cc55ff4cef6..838d1510ecc 100644 --- a/app/javascript/mastodon/features/ui/components/compose_panel.tsx +++ b/app/javascript/mastodon/features/ui/components/compose_panel.tsx @@ -51,7 +51,7 @@ export const ComposePanel: React.FC = () => { {signedIn && !hideComposer && <ComposeFormContainer singleColumn />} {signedIn && hideComposer && <div className='compose-form' />} - <LinkFooter multiColumn={!singleColumn} /> + <LinkFooter context={singleColumn ? 'default' : 'multi-column'} /> </div> ); }; diff --git a/app/javascript/mastodon/features/ui/components/link_footer.module.scss b/app/javascript/mastodon/features/ui/components/link_footer.module.scss new file mode 100644 index 00000000000..f2b094744e4 --- /dev/null +++ b/app/javascript/mastodon/features/ui/components/link_footer.module.scss @@ -0,0 +1,61 @@ +.wrapper { + z-index: 1; + flex: 0 0 auto; + display: flex; + flex-direction: column; + gap: 20px; + font-size: 13px; + color: var(--color-text-secondary); + + &[data-context='default'] { + padding: 20px 0; + } + + &[data-context='multi-column'] { + padding: 15px; + } + + &[data-context='about'] { + margin-top: 60px; + text-align: center; + font-size: 15px; + line-height: 22px; + + @media screen and (width >= 1175px) { + display: none; + } + } +} + +.heading { + display: inline; + margin-inline-end: 0.3em; + font-weight: 500; +} + +.list { + display: inline; + + li { + display: inline; + + &:not(:last-child)::after { + content: ' · '; + } + } + + a { + color: var(--color-text-secondary); + text-decoration: underline; + + &:hover, + &:focus, + &:active { + text-decoration: none; + } + } +} + +.version { + white-space: nowrap; +} diff --git a/app/javascript/mastodon/features/ui/components/link_footer.tsx b/app/javascript/mastodon/features/ui/components/link_footer.tsx index df153b22581..1f4ee7cde95 100644 --- a/app/javascript/mastodon/features/ui/components/link_footer.tsx +++ b/app/javascript/mastodon/features/ui/components/link_footer.tsx @@ -11,94 +11,110 @@ import { termsOfServiceEnabled, } from 'mastodon/initial_state'; -const DividingCircle: React.FC = () => <span aria-hidden>{' · '}</span>; +import classes from './link_footer.module.scss'; export const LinkFooter: React.FC<{ - multiColumn: boolean; -}> = ({ multiColumn }) => { + context?: 'default' | 'multi-column' | 'about'; +}> = ({ context = 'default' }) => { + const multiColumn = context === 'multi-column'; + return ( - <div className='link-footer'> - <p> - <strong>{domain}</strong>:{' '} - <Link to='/about' target={multiColumn ? '_blank' : undefined}> - <FormattedMessage - id='footer.about_this_server' - defaultMessage='About' - /> - </Link> - {statusPageUrl && ( - <> - <DividingCircle /> - <a href={statusPageUrl} target='_blank' rel='noopener'> - <FormattedMessage id='footer.status' defaultMessage='Status' /> - </a> - </> - )} - {canProfileDirectory && ( - <> - <DividingCircle /> - <Link to='/directory'> + <footer className={classes.wrapper} data-context={context}> + <section> + <h2 className={classes.heading}>{`${domain}:`}</h2> + <ul className={classes.list}> + <li> + <Link to='/about' target={multiColumn ? '_blank' : undefined}> <FormattedMessage - id='footer.directory' - defaultMessage='Profiles directory' + id='footer.about_this_server' + defaultMessage='About' /> </Link> - </> - )} - <DividingCircle /> - <Link - to='/privacy-policy' - target={multiColumn ? '_blank' : undefined} - rel='privacy-policy' - > - <FormattedMessage - id='footer.privacy_policy' - defaultMessage='Privacy policy' - /> - </Link> - {termsOfServiceEnabled && ( - <> - <DividingCircle /> + </li> + {statusPageUrl && ( + <li> + <a href={statusPageUrl} target='_blank' rel='noopener'> + <FormattedMessage id='footer.status' defaultMessage='Status' /> + </a> + </li> + )} + {canProfileDirectory && ( + <li> + <Link to='/directory'> + <FormattedMessage + id='footer.directory' + defaultMessage='Profiles directory' + /> + </Link> + </li> + )} + <li> <Link - to='/terms-of-service' + to='/privacy-policy' target={multiColumn ? '_blank' : undefined} - rel='terms-of-service' + rel='privacy-policy' > <FormattedMessage - id='footer.terms_of_service' - defaultMessage='Terms of service' + id='footer.privacy_policy' + defaultMessage='Privacy policy' /> </Link> - </> - )} - </p> - - <p> - <strong>Mastodon</strong>:{' '} - <a href='https://joinmastodon.org' target='_blank' rel='noopener'> - <FormattedMessage id='footer.about' defaultMessage='About' /> - </a> - <DividingCircle /> - <a href='https://joinmastodon.org/apps' target='_blank' rel='noopener'> - <FormattedMessage id='footer.get_app' defaultMessage='Get the app' /> - </a> - <DividingCircle /> - <Link to='/keyboard-shortcuts'> - <FormattedMessage - id='footer.keyboard_shortcuts' - defaultMessage='Keyboard shortcuts' - /> - </Link> - <DividingCircle /> - <a href={source_url} rel='noopener' target='_blank'> - <FormattedMessage - id='footer.source_code' - defaultMessage='View source code' - /> - </a> - <DividingCircle /> - <span className='version'>v{version}</span> - </p> - </div> + </li> + {termsOfServiceEnabled && ( + <li> + <Link + to='/terms-of-service' + target={multiColumn ? '_blank' : undefined} + rel='terms-of-service' + > + <FormattedMessage + id='footer.terms_of_service' + defaultMessage='Terms of service' + /> + </Link> + </li> + )} + </ul> + </section> + <section> + <h2 className={classes.heading}>Mastodon:</h2> + <ul className={classes.list}> + <li> + <a href='https://joinmastodon.org' target='_blank' rel='noopener'> + <FormattedMessage id='footer.about' defaultMessage='About' /> + </a> + </li> + <li> + <a + href='https://joinmastodon.org/apps' + target='_blank' + rel='noopener' + > + <FormattedMessage + id='footer.get_app' + defaultMessage='Get the app' + /> + </a> + </li> + <li> + <Link to='/keyboard-shortcuts'> + <FormattedMessage + id='footer.keyboard_shortcuts' + defaultMessage='Keyboard shortcuts' + /> + </Link> + </li> + <li> + <a href={source_url} rel='noopener' target='_blank'> + <FormattedMessage + id='footer.source_code' + defaultMessage='View source code' + /> + </a> + </li> + <li className={classes.version}>v{version}</li> + </ul> + </section> + </footer> ); }; diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 6824de24bff..ec5caf93995 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -9637,41 +9637,6 @@ noscript { } } -.link-footer { - flex: 0 0 auto; - padding-top: 20px; - z-index: 1; - font-size: 13px; - - .column & { - padding: 15px; - } - - p { - color: var(--color-text-secondary); - margin-bottom: 20px; - - .version { - white-space: nowrap; - } - - strong { - font-weight: 500; - } - - a { - color: var(--color-text-secondary); - text-decoration: underline; - - &:hover, - &:focus, - &:active { - text-decoration: none; - } - } - } -} - .about { padding: 20px; border-top: 1px solid var(--color-border-primary); @@ -9808,18 +9773,6 @@ noscript { } } - .link-footer { - padding: 0; - margin-top: 60px; - text-align: center; - font-size: 15px; - line-height: 22px; - - @media screen and (min-width: $no-gap-breakpoint) { - display: none; - } - } - .account { padding: 0; border: 0; From 28849e433a4cde2037d7e719f9061e37267da3e7 Mon Sep 17 00:00:00 2001 From: diondiondion <mail@diondiondion.com> Date: Fri, 22 May 2026 16:25:00 +0200 Subject: [PATCH 12/70] [Accessibility] Add list semantics to main navigation (#39145) --- .../components/collapsible_panel.tsx | 6 +- .../features/navigation_panel/index.tsx | 202 ++++++++++-------- .../styles/mastodon/components.scss | 3 +- 3 files changed, 119 insertions(+), 92 deletions(-) diff --git a/app/javascript/mastodon/features/navigation_panel/components/collapsible_panel.tsx b/app/javascript/mastodon/features/navigation_panel/components/collapsible_panel.tsx index 39a78995964..217e15b5ee0 100644 --- a/app/javascript/mastodon/features/navigation_panel/components/collapsible_panel.tsx +++ b/app/javascript/mastodon/features/navigation_panel/components/collapsible_panel.tsx @@ -36,7 +36,7 @@ export const CollapsiblePanel: React.FC<{ }, [setExpanded]); return ( - <div className='navigation-panel__list-panel'> + <li className='navigation-panel__list-panel'> <div className='navigation-panel__list-panel__header'> <ColumnLink transparent @@ -64,7 +64,7 @@ export const CollapsiblePanel: React.FC<{ } title={expanded ? collapseTitle : expandTitle} onClick={handleClick} - aria-controls={`${accessibilityId}-content`} + ariaControls={`${accessibilityId}-content`} /> </> )} @@ -80,6 +80,6 @@ export const CollapsiblePanel: React.FC<{ {children} </div> )} - </div> + </li> ); }; diff --git a/app/javascript/mastodon/features/navigation_panel/index.tsx b/app/javascript/mastodon/features/navigation_panel/index.tsx index 33a2a43a70a..3d038c22dd2 100644 --- a/app/javascript/mastodon/features/navigation_panel/index.tsx +++ b/app/javascript/mastodon/features/navigation_panel/index.tsx @@ -249,124 +249,150 @@ export const NavigationPanel: React.FC<{ multiColumn?: boolean }> = ({ {banner && <div className='navigation-panel__banner'>{banner}</div>} - <div className='navigation-panel__menu'> + <ul className='navigation-panel__menu'> {signedIn && ( <> {!multiColumn && ( - <ColumnLink - to='/publish' - icon='plus' - iconComponent={AddIcon} - activeIconComponent={AddIcon} - text={intl.formatMessage(messages.compose)} - className='button navigation-panel__compose-button' - /> + <li> + <ColumnLink + to='/publish' + icon='plus' + iconComponent={AddIcon} + activeIconComponent={AddIcon} + text={intl.formatMessage(messages.compose)} + className='button navigation-panel__compose-button' + /> + </li> )} - <ColumnLink - transparent - to='/home' - icon='home' - iconComponent={HomeIcon} - activeIconComponent={HomeActiveIcon} - text={intl.formatMessage(messages.home)} - /> + <li> + <ColumnLink + transparent + to='/home' + icon='home' + iconComponent={HomeIcon} + activeIconComponent={HomeActiveIcon} + text={intl.formatMessage(messages.home)} + /> + </li> </> )} {trendsEnabled && ( - <ColumnLink - transparent - to='/explore' - icon='explore' - iconComponent={TrendingUpIcon} - text={intl.formatMessage(messages.explore)} - /> + <li> + <ColumnLink + transparent + to='/explore' + icon='explore' + iconComponent={TrendingUpIcon} + text={intl.formatMessage(messages.explore)} + /> + </li> )} {(canViewFeed(signedIn, permissions, localLiveFeedAccess) || canViewFeed(signedIn, permissions, remoteLiveFeedAccess)) && ( - <ColumnLink - transparent - to={ - canViewFeed(signedIn, permissions, localLiveFeedAccess) - ? '/public/local' - : '/public/remote' - } - icon='globe' - iconComponent={PublicIcon} - isActive={isFirehoseActive} - text={intl.formatMessage( - canViewFeed(signedIn, permissions, localLiveFeedAccess) && - canViewFeed(signedIn, permissions, remoteLiveFeedAccess) - ? messages.firehose - : messages.firehose_singular, - )} - /> + <li> + <ColumnLink + transparent + to={ + canViewFeed(signedIn, permissions, localLiveFeedAccess) + ? '/public/local' + : '/public/remote' + } + icon='globe' + iconComponent={PublicIcon} + isActive={isFirehoseActive} + text={intl.formatMessage( + canViewFeed(signedIn, permissions, localLiveFeedAccess) && + canViewFeed(signedIn, permissions, remoteLiveFeedAccess) + ? messages.firehose + : messages.firehose_singular, + )} + /> + </li> )} {signedIn && ( <> - <NotificationsLink /> + <li> + <NotificationsLink /> + </li> - <FollowRequestsLink /> + <li> + <FollowRequestsLink /> + </li> - <AnnualReportNavItem /> + <li> + <AnnualReportNavItem /> + </li> - <hr /> + <li role='separator' /> <ListPanel /> <FollowedTagsPanel /> - <ColumnLink - transparent - to='/favourites' - icon='star' - iconComponent={StarIcon} - activeIconComponent={StarActiveIcon} - text={intl.formatMessage(messages.favourites)} - /> - <ColumnLink - transparent - to='/bookmarks' - icon='bookmarks' - iconComponent={BookmarksIcon} - activeIconComponent={BookmarksActiveIcon} - text={intl.formatMessage(messages.bookmarks)} - /> - {areCollectionsEnabled() && ( + <li> <ColumnLink transparent - to={`/@${account?.acct}/collections`} - icon='collections' - iconComponent={CollectionsIcon} - activeIconComponent={CollectionsActiveIcon} - text={intl.formatMessage(messages.collections)} + to='/favourites' + icon='star' + iconComponent={StarIcon} + activeIconComponent={StarActiveIcon} + text={intl.formatMessage(messages.favourites)} /> + </li> + <li> + <ColumnLink + transparent + to='/bookmarks' + icon='bookmarks' + iconComponent={BookmarksIcon} + activeIconComponent={BookmarksActiveIcon} + text={intl.formatMessage(messages.bookmarks)} + /> + </li> + {areCollectionsEnabled() && ( + <li> + <ColumnLink + transparent + to={`/@${account?.acct}/collections`} + icon='collections' + iconComponent={CollectionsIcon} + activeIconComponent={CollectionsActiveIcon} + text={intl.formatMessage(messages.collections)} + /> + </li> )} - <ColumnLink - transparent - to='/conversations' - icon='at' - iconComponent={AlternateEmailIcon} - text={intl.formatMessage(messages.direct)} - /> + <li> + <ColumnLink + transparent + to='/conversations' + icon='at' + iconComponent={AlternateEmailIcon} + text={intl.formatMessage(messages.direct)} + /> + </li> - <hr /> + <li role='separator' /> - <ColumnLink - transparent - href='/settings/preferences' - icon='cog' - iconComponent={SettingsIcon} - text={intl.formatMessage(messages.preferences)} - /> + <li> + <ColumnLink + transparent + href='/settings/preferences' + icon='cog' + iconComponent={SettingsIcon} + text={intl.formatMessage(messages.preferences)} + /> + </li> - <MoreLink /> + <li> + <MoreLink /> + </li> </> )} - <div className='navigation-panel__legal'> + <li className='navigation-panel__legal'> <ColumnLink transparent to='/about' @@ -374,16 +400,16 @@ export const NavigationPanel: React.FC<{ multiColumn?: boolean }> = ({ iconComponent={InfoIcon} text={intl.formatMessage(messages.about)} /> - </div> + </li> {!signedIn && ( - <div className='navigation-panel__sign-in-banner'> + <li className='navigation-panel__sign-in-banner'> <hr /> {disabledAccountId ? <DisabledAccountBanner /> : <SignInBanner />} - </div> + </li> )} - </div> + </ul> <div className='flex-spacer' /> diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index ec5caf93995..2e85f7a476b 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -3801,7 +3801,8 @@ a.account__display-name { .navigation-panel, .compose-panel { - hr { + hr, + li[role='separator'] { flex: 0 0 auto; border: 0; background: transparent; From 6a4d14b178fc00de989b4a2758f2a1e4adf5ed33 Mon Sep 17 00:00:00 2001 From: diondiondion <mail@diondiondion.com> Date: Fri, 22 May 2026 17:06:59 +0200 Subject: [PATCH 13/70] [Accessibility] Fix heading level gaps (#39149) --- app/javascript/mastodon/components/status.jsx | 4 +- .../mastodon/features/about/index.jsx | 3 +- .../components/collection_lockup.tsx | 4 +- .../collections/components/share_modal.tsx | 2 +- .../components/inline_follow_suggestions.tsx | 4 +- .../navigation_panel/components/trends.tsx | 8 +-- .../components/notification_admin_report.tsx | 4 +- .../components/notification_collection.tsx | 4 +- .../notification_group_with_status.tsx | 4 +- .../components/notification_with_status.tsx | 4 +- .../status/components/detailed_status.tsx | 12 +++- .../styles/mastodon/components.scss | 58 +++++++++---------- 12 files changed, 61 insertions(+), 50 deletions(-) diff --git a/app/javascript/mastodon/components/status.jsx b/app/javascript/mastodon/components/status.jsx index c909f9f0b1f..808f4d73bfc 100644 --- a/app/javascript/mastodon/components/status.jsx +++ b/app/javascript/mastodon/components/status.jsx @@ -556,7 +556,7 @@ class Status extends ImmutablePureComponent { ).find((item) => compareUrls(item.get('url'), cardUrl)); if (taggedCollection) { - media = <CollectionPreviewCard collection={taggedCollection.toJS()} />; + media = <CollectionPreviewCard collection={taggedCollection.toJS()} headingLevel='h2' />; } else { media = ( <Card @@ -570,7 +570,7 @@ class Status extends ImmutablePureComponent { const firstLinkedCollection = status.get('tagged_collections').first(); if (firstLinkedCollection) { media = ( - <CollectionPreviewCard collection={firstLinkedCollection.toJS()} /> + <CollectionPreviewCard collection={firstLinkedCollection.toJS()} headingLevel='h2' /> ); } } diff --git a/app/javascript/mastodon/features/about/index.jsx b/app/javascript/mastodon/features/about/index.jsx index 01ae0b16a37..85b76aee32e 100644 --- a/app/javascript/mastodon/features/about/index.jsx +++ b/app/javascript/mastodon/features/about/index.jsx @@ -18,6 +18,7 @@ import { LinkFooter} from 'mastodon/features/ui/components/link_footer'; import { Section } from './components/section'; import { RulesSection } from './components/rules'; +import { getColumnSkipLinkId } from '../ui/components/skip_links'; const messages = defineMessages({ title: { id: 'column.about', defaultMessage: 'About' }, @@ -80,7 +81,7 @@ class About extends PureComponent { return ( <Column bindToDocument={!multiColumn} label={intl.formatMessage(messages.title)}> - <div className='scrollable about'> + <div className='scrollable about' id={getColumnSkipLinkId(1)}> <div className='about__header'> <ServerHeroImage withAltBadge diff --git a/app/javascript/mastodon/features/collections/components/collection_lockup.tsx b/app/javascript/mastodon/features/collections/components/collection_lockup.tsx index c79de4f61e7..e16d49e7922 100644 --- a/app/javascript/mastodon/features/collections/components/collection_lockup.tsx +++ b/app/javascript/mastodon/features/collections/components/collection_lockup.tsx @@ -47,6 +47,7 @@ export interface CollectionLockupProps { withTimestamp?: boolean; sideContent?: React.ReactNode; className?: string; + headingLevel?: 'h2' | 'h3' | 'h4'; } export const CollectionLockup: React.FC<CollectionLockupProps> = ({ @@ -54,6 +55,7 @@ export const CollectionLockup: React.FC<CollectionLockupProps> = ({ withAuthorHandle = true, withTimestamp, sideContent, + headingLevel = 'h3', className, }) => { const { id, name } = collection; @@ -70,7 +72,7 @@ export const CollectionLockup: React.FC<CollectionLockupProps> = ({ sideContent={sideContent} > <ListItemLink - as='h3' + as={headingLevel} to={getCollectionPath(id)} subtitle={ <CollectionInfo diff --git a/app/javascript/mastodon/features/collections/components/share_modal.tsx b/app/javascript/mastodon/features/collections/components/share_modal.tsx index f9e9985519d..e9039e0dd13 100644 --- a/app/javascript/mastodon/features/collections/components/share_modal.tsx +++ b/app/javascript/mastodon/features/collections/components/share_modal.tsx @@ -92,7 +92,7 @@ export const CollectionShareModal: React.FC<{ /> <div className={classes.preview}> - <CollectionPreviewCard collection={collection} /> + <CollectionPreviewCard collection={collection} headingLevel='h2' /> </div> <CopyLinkField diff --git a/app/javascript/mastodon/features/home_timeline/components/inline_follow_suggestions.tsx b/app/javascript/mastodon/features/home_timeline/components/inline_follow_suggestions.tsx index d7c463c5cc3..e48fd19c3bd 100644 --- a/app/javascript/mastodon/features/home_timeline/components/inline_follow_suggestions.tsx +++ b/app/javascript/mastodon/features/home_timeline/components/inline_follow_suggestions.tsx @@ -212,12 +212,12 @@ export const InlineFollowSuggestions: React.FC<{ hidden?: boolean }> = ({ tabIndex={-1} > <div className='inline-follow-suggestions__header'> - <h3 id={uniqueId}> + <h2 id={uniqueId} className='inline-follow-suggestions__title'> <FormattedMessage id='follow_suggestions.who_to_follow' defaultMessage='Who to follow' /> - </h3> + </h2> <div className='inline-follow-suggestions__header__actions'> <button className='link-button' onClick={handleDismiss} type='button'> diff --git a/app/javascript/mastodon/features/navigation_panel/components/trends.tsx b/app/javascript/mastodon/features/navigation_panel/components/trends.tsx index f51bb2ed9ff..8e8f1e47e11 100644 --- a/app/javascript/mastodon/features/navigation_panel/components/trends.tsx +++ b/app/javascript/mastodon/features/navigation_panel/components/trends.tsx @@ -37,21 +37,21 @@ export const Trends: React.FC = () => { } return ( - <div className='navigation-panel__portal'> + <aside className='navigation-panel__portal'> <div className='getting-started__trends'> - <h4> + <h2 className='getting-started__trends-heading'> <Link to={'/explore/tags'}> <FormattedMessage id='trends.trending_now' defaultMessage='Trending now' /> </Link> - </h4> + </h2> {trends.take(4).map((hashtag) => ( <Hashtag key={hashtag.get('name') as string} hashtag={hashtag} /> ))} </div> - </div> + </aside> ); }; diff --git a/app/javascript/mastodon/features/notifications_v2/components/notification_admin_report.tsx b/app/javascript/mastodon/features/notifications_v2/components/notification_admin_report.tsx index 03f047fb7fe..a3da581f88a 100644 --- a/app/javascript/mastodon/features/notifications_v2/components/notification_admin_report.tsx +++ b/app/javascript/mastodon/features/notifications_v2/components/notification_admin_report.tsx @@ -106,10 +106,10 @@ export const NotificationAdminReport: React.FC<{ <div className='notification-group__main'> <div className='notification-group__main__header'> - <div className='notification-group__main__header__label'> + <h2 className='notification-group__main__header__label'> {message} <RelativeTimestamp timestamp={report.created_at} /> - </div> + </h2> </div> {report.comment.length > 0 && ( diff --git a/app/javascript/mastodon/features/notifications_v2/components/notification_collection.tsx b/app/javascript/mastodon/features/notifications_v2/components/notification_collection.tsx index 10466b5d3d8..9c8d3832b72 100644 --- a/app/javascript/mastodon/features/notifications_v2/components/notification_collection.tsx +++ b/app/javascript/mastodon/features/notifications_v2/components/notification_collection.tsx @@ -46,7 +46,7 @@ export const NotificationCollection: React.FC<{ <div className='notification-group__main'> <div className='notification-group__main__header'> - <div className='notification-group__main__header__label'> + <h2 className='notification-group__main__header__label'> {type === 'added_to_collection' && ( <FormattedMessage id='notification.added_to_collection' @@ -79,7 +79,7 @@ export const NotificationCollection: React.FC<{ }} /> )} - </div> + </h2> </div> <CollectionPreviewCard collection={collection} /> diff --git a/app/javascript/mastodon/features/notifications_v2/components/notification_group_with_status.tsx b/app/javascript/mastodon/features/notifications_v2/components/notification_group_with_status.tsx index 8035493283c..8377e8465b9 100644 --- a/app/javascript/mastodon/features/notifications_v2/components/notification_group_with_status.tsx +++ b/app/javascript/mastodon/features/notifications_v2/components/notification_group_with_status.tsx @@ -125,7 +125,7 @@ export const NotificationGroupWithStatus: React.FC<{ )} </div> - <div className='notification-group__main__header__label'> + <h2 className='notification-group__main__header__label'> <span>{label}</span> {timestamp && ( <> @@ -135,7 +135,7 @@ export const NotificationGroupWithStatus: React.FC<{ <RelativeTimestamp timestamp={timestamp} /> </> )} - </div> + </h2> </div> {statusId && ( diff --git a/app/javascript/mastodon/features/notifications_v2/components/notification_with_status.tsx b/app/javascript/mastodon/features/notifications_v2/components/notification_with_status.tsx index 68c62232da8..6a110c1425a 100644 --- a/app/javascript/mastodon/features/notifications_v2/components/notification_with_status.tsx +++ b/app/javascript/mastodon/features/notifications_v2/components/notification_with_status.tsx @@ -101,12 +101,12 @@ export const NotificationWithStatus: React.FC<{ )} tabIndex={0} > - <div className='notification-ungrouped__header'> + <h2 className='notification-ungrouped__header'> <div className='notification-ungrouped__header__icon'> <Icon icon={icon} id={iconId} /> </div> <span>{label}</span> - </div> + </h2> <StatusQuoteManager id={statusId} diff --git a/app/javascript/mastodon/features/status/components/detailed_status.tsx b/app/javascript/mastodon/features/status/components/detailed_status.tsx index 0dec921343e..ba0ce8b8c50 100644 --- a/app/javascript/mastodon/features/status/components/detailed_status.tsx +++ b/app/javascript/mastodon/features/status/components/detailed_status.tsx @@ -272,7 +272,12 @@ export const DetailedStatus: React.FC<{ ); if (taggedCollection) { - media = <CollectionPreviewCard collection={taggedCollection.toJS()} />; + media = ( + <CollectionPreviewCard + collection={taggedCollection.toJS()} + headingLevel='h2' + /> + ); } else { media = ( <Card @@ -286,7 +291,10 @@ export const DetailedStatus: React.FC<{ const firstLinkedCollection = status.get('tagged_collections').first(); if (firstLinkedCollection) { media = ( - <CollectionPreviewCard collection={firstLinkedCollection.toJS()} /> + <CollectionPreviewCard + collection={firstLinkedCollection.toJS()} + headingLevel='h2' + /> ); } } diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 2e85f7a476b..25265433faf 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -3764,16 +3764,6 @@ a.account__display-name { margin-bottom: 12px; } - .getting-started__trends h4 { - padding: 10px 12px; - padding-inline-start: 16px; - } - - .getting-started__trends .trends__item { - padding: 10px 12px; - padding-inline-start: 16px; - } - @media screen and (height <= 930px) { &__portal .trends__item:nth-child(n + 5) { display: none; @@ -4140,25 +4130,30 @@ a.account__display-name { border: 1px solid var(--color-border-primary); border-top: 0; + &__trends-heading { + border-bottom: 1px solid var(--color-border-primary); + padding: 10px; + font-size: 12px; + text-transform: uppercase; + font-weight: 500; + + .navigation-panel & { + padding: 10px 12px; + padding-inline-start: 16px; + } + + a { + color: var(--color-text-secondary); + text-decoration: none; + } + } + &__trends { flex: 0 1 auto; opacity: 1; animation: fade 150ms linear; margin-top: 10px; - h4 { - border-bottom: 1px solid var(--color-border-primary); - padding: 10px; - font-size: 12px; - text-transform: uppercase; - font-weight: 500; - - a { - color: var(--color-text-secondary); - text-decoration: none; - } - } - .trends__item { border-bottom: 0; padding: 10px; @@ -4166,6 +4161,11 @@ a.account__display-name { &__current { color: var(--color-text-secondary); } + + .navigation-panel & { + padding: 10px 12px; + padding-inline-start: 16px; + } } } } @@ -10077,18 +10077,18 @@ noscript { background: var(--color-bg-brand-softest); } + &__title { + font-size: 15px; + line-height: 22px; + font-weight: 500; + } + &__header { display: flex; align-items: center; justify-content: space-between; padding: 0 16px; - h3 { - font-size: 15px; - line-height: 22px; - font-weight: 500; - } - &__actions { display: flex; align-items: center; From 6b2616453ffe7430295bea3d3ccbf06ada67e033 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nicole=20miko=C5=82ajczyk?= <git@mkljczk.pl> Date: Sat, 23 May 2026 13:07:02 +0200 Subject: [PATCH 14/70] Make it possible to retrieve both resolved and unresolved reports by api (#38323) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: nicole mikołajczyk <git@mkljczk.pl> --- .../api/v1/admin/reports_controller.rb | 1 + app/models/report_filter.rb | 17 +++++++++++++---- spec/requests/api/v1/admin/reports_spec.rb | 11 +++++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/app/controllers/api/v1/admin/reports_controller.rb b/app/controllers/api/v1/admin/reports_controller.rb index 9b5beeab67e..765996eb3cf 100644 --- a/app/controllers/api/v1/admin/reports_controller.rb +++ b/app/controllers/api/v1/admin/reports_controller.rb @@ -16,6 +16,7 @@ class Api::V1::Admin::ReportsController < Api::BaseController FILTER_PARAMS = %i( resolved + unresolved account_id target_account_id ).freeze diff --git a/app/models/report_filter.rb b/app/models/report_filter.rb index 9d2b0fb3742..dab45007bc9 100644 --- a/app/models/report_filter.rb +++ b/app/models/report_filter.rb @@ -3,6 +3,7 @@ class ReportFilter KEYS = %i( resolved + unresolved account_id target_account_id by_target_domain @@ -16,7 +17,7 @@ class ReportFilter end def results - scope = Report.unresolved + scope = status_scope relevant_params.each do |key, value| scope = scope.merge scope_for(key, value) @@ -28,7 +29,7 @@ class ReportFilter private def relevant_params - params.tap do |args| + params.except(:resolved, :unresolved).tap do |args| args.delete(:target_origin) if origin_is_remote_and_domain_present? end end @@ -37,12 +38,20 @@ class ReportFilter params[:target_origin] == 'remote' && params[:by_target_domain].present? end + def status_scope + resolved = params.key?(:resolved) + unresolved = params.key?(:unresolved) + + return Report.all if resolved && unresolved + return Report.resolved if resolved + + Report.unresolved + end + def scope_for(key, value) case key.to_sym when :by_target_domain Report.where(target_account: Account.where(domain: value)) - when :resolved - Report.resolved when :account_id Report.where(account_id: value) when :target_account_id diff --git a/spec/requests/api/v1/admin/reports_spec.rb b/spec/requests/api/v1/admin/reports_spec.rb index 54dd4c9c8c4..432e7f47a2b 100644 --- a/spec/requests/api/v1/admin/reports_spec.rb +++ b/spec/requests/api/v1/admin/reports_spec.rb @@ -78,6 +78,17 @@ RSpec.describe 'Reports' do end end + context 'with both resolved and unresolved params' do + let(:params) { { resolved: true, unresolved: true } } + let(:scope) { Report.all } + + it 'returns all reports' do + subject + + expect(response.parsed_body).to match_array(expected_response) + end + end + context 'with account_id param' do let(:params) { { account_id: reporter.id } } let(:scope) { Report.unresolved.where(account: reporter) } From 71da0c46483f2970befff84eb7f0fdf66b58c197 Mon Sep 17 00:00:00 2001 From: Coro <Coro365@users.noreply.github.com> Date: Tue, 26 May 2026 17:53:11 +0900 Subject: [PATCH 15/70] Fix bio text overflow (#39160) --- app/javascript/styles/mastodon/components.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 25265433faf..3848b76377a 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -10778,6 +10778,7 @@ noscript { -webkit-box-orient: vertical; max-height: 2 * 20px; overflow: hidden; + overflow-wrap: anywhere; p { margin-bottom: 0; From 041100365f22ebaea3b87798dcb42867bec660b0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 26 May 2026 12:19:51 +0200 Subject: [PATCH 16/70] Update dependency chromatic to v17 (#39094) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 21 +++++++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 2cc867c007f..3edde49a714 100644 --- a/package.json +++ b/package.json @@ -162,7 +162,7 @@ "@vitest/browser-playwright": "^4.1.0", "@vitest/coverage-v8": "^4.1.0", "@vitest/ui": "^4.1.0", - "chromatic": "^16.0.0", + "chromatic": "^17.0.0", "eslint": "^9.39.2", "eslint-import-resolver-typescript": "^4.2.5", "eslint-plugin-formatjs": "^6.0.0", diff --git a/yarn.lock b/yarn.lock index e596521858f..48f731f1eb4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2963,7 +2963,7 @@ __metadata: axios: "npm:^1.4.0" babel-plugin-transform-react-remove-prop-types: "npm:^0.4.24" blurhash: "npm:^2.0.5" - chromatic: "npm:^16.0.0" + chromatic: "npm:^17.0.0" classnames: "npm:^2.3.2" cocoon-js-vanilla: "npm:^1.5.1" color-blend: "npm:^4.0.0" @@ -6821,22 +6821,27 @@ __metadata: languageName: node linkType: hard -"chromatic@npm:^16.0.0": - version: 16.0.0 - resolution: "chromatic@npm:16.0.0" +"chromatic@npm:^17.0.0": + version: 17.0.0 + resolution: "chromatic@npm:17.0.0" + dependencies: + semver: "npm:^7.3.5" peerDependencies: "@chromatic-com/cypress": ^0.*.* || ^1.0.0 "@chromatic-com/playwright": ^0.*.* || ^1.0.0 + "@chromatic-com/vitest": ^0.*.* || ^1.0.0 peerDependenciesMeta: "@chromatic-com/cypress": optional: true "@chromatic-com/playwright": optional: true + "@chromatic-com/vitest": + optional: true bin: - chroma: dist/bin.js - chromatic: dist/bin.js - chromatic-cli: dist/bin.js - checksum: 10c0/ebebbf1c7d57e1ee9863997416c5125aab0a1886dce60fcb0358d34a51e0e1a45edc4635c8f8fb56d9facbcf21cd48014320c550f723b4791da51dde8552ee2b + chroma: dist/bin.cjs + chromatic: dist/bin.cjs + chromatic-cli: dist/bin.cjs + checksum: 10c0/962c86feec17b12757fa3327b7e98abff272a048c03227bb21ecb51c7f1d7ec3589386611ece8e2c413ac4049f26d71e9c9226a5fb7628fdcbb47e87905863a0 languageName: node linkType: hard From 9fe97e1ad6182ca62913e405a7e85746366e25a5 Mon Sep 17 00:00:00 2001 From: diondiondion <mail@diondiondion.com> Date: Tue, 26 May 2026 12:22:15 +0200 Subject: [PATCH 17/70] Accessibility: Mark pseudo element content in link footer as decorative (#39164) --- .../mastodon/features/ui/components/link_footer.module.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/javascript/mastodon/features/ui/components/link_footer.module.scss b/app/javascript/mastodon/features/ui/components/link_footer.module.scss index f2b094744e4..beb0173ffda 100644 --- a/app/javascript/mastodon/features/ui/components/link_footer.module.scss +++ b/app/javascript/mastodon/features/ui/components/link_footer.module.scss @@ -41,6 +41,10 @@ &:not(:last-child)::after { content: ' · '; + + @supports (content: 'x' / 'y') { + content: ' · ' / ''; + } } } From e1aa4e3a8c7401d9fd2ab0371e550dde0458c961 Mon Sep 17 00:00:00 2001 From: diondiondion <mail@diondiondion.com> Date: Tue, 26 May 2026 12:22:22 +0200 Subject: [PATCH 18/70] Accessibility: Add landmark regions to Web UI (#39133) --- .../compose/components/compose_form.jsx | 10 +++++++++- .../features/compose/components/search.tsx | 8 ++++++-- .../mastodon/features/compose/index.tsx | 17 ++++++++++------- .../mastodon/features/getting_started/index.tsx | 6 ++++-- .../features/navigation_panel/index.tsx | 14 +++++++++++--- .../features/ui/components/columns_area.tsx | 8 ++++---- .../features/ui/components/navigation_bar.tsx | 4 ++++ app/javascript/mastodon/locales/en.json | 2 ++ app/javascript/styles/mastodon/admin.scss | 2 +- app/views/layouts/admin.html.haml | 5 +++-- spec/system/unlogged_spec.rb | 2 +- 11 files changed, 55 insertions(+), 23 deletions(-) diff --git a/app/javascript/mastodon/features/compose/components/compose_form.jsx b/app/javascript/mastodon/features/compose/components/compose_form.jsx index a646a7efae1..2cc1f7915a5 100644 --- a/app/javascript/mastodon/features/compose/components/compose_form.jsx +++ b/app/javascript/mastodon/features/compose/components/compose_form.jsx @@ -248,7 +248,15 @@ class ComposeForm extends ImmutablePureComponent { const { intl, onPaste, onDrop, autoFocus, withoutNavigation, maxChars, isSubmitting } = this.props; return ( - <form className='compose-form' onSubmit={this.handleSubmit}> + <form + className='compose-form' + role='region' + aria-label={intl.formatMessage({ + id: 'tabs_bar.publish', + defaultMessage: 'New Post' + })} + onSubmit={this.handleSubmit} + > <ReplyIndicator /> {!withoutNavigation && <NavigationBar />} <Warning /> diff --git a/app/javascript/mastodon/features/compose/components/search.tsx b/app/javascript/mastodon/features/compose/components/search.tsx index c2855e8cb58..9c7baf50214 100644 --- a/app/javascript/mastodon/features/compose/components/search.tsx +++ b/app/javascript/mastodon/features/compose/components/search.tsx @@ -547,11 +547,15 @@ export const Search: React.FC<{ const searchOptionsHeading = useId(); return ( - <form ref={formRef} className={classNames('search', { active: expanded })}> + <form + role='search' + ref={formRef} + className={classNames('search', { active: expanded })} + > <input ref={searchInputRef} className='search__input' - type='text' + type='search' placeholder={intl.formatMessage( signedIn ? messages.placeholderSignedIn : messages.placeholder, )} diff --git a/app/javascript/mastodon/features/compose/index.tsx b/app/javascript/mastodon/features/compose/index.tsx index 0439606ac2c..eb44691997e 100644 --- a/app/javascript/mastodon/features/compose/index.tsx +++ b/app/javascript/mastodon/features/compose/index.tsx @@ -87,12 +87,11 @@ const Compose: React.FC<{ multiColumn: boolean }> = ({ multiColumn }) => { if (multiColumn) { return ( - <div - className='drawer' - role='region' - aria-label={intl.formatMessage(navbarMessages.publish)} - > - <nav className='drawer__header'> + <div className='drawer'> + <nav + className='drawer__header' + aria-label={intl.formatMessage(navbarMessages.advancedUiQuickLinks)} + > <Link to='/getting-started' className='drawer__tab' @@ -163,7 +162,11 @@ const Compose: React.FC<{ multiColumn: boolean }> = ({ multiColumn }) => { <Search singleColumn={false} /> - <div className='drawer__pager'> + <div + className='drawer__pager' + role='region' + aria-label={intl.formatMessage(navbarMessages.publish)} + > <div className='drawer__inner'> <ComposeFormContainer /> diff --git a/app/javascript/mastodon/features/getting_started/index.tsx b/app/javascript/mastodon/features/getting_started/index.tsx index 84c786fa068..5497b2de89e 100644 --- a/app/javascript/mastodon/features/getting_started/index.tsx +++ b/app/javascript/mastodon/features/getting_started/index.tsx @@ -4,14 +4,16 @@ import { Helmet } from '@unhead/react/helmet'; import { Column } from 'mastodon/components/column'; -import { NavigationPanel } from '../navigation_panel'; +import { NavigationPanel, messages } from '../navigation_panel'; import { LinkFooter } from '../ui/components/link_footer'; const GettingStarted: React.FC = () => { const intl = useIntl(); return ( <Column> - <NavigationPanel multiColumn /> + <nav aria-label={intl.formatMessage(messages.main)}> + <NavigationPanel multiColumn /> + </nav> <LinkFooter context='multi-column' /> diff --git a/app/javascript/mastodon/features/navigation_panel/index.tsx b/app/javascript/mastodon/features/navigation_panel/index.tsx index 3d038c22dd2..9ac2ee461ee 100644 --- a/app/javascript/mastodon/features/navigation_panel/index.tsx +++ b/app/javascript/mastodon/features/navigation_panel/index.tsx @@ -60,7 +60,7 @@ import { MoreLink } from './components/more_link'; import { SignInBanner } from './components/sign_in_banner'; import { Trends } from './components/trends'; -const messages = defineMessages({ +export const messages = defineMessages({ home: { id: 'tabs_bar.home', defaultMessage: 'Home' }, notifications: { id: 'tabs_bar.notifications', @@ -72,6 +72,12 @@ const messages = defineMessages({ id: 'column.firehose_singular', defaultMessage: 'Live feed', }, + main: { + id: 'navigation_bar.main', + defaultMessage: 'Main', + description: + 'Label for the main navigation; should not contain the word "navigation".', + }, direct: { id: 'navigation_bar.direct', defaultMessage: 'Private mentions' }, favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favorites' }, bookmarks: { id: 'navigation_bar.bookmarks', defaultMessage: 'Bookmarks' }, @@ -419,6 +425,7 @@ export const NavigationPanel: React.FC<{ multiColumn?: boolean }> = ({ }; export const CollapsibleNavigationPanel: React.FC = () => { + const intl = useIntl(); const open = useAppSelector((state) => state.navigation.open); const dispatch = useAppDispatch(); const openable = useBreakpoint('openable'); @@ -527,7 +534,8 @@ export const CollapsibleNavigationPanel: React.FC = () => { const showOverlay = openable && open; return ( - <div + <nav + aria-label={intl.formatMessage(messages.main)} className={classNames( 'columns-area__panels__pane columns-area__panels__pane--start columns-area__panels__pane--navigational', { 'columns-area__panels__pane--overlay': showOverlay }, @@ -541,6 +549,6 @@ export const CollapsibleNavigationPanel: React.FC = () => { > <NavigationPanel /> </animated.div> - </div> + </nav> ); }; diff --git a/app/javascript/mastodon/features/ui/components/columns_area.tsx b/app/javascript/mastodon/features/ui/components/columns_area.tsx index 6861410367c..ae735e196f3 100644 --- a/app/javascript/mastodon/features/ui/components/columns_area.tsx +++ b/app/javascript/mastodon/features/ui/components/columns_area.tsx @@ -108,12 +108,12 @@ export const ColumnsArea = forwardRef< </div> </div> - <div className='columns-area__panels__main'> + <main className='columns-area__panels__main'> <div className='tabs-bar__wrapper'> <TabsBarPortal /> </div> <div className='columns-area columns-area--mobile'>{children}</div> - </div> + </main> <CollapsibleNavigationPanel /> </div> @@ -121,7 +121,7 @@ export const ColumnsArea = forwardRef< } return ( - <div + <main className={classNames('columns-area', { unscrollable: isModalOpen })} ref={ref} tabIndex={isModalOpen ? undefined : 0} @@ -160,7 +160,7 @@ export const ColumnsArea = forwardRef< cloneElement(child, { multiColumn: true }), )} </ColumnIndexContext.Provider> - </div> + </main> ); }); diff --git a/app/javascript/mastodon/features/ui/components/navigation_bar.tsx b/app/javascript/mastodon/features/ui/components/navigation_bar.tsx index ec45e395b21..c3f9373966f 100644 --- a/app/javascript/mastodon/features/ui/components/navigation_bar.tsx +++ b/app/javascript/mastodon/features/ui/components/navigation_bar.tsx @@ -31,6 +31,10 @@ export const messages = defineMessages({ defaultMessage: 'Notifications', }, menu: { id: 'tabs_bar.menu', defaultMessage: 'Menu' }, + advancedUiQuickLinks: { + id: 'tabs_bar.quick_links', + defaultMessage: 'Quick links', + }, }); const IconLabelButton: React.FC<{ diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index 057b235576e..df12731edaf 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -908,6 +908,7 @@ "navigation_bar.live_feed_local": "Live feed (local)", "navigation_bar.live_feed_public": "Live feed (public)", "navigation_bar.logout": "Logout", + "navigation_bar.main": "Main", "navigation_bar.moderation": "Moderation", "navigation_bar.more": "More", "navigation_bar.mutes": "Muted users", @@ -1305,6 +1306,7 @@ "tabs_bar.menu": "Menu", "tabs_bar.notifications": "Notifications", "tabs_bar.publish": "New Post", + "tabs_bar.quick_links": "Quick links", "tabs_bar.search": "Search", "tag.remove": "Remove", "terms_of_service.effective_as_of": "Effective as of {date}", diff --git a/app/javascript/styles/mastodon/admin.scss b/app/javascript/styles/mastodon/admin.scss index 887f14360a1..0abcefaa4b7 100644 --- a/app/javascript/styles/mastodon/admin.scss +++ b/app/javascript/styles/mastodon/admin.scss @@ -411,7 +411,7 @@ $content-width: 840px; display: flex; } - & > ul { + & > nav > ul { display: none; &.visible { diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml index 039ca88f7e3..4bb05b892ab 100644 --- a/app/views/layouts/admin.html.haml +++ b/app/views/layouts/admin.html.haml @@ -8,7 +8,7 @@ - content_for :content do %a.navigation-skip-link{ href: '#content' }= t('admin.skip_to_content') .admin-wrapper - %nav.sidebar-wrapper + %header.sidebar-wrapper .sidebar-wrapper__inner .sidebar = link_to root_path do @@ -23,7 +23,8 @@ = material_symbol 'menu' = material_symbol 'close' - = render_navigation + %nav + = render_navigation %main.content-wrapper#content .content diff --git a/spec/system/unlogged_spec.rb b/spec/system/unlogged_spec.rb index 26d1bd45426..90db5fb40e4 100644 --- a/spec/system/unlogged_spec.rb +++ b/spec/system/unlogged_spec.rb @@ -12,6 +12,6 @@ RSpec.describe 'UnloggedBrowsing', :js, :streaming do it 'loads the home page' do expect(subject).to have_css('div.app-holder') - expect(subject).to have_css('div.columns-area__panels__main') + expect(subject).to have_css('main.columns-area__panels__main') end end From cc03e381efb0a264692d2a40193db56ad01cde58 Mon Sep 17 00:00:00 2001 From: diondiondion <mail@diondiondion.com> Date: Tue, 26 May 2026 12:22:38 +0200 Subject: [PATCH 19/70] Accessibility: Fix broken aria label & description in `CollectionListItem` (#39165) --- .../collections/components/collection_list_item.tsx | 10 ++++++---- .../collections/components/collection_lockup.tsx | 6 ++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/app/javascript/mastodon/features/collections/components/collection_list_item.tsx b/app/javascript/mastodon/features/collections/components/collection_list_item.tsx index 8169544cb86..c1b32cac279 100644 --- a/app/javascript/mastodon/features/collections/components/collection_list_item.tsx +++ b/app/javascript/mastodon/features/collections/components/collection_list_item.tsx @@ -27,14 +27,14 @@ export const CollectionListItem: React.FC<CollectionListItemProps> = ({ ...otherProps }) => { const uniqueId = useId(); - const linkId = `${uniqueId}-link`; - const infoId = `${uniqueId}-info`; + const titleId = `${uniqueId}-title`; + const subtitleId = `${uniqueId}-info`; return ( <Article focusable - aria-labelledby={linkId} - aria-describedby={infoId} + aria-labelledby={titleId} + aria-describedby={subtitleId} aria-posinset={positionInList} aria-setsize={listSize} > @@ -52,6 +52,8 @@ export const CollectionListItem: React.FC<CollectionListItemProps> = ({ className={classes.menuButton} /> } + titleId={titleId} + subtitleId={subtitleId} {...otherProps} /> </Article> diff --git a/app/javascript/mastodon/features/collections/components/collection_lockup.tsx b/app/javascript/mastodon/features/collections/components/collection_lockup.tsx index e16d49e7922..5250ea55047 100644 --- a/app/javascript/mastodon/features/collections/components/collection_lockup.tsx +++ b/app/javascript/mastodon/features/collections/components/collection_lockup.tsx @@ -48,6 +48,8 @@ export interface CollectionLockupProps { sideContent?: React.ReactNode; className?: string; headingLevel?: 'h2' | 'h3' | 'h4'; + titleId?: string; + subtitleId?: string; } export const CollectionLockup: React.FC<CollectionLockupProps> = ({ @@ -56,6 +58,8 @@ export const CollectionLockup: React.FC<CollectionLockupProps> = ({ withTimestamp, sideContent, headingLevel = 'h3', + titleId, + subtitleId, className, }) => { const { id, name } = collection; @@ -74,6 +78,7 @@ export const CollectionLockup: React.FC<CollectionLockupProps> = ({ <ListItemLink as={headingLevel} to={getCollectionPath(id)} + id={titleId} subtitle={ <CollectionInfo collection={collection} @@ -81,6 +86,7 @@ export const CollectionLockup: React.FC<CollectionLockupProps> = ({ withTimestamp={withTimestamp} /> } + subtitleId={subtitleId} > {name} </ListItemLink> From 0275a978888516e68256acefd76f2238c99c9b01 Mon Sep 17 00:00:00 2001 From: diondiondion <mail@diondiondion.com> Date: Tue, 26 May 2026 12:24:38 +0200 Subject: [PATCH 20/70] Don't open account hover card unless preceded by mouse movement (#39166) --- .../mastodon/components/hover_card_controller.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/javascript/mastodon/components/hover_card_controller.tsx b/app/javascript/mastodon/components/hover_card_controller.tsx index a0c704a4e7c..dd7ff3b3e7e 100644 --- a/app/javascript/mastodon/components/hover_card_controller.tsx +++ b/app/javascript/mastodon/components/hover_card_controller.tsx @@ -144,11 +144,16 @@ export const HoverCardController: React.FC = () => { setScrollTimeout(handleScrollEnd, 100); }; - const handleMouseMove = () => { + const handleMouseMove = (e: MouseEvent) => { if (isUsingTouch) { isUsingTouch = false; } + const hasMoved = Math.max(e.movementX, e.movementY) > 0; + if (!hasMoved) { + return; + } + delayEnterTimeout(enterDelay); cancelMoveTimeout(); From f6d1795da5e42b9436b6f4bf49d25a3f29d34e25 Mon Sep 17 00:00:00 2001 From: Eugen Rochko <eugen@zeonfederated.com> Date: Tue, 26 May 2026 13:51:25 +0200 Subject: [PATCH 21/70] Fix some server-side limits not being respected in web UI (#39163) --- app/javascript/mastodon/actions/compose.js | 2 +- .../mastodon/features/compose/components/poll_form.jsx | 2 +- .../features/compose/containers/upload_button_container.js | 2 +- app/javascript/mastodon/features/ui/index.jsx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/javascript/mastodon/actions/compose.js b/app/javascript/mastodon/actions/compose.js index 06335f9fbff..b4be55cbfea 100644 --- a/app/javascript/mastodon/actions/compose.js +++ b/app/javascript/mastodon/actions/compose.js @@ -327,7 +327,7 @@ export function uploadCompose(files) { dispatch(showAlert({ message: messages.uploadQuote })); return; } - const uploadLimit = getState().getIn(['server', 'server', 'configuration', 'statuses', 'max_media_attachments']); + const uploadLimit = getState().getIn(['server', 'server', 'item', 'configuration', 'statuses', 'max_media_attachments']); const media = getState().getIn(['compose', 'media_attachments']); const pending = getState().getIn(['compose', 'pending_media_attachments']); const progress = new Array(files.length).fill(0); diff --git a/app/javascript/mastodon/features/compose/components/poll_form.jsx b/app/javascript/mastodon/features/compose/components/poll_form.jsx index e8d53311965..a2036d0cc51 100644 --- a/app/javascript/mastodon/features/compose/components/poll_form.jsx +++ b/app/javascript/mastodon/features/compose/components/poll_form.jsx @@ -58,7 +58,7 @@ const Option = ({ multipleChoice, index, title, autoFocus }) => { const dispatch = useDispatch(); const suggestions = useSelector(state => state.getIn(['compose', 'suggestions'])); const lang = useSelector(state => state.getIn(['compose', 'language'])); - const maxOptions = useSelector(state => state.getIn(['server', 'server', 'configuration', 'polls', 'max_options'])); + const maxOptions = useSelector(state => state.getIn(['server', 'server', 'item', 'configuration', 'polls', 'max_options'])); const handleChange = useCallback(({ target: { value } }) => { dispatch(changePollOption(index, value, maxOptions)); diff --git a/app/javascript/mastodon/features/compose/containers/upload_button_container.js b/app/javascript/mastodon/features/compose/containers/upload_button_container.js index a5ae874b066..a332e99c087 100644 --- a/app/javascript/mastodon/features/compose/containers/upload_button_container.js +++ b/app/javascript/mastodon/features/compose/containers/upload_button_container.js @@ -9,7 +9,7 @@ const mapStateToProps = state => { const readyAttachmentsSize = state.getIn(['compose', 'media_attachments']).size ?? 0; const pendingAttachmentsSize = state.getIn(['compose', 'pending_media_attachments']).size ?? 0; const attachmentsSize = readyAttachmentsSize + pendingAttachmentsSize; - const isOverLimit = attachmentsSize > state.getIn(['server', 'server', 'configuration', 'statuses', 'max_media_attachments'])-1; + const isOverLimit = attachmentsSize > state.getIn(['server', 'server', 'item', 'configuration', 'statuses', 'max_media_attachments'])-1; const hasVideoOrAudio = state.getIn(['compose', 'media_attachments']).some(m => ['video', 'audio'].includes(m.get('type'))); const hasQuote = !!state.compose.get('quoted_status_id'); diff --git a/app/javascript/mastodon/features/ui/index.jsx b/app/javascript/mastodon/features/ui/index.jsx index 4f398b510cb..733a91d041c 100644 --- a/app/javascript/mastodon/features/ui/index.jsx +++ b/app/javascript/mastodon/features/ui/index.jsx @@ -105,7 +105,7 @@ const mapStateToProps = state => ({ hasComposingContents: state.getIn(['compose', 'text']).trim().length !== 0 || state.getIn(['compose', 'media_attachments']).size > 0 || state.getIn(['compose', 'poll']) !== null || state.getIn(['compose', 'quoted_status_id']) !== null, canUploadMore: !state.getIn(['compose', 'media_attachments']).some(x => ['audio', 'video'].includes(x.get('type'))) - && state.getIn(['compose', 'media_attachments']).size < state.getIn(['server', 'server', 'configuration', 'statuses', 'max_media_attachments']), + && state.getIn(['compose', 'media_attachments']).size < state.getIn(['server', 'server', 'item', 'configuration', 'statuses', 'max_media_attachments']), isUploadEnabled: state.getIn(['compose', 'isDragDisabled']) !== true, firstLaunch: state.getIn(['settings', 'introductionVersion'], 0) < INTRODUCTION_VERSION, From 07d099cbf7b646b7dc715c3bfe3a8ea453e9eafb Mon Sep 17 00:00:00 2001 From: Eugen Rochko <eugen@zeonfederated.com> Date: Tue, 26 May 2026 14:36:54 +0200 Subject: [PATCH 22/70] Add new overview landing page setting (#39074) --- app/javascript/mastodon/actions/server.ts | 14 ++ .../features/custom_homepage/about.tsx | 75 +++++++++ .../custom_homepage/components/footer.tsx | 39 +++++ .../custom_homepage/components/header.tsx | 25 +++ .../features/custom_homepage/index.tsx | 71 +++++++++ .../custom_homepage/latest_activity.tsx | 35 +++++ .../custom_homepage/styles.module.scss | 145 ++++++++++++++++++ .../features/ui/components/columns_area.tsx | 24 ++- .../ui/containers/status_list_container.js | 21 ++- app/javascript/mastodon/features/ui/index.jsx | 24 ++- app/javascript/mastodon/locales/en.json | 6 + app/models/form/admin_settings.rb | 2 +- .../admin/settings/branding/show.html.haml | 5 +- config/locales/en.yml | 12 +- config/routes/web_app.rb | 2 + 15 files changed, 483 insertions(+), 17 deletions(-) create mode 100644 app/javascript/mastodon/features/custom_homepage/about.tsx create mode 100644 app/javascript/mastodon/features/custom_homepage/components/footer.tsx create mode 100644 app/javascript/mastodon/features/custom_homepage/components/header.tsx create mode 100644 app/javascript/mastodon/features/custom_homepage/index.tsx create mode 100644 app/javascript/mastodon/features/custom_homepage/latest_activity.tsx create mode 100644 app/javascript/mastodon/features/custom_homepage/styles.module.scss diff --git a/app/javascript/mastodon/actions/server.ts b/app/javascript/mastodon/actions/server.ts index 4e4795c1233..b301919b237 100644 --- a/app/javascript/mastodon/actions/server.ts +++ b/app/javascript/mastodon/actions/server.ts @@ -16,19 +16,33 @@ export const fetchServer = createDataLoadingThunk( dispatch(importFetchedAccount(instance.contact.account)); } }, + { + condition: (_, { getState }) => !getState().server.server.isLoading, + }, ); export const fetchExtendedDescription = createDataLoadingThunk( 'server/extended_description', () => apiGetExtendedDescription(), + { + condition: (_, { getState }) => + !getState().server.extendedDescription.isLoading, + }, ); export const fetchServerTranslationLanguages = createDataLoadingThunk( 'server/translation_languages', () => apiGetTranslationLanguages(), + { + condition: (_, { getState }) => + !getState().server.translationLanguages.isLoading, + }, ); export const fetchDomainBlocks = createDataLoadingThunk( 'server/domain_blocks', () => apiGetDomainBlocks(), + { + condition: (_, { getState }) => !getState().server.domainBlocks.isLoading, + }, ); diff --git a/app/javascript/mastodon/features/custom_homepage/about.tsx b/app/javascript/mastodon/features/custom_homepage/about.tsx new file mode 100644 index 00000000000..7ec3a8e442c --- /dev/null +++ b/app/javascript/mastodon/features/custom_homepage/about.tsx @@ -0,0 +1,75 @@ +import { useEffect } from 'react'; + +import { FormattedMessage } from 'react-intl'; + +import { fetchExtendedDescription } from 'mastodon/actions/server'; +import { Account } from 'mastodon/components/account'; +import { Skeleton } from 'mastodon/components/skeleton'; +import { useAppSelector, useAppDispatch } from 'mastodon/store'; + +import classes from './styles.module.scss'; + +const Placeholder = () => ( + <div className={classes.placeholder}> + <Skeleton width='100%' /> + <Skeleton width='100%' /> + <Skeleton width='100%' /> + </div> +); + +export const About = () => { + const dispatch = useAppDispatch(); + const server = useAppSelector((state) => state.server.server); + const extendedDescription = useAppSelector( + (state) => state.server.extendedDescription, + ); + + const accountId = server.item?.contact.account?.id ?? ''; + const isLoading = extendedDescription.isLoading; + const hasContent = (extendedDescription.item?.content.length ?? 0) > 0; + const content = extendedDescription.item?.content ?? ''; + + useEffect(() => { + void dispatch(fetchExtendedDescription()); + }, [dispatch]); + + return ( + <> + <div className={classes.block}> + <h2> + <FormattedMessage + id='custom_homepage.administered_by' + defaultMessage='Administered by' + /> + </h2> + <Account id={accountId} size={36} minimal /> + </div> + + <div className={classes.block}> + <h2> + <FormattedMessage + id='custom_homepage.about_this_server' + defaultMessage='About this server' + /> + </h2> + {isLoading ? ( + <Placeholder /> + ) : hasContent ? ( + <div + className='prose' + dangerouslySetInnerHTML={{ __html: content }} + /> + ) : ( + <div className='prose'> + <p> + <FormattedMessage + id='about.not_available' + defaultMessage='This information has not been made available on this server.' + /> + </p> + </div> + )} + </div> + </> + ); +}; diff --git a/app/javascript/mastodon/features/custom_homepage/components/footer.tsx b/app/javascript/mastodon/features/custom_homepage/components/footer.tsx new file mode 100644 index 00000000000..b1b69cfc76e --- /dev/null +++ b/app/javascript/mastodon/features/custom_homepage/components/footer.tsx @@ -0,0 +1,39 @@ +import { useEffect } from 'react'; + +import { FormattedMessage } from 'react-intl'; + +import { Link } from 'react-router-dom'; + +import { fetchServer } from 'mastodon/actions/server'; +import { useAppDispatch, useAppSelector } from 'mastodon/store'; + +import classes from '../styles.module.scss'; + +export const Footer = () => { + const dispatch = useAppDispatch(); + const server = useAppSelector((state) => state.server.server); + const email = server.item?.contact.email ?? ''; + + useEffect(() => { + void dispatch(fetchServer()); + }, [dispatch]); + + return ( + <footer className={classes.minimalFooter}> + <div className={classes.contact}> + <FormattedMessage + id='custom_homepage.contact' + defaultMessage='Contact:' + /> + <a href={`mailto:${email}`}>{email}</a> + </div> + + <Link to='/privacy-policy' rel='privacy-policy'> + <FormattedMessage + id='footer.privacy_policy' + defaultMessage='Privacy policy' + /> + </Link> + </footer> + ); +}; diff --git a/app/javascript/mastodon/features/custom_homepage/components/header.tsx b/app/javascript/mastodon/features/custom_homepage/components/header.tsx new file mode 100644 index 00000000000..dd4b7969c35 --- /dev/null +++ b/app/javascript/mastodon/features/custom_homepage/components/header.tsx @@ -0,0 +1,25 @@ +import { FormattedMessage } from 'react-intl'; + +import { Link } from 'react-router-dom'; + +import { domain, sso_redirect } from 'mastodon/initial_state'; + +import classes from '../styles.module.scss'; + +export const Header = () => ( + <div className={classes.minimalHeader}> + <div className={classes.leftSide}> + <Link to='/overview'>{domain}</Link> + </div> + + <div className={classes.rightSide}> + <a + href={sso_redirect ?? '/auth/sign_in'} + data-method={sso_redirect ? 'post' : undefined} + className='button button-secondary' + > + <FormattedMessage id='sign_in_banner.sign_in' defaultMessage='Login' /> + </a> + </div> + </div> +); diff --git a/app/javascript/mastodon/features/custom_homepage/index.tsx b/app/javascript/mastodon/features/custom_homepage/index.tsx new file mode 100644 index 00000000000..5fc75108f11 --- /dev/null +++ b/app/javascript/mastodon/features/custom_homepage/index.tsx @@ -0,0 +1,71 @@ +import { useEffect } from 'react'; + +import { FormattedMessage } from 'react-intl'; + +import { Route, Switch, useRouteMatch } from 'react-router-dom'; + +import { Helmet } from '@unhead/react/helmet'; + +import { fetchServer } from 'mastodon/actions/server'; +import { ServerHeroImage } from 'mastodon/components/server_hero_image'; +import { TabLink, TabList } from 'mastodon/components/tab_list'; +import { useAppSelector, useAppDispatch } from 'mastodon/store'; + +import { About } from './about'; +import { LatestActivity } from './latest_activity'; +import classes from './styles.module.scss'; + +export const CustomHomepage: React.FC = () => { + const dispatch = useAppDispatch(); + const server = useAppSelector((state) => state.server.server); + const { path } = useRouteMatch(); + + useEffect(() => { + void dispatch(fetchServer()); + }, [dispatch]); + + return ( + <div className={classes.page}> + <ServerHeroImage + alt={server.item?.thumbnail.description ?? ''} + blurhash={server.item?.thumbnail.blurhash ?? ''} + src={server.item?.thumbnail.url ?? ''} + srcSet={Object.keys(server.item?.thumbnail.versions ?? {}) + .map( + (key) => + `${server.item?.thumbnail.versions?.[key]} ${key.replace('@', '')}`, + ) + .join(', ')} + className={classes.header} + /> + + <div className={classes.topSection}> + <h1>{server.item?.domain}</h1> + <p>{server.item?.description}</p> + </div> + + <TabList> + <TabLink to={path} exact> + <FormattedMessage + id='custom_homepage.latest_activity' + defaultMessage='Latest activity' + /> + </TabLink> + + <TabLink to={`${path}/about`} exact> + <FormattedMessage id='custom_homepage.about' defaultMessage='About' /> + </TabLink> + </TabList> + + <Switch> + <Route path={path} exact component={LatestActivity} /> + <Route path={`${path}/about`} exact component={About} /> + </Switch> + + <Helmet> + <title>{server.item?.domain} + + +
+ ); +}; diff --git a/app/javascript/mastodon/features/custom_homepage/latest_activity.tsx b/app/javascript/mastodon/features/custom_homepage/latest_activity.tsx new file mode 100644 index 00000000000..9deac2db4c8 --- /dev/null +++ b/app/javascript/mastodon/features/custom_homepage/latest_activity.tsx @@ -0,0 +1,35 @@ +import { useEffect } from 'react'; + +import { FormattedMessage } from 'react-intl'; + +import { expandCommunityTimeline } from 'mastodon/actions/timelines'; +import { Callout } from 'mastodon/components/callout'; +import StatusListContainer from 'mastodon/features/ui/containers/status_list_container'; +import { useAppDispatch } from 'mastodon/store'; + +import classes from './styles.module.scss'; + +export const LatestActivity = () => { + const dispatch = useAppDispatch(); + + useEffect(() => { + void dispatch(expandCommunityTimeline()); + }, [dispatch]); + + return ( + + + + } + scrollKey='custom_homepage' + timelineId='community' + maxItems={40} + bindToDocument + /> + ); +}; diff --git a/app/javascript/mastodon/features/custom_homepage/styles.module.scss b/app/javascript/mastodon/features/custom_homepage/styles.module.scss new file mode 100644 index 00000000000..bbf834ffc9f --- /dev/null +++ b/app/javascript/mastodon/features/custom_homepage/styles.module.scss @@ -0,0 +1,145 @@ +.page { + border-radius: 16px; + border: 1px solid var(--color-border-primary); + background: var(--color-bg-primary); + min-height: 100%; + + :global(.item-list) article:last-child :global(.status) { + border-bottom: 0; + } + + @media screen and (width <= 1175px) { + border-radius: 0; + } +} + +.header { + aspect-ratio: 40/21; + border-radius: 16px 16px 0 0; + + @media screen and (width <= 1175px) { + border-radius: 0; + } +} + +.banner { + margin: 16px; + margin-bottom: 0; +} + +.topSection { + display: flex; + padding: 16px; + flex-direction: column; + gap: 8px; + color: var(--color-text-primary); + + h1 { + font-size: 24px; + font-weight: 500; + line-height: 30px; + letter-spacing: -0.12px; + } + + p { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + font-size: 16px; + line-height: 24px; + text-overflow: ellipsis; + } +} + +.block { + padding: 16px; + + h2 { + font-size: 16px; + font-weight: 500; + line-height: 22.4px; + margin-bottom: 8px; + } + + :global(.account) { + border: 1px solid var(--color-border-primary); + padding: 18px 16px; + border-radius: 12px; + + --avatar-border-radius: 50%; + } +} + +.placeholder { + padding: 4px 0; + display: flex; + flex-direction: column; + gap: 12px; + + :global(.skeleton) { + height: 40px; + border-radius: 12px; + background: var(--color-bg-overlay-highlight); + } +} + +.minimalHeader { + padding-top: 24px; + padding-bottom: 12px; + display: flex; + align-items: center; + + @media screen and (width <= 1175px) { + padding-inline-start: 12px; + padding-inline-end: 12px; + } +} + +.leftSide { + font-size: 15px; + font-weight: 600; + max-width: 300px; + + a { + text-decoration: none; + color: inherit; + } +} + +.rightSide { + display: flex; + justify-content: flex-end; + align-items: center; + gap: 4px; + flex: 1 0 0; +} + +.minimalFooter { + display: flex; + justify-content: space-between; + align-items: center; + color: var(--color-text-secondary); + font-size: 16px; + font-weight: 500; + line-height: 22.4px; + padding-top: 28px; + padding-bottom: 54px; + gap: 8px; + flex-wrap: wrap; + + a { + color: inherit; + text-decoration: underline; + } + + @media screen and (width <= 1175px) { + justify-content: center; + padding-inline-start: 12px; + padding-inline-end: 12px; + } +} + +.contact { + display: flex; + gap: 8px; +} diff --git a/app/javascript/mastodon/features/ui/components/columns_area.tsx b/app/javascript/mastodon/features/ui/components/columns_area.tsx index ae735e196f3..f5ab3de849e 100644 --- a/app/javascript/mastodon/features/ui/components/columns_area.tsx +++ b/app/javascript/mastodon/features/ui/components/columns_area.tsx @@ -12,6 +12,8 @@ import classNames from 'classnames'; import type { List, Record } from 'immutable'; import { useAppSelector } from '@/mastodon/store'; +import { Footer } from 'mastodon/features/custom_homepage/components/footer'; +import { Header } from 'mastodon/features/custom_homepage/components/header'; import { CollapsibleNavigationPanel } from 'mastodon/features/navigation_panel'; import { useBreakpoint } from '../hooks/useBreakpoint'; @@ -85,9 +87,10 @@ export const ColumnsArea = forwardRef< HTMLDivElement, { singleColumn?: boolean; + minimalShell?: boolean; children: React.ReactElement | React.ReactElement[]; } ->(({ children, singleColumn }, ref) => { +>(({ children, minimalShell, singleColumn }, ref) => { const renderComposePanel = !useBreakpoint('full'); const columns = useAppSelector((state) => (state.settings as Record<{ columns: List> }>).get( @@ -98,6 +101,24 @@ export const ColumnsArea = forwardRef< (state) => !state.modal.get('stack').isEmpty(), ); + if (minimalShell) { + return ( +
+
+
+ +
+ +
+ +
{children}
+ +
+
+
+ ); + } + if (singleColumn) { return (
@@ -112,6 +133,7 @@ export const ColumnsArea = forwardRef<
+
{children}
diff --git a/app/javascript/mastodon/features/ui/containers/status_list_container.js b/app/javascript/mastodon/features/ui/containers/status_list_container.js index 1e21730a007..8abbbefe146 100644 --- a/app/javascript/mastodon/features/ui/containers/status_list_container.js +++ b/app/javascript/mastodon/features/ui/containers/status_list_container.js @@ -11,7 +11,15 @@ import { me } from '@/mastodon/initial_state'; const makeGetStatusIds = (pending = false) => createSelector([ (state, { type }) => state.getIn(['settings', type], ImmutableMap()), - (state, { type }) => state.getIn(['timelines', type, pending ? 'pendingItems' : 'items'], ImmutableList()), + (state, { type, maxItems }) => { + const items = state.getIn(['timelines', type, pending ? 'pendingItems' : 'items'], ImmutableList()); + + if (maxItems) { + return items.take(maxItems); + } + + return items; + }, (state) => state.get('statuses'), ], (columnSettings, statusIds, statuses) => { return statusIds.filter(id => { @@ -41,8 +49,15 @@ const makeMapStateToProps = () => { const getStatusIds = makeGetStatusIds(); const getPendingStatusIds = makeGetStatusIds(true); - const mapStateToProps = (state, { timelineId, initialLoadingState = true }) => ({ - statusIds: getStatusIds(state, { type: timelineId }), + /** + * @param {import('mastodon/store').RootState} state + * @param {Object} props + * @param {string} props.timelineId + * @param {boolean} [props.initialLoadingState] + * @param {number} [props.maxItems] + */ + const mapStateToProps = (state, { timelineId, initialLoadingState = true, maxItems }) => ({ + statusIds: getStatusIds(state, { type: timelineId, maxItems }), lastId: state.getIn(['timelines', timelineId, 'items'])?.last(), isLoading: state.getIn(['timelines', timelineId, 'isLoading'], initialLoadingState), isPartial: state.getIn(['timelines', timelineId, 'isPartial'], false), diff --git a/app/javascript/mastodon/features/ui/index.jsx b/app/javascript/mastodon/features/ui/index.jsx index 733a91d041c..1bf0842cb8c 100644 --- a/app/javascript/mastodon/features/ui/index.jsx +++ b/app/javascript/mastodon/features/ui/index.jsx @@ -29,7 +29,7 @@ import { uploadCompose, resetCompose, changeComposeSpoilerness } from '../../act import { clearHeight } from '../../actions/height_cache'; import { fetchServer, fetchServerTranslationLanguages } from '../../actions/server'; import { expandHomeTimeline } from '../../actions/timelines'; -import { initialState, me, owner, singleUserMode, trendsEnabled, landingPage, localLiveFeedAccess, disableHoverCards } from '../../initial_state'; +import { initialState, me, owner, singleUserMode, trendsEnabled, landingPage, localLiveFeedAccess, disableHoverCards, domain } from '../../initial_state'; import BundleColumnError from './components/bundle_column_error'; import { NavigationBar } from './components/navigation_bar'; @@ -88,6 +88,7 @@ import { import { ColumnsContextProvider } from './util/columns_context'; import { focusColumn, getFocusedItemIndex, focusItemSibling, focusFirstItem } from './util/focusUtils'; import { WrappedSwitch, WrappedRoute } from './util/react_router_helpers'; +import { CustomHomepage } from 'mastodon/features/custom_homepage'; // Dummy import, to make sure that ends up in the application bundle. // Without this it ends up in ~8 very commonly used bundles. @@ -177,13 +178,15 @@ class SwitchingColumnsArea extends PureComponent { rootRedirect = '/explore'; } else if (localLiveFeedAccess === 'public' && landingPage === 'local_feed') { rootRedirect = '/public/local'; + } else if (landingPage === 'overview') { + rootRedirect = '/overview'; } else { rootRedirect = '/about'; } return ( - + @@ -262,6 +265,8 @@ class SwitchingColumnsArea extends PureComponent { + + @@ -633,13 +638,18 @@ class UI extends PureComponent { cheat: this.handleDonate, }; + const minimalShell = !this.props.identity.signedIn && landingPage === 'overview'; + return (
- + {!minimalShell && ( + + )} + - + {!minimalShell && } {layout !== 'mobile' && } {!disableHoverCards && } diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index df12731edaf..b97260173b8 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -584,6 +584,12 @@ "copy_icon_button.copy_this_text": "Copy link to clipboard", "copypaste.copied": "Copied", "copypaste.copy_to_clipboard": "Copy to clipboard", + "custom_homepage.about": "About", + "custom_homepage.about_this_server": "About this server", + "custom_homepage.administered_by": "Administered by", + "custom_homepage.contact": "Contact:", + "custom_homepage.latest_activity": "Latest activity", + "custom_homepage.these_are_the_latest_posts": "These are the latest 40 posts from accounts on this server.", "directory.federated": "From known fediverse", "directory.local": "From {domain} only", "directory.new_arrivals": "New arrivals", diff --git a/app/models/form/admin_settings.rb b/app/models/form/admin_settings.rb index 0ad53354192..5e97151438f 100644 --- a/app/models/form/admin_settings.rb +++ b/app/models/form/admin_settings.rb @@ -94,7 +94,7 @@ class Form::AdminSettings REGISTRATION_MODES = %w(open approved none).freeze FEED_ACCESS_MODES = %w(public authenticated disabled).freeze ALTERNATE_FEED_ACCESS_MODES = %w(public authenticated).freeze - LANDING_PAGE = %w(trends about local_feed).freeze + LANDING_PAGE = %w(trends overview local_feed about).freeze attr_accessor(*KEYS) diff --git a/app/views/admin/settings/branding/show.html.haml b/app/views/admin/settings/branding/show.html.haml index 65aae77d5f0..9e9653abf12 100644 --- a/app/views/admin/settings/branding/show.html.haml +++ b/app/views/admin/settings/branding/show.html.haml @@ -75,10 +75,11 @@ .fields-row = f.input :landing_page, + as: :radio_buttons, collection: f.object.class::LANDING_PAGE, include_blank: false, - label_method: ->(page) { I18n.t("admin.settings.landing_page.values.#{page}") }, - wrapper: :with_label + label_method: ->(page) { safe_join([I18n.t("admin.settings.landing_page.values.#{page}"), content_tag(:span, I18n.t("admin.settings.landing_page.hints.#{page}_html"), class: 'hint')]) }, + wrapper: :with_block_label .actions = f.button :button, t('generic.save_changes'), type: :submit diff --git a/config/locales/en.yml b/config/locales/en.yml index 2ed8dd1c1a7..f47eac1fe12 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -956,10 +956,16 @@ en: disabled: Require specific user role public: Everyone landing_page: + hints: + about_html: A page with the description, contact information, rules and other information regarding this server. + local_feed_html: A live feed featuring most recent posts by users on this server. + overview_html: A page showcasing the description of your server alongside the most recent local posts by users on this server. + trends_html: A page featuring what's popular on this server right now. values: - about: About - local_feed: Local feed - trends: Trends + about: About page + local_feed: Local live feed + overview: Overview + trends: Trending registrations: moderation_recommandation: Please make sure you have an adequate and reactive moderation team before you open registrations to everyone! preamble: Control who can create an account on your server. diff --git a/config/routes/web_app.rb b/config/routes/web_app.rb index cb85dc87539..22814f294c0 100644 --- a/config/routes/web_app.rb +++ b/config/routes/web_app.rb @@ -33,4 +33,6 @@ /search /start/(*any) /statuses/(*any) + /overview + /overview/about ).each { |path| get path, to: 'home#index' } From 3559efe526c144e128607cb60b556c366adba0c3 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 26 May 2026 15:42:55 +0200 Subject: [PATCH 23/70] Fix missing padding on email subscription form (#39162) --- .../mastodon/components/account_header/styles.module.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/app/javascript/mastodon/components/account_header/styles.module.scss b/app/javascript/mastodon/components/account_header/styles.module.scss index 2daf3867346..ab751ce170e 100644 --- a/app/javascript/mastodon/components/account_header/styles.module.scss +++ b/app/javascript/mastodon/components/account_header/styles.module.scss @@ -480,6 +480,7 @@ $button-fallback-breakpoint: $button-breakpoint + 55px; justify-content: center; align-items: flex-start; margin: 16px 0; + padding: 16px; } .bannerBaseCentered { From c39072ad9d2b531a04c0192f06018fbd8d737f69 Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 26 May 2026 16:00:23 +0200 Subject: [PATCH 24/70] Emojis: Fix bug with search + improve custom tokenization (#39167) --- .../mastodon/actions/importer/emoji.ts | 9 ++++++ .../mastodon/features/emoji/database.ts | 31 +++++++++++++++---- .../mastodon/features/emoji/index.ts | 2 ++ .../mastodon/features/emoji/normalize.ts | 14 ++++++--- .../mastodon/features/emoji/picker.ts | 11 ++++++- .../mastodon/hooks/useCustomEmojis.ts | 2 +- 6 files changed, 56 insertions(+), 13 deletions(-) diff --git a/app/javascript/mastodon/actions/importer/emoji.ts b/app/javascript/mastodon/actions/importer/emoji.ts index 9e06c88f66e..e9356ab6215 100644 --- a/app/javascript/mastodon/actions/importer/emoji.ts +++ b/app/javascript/mastodon/actions/importer/emoji.ts @@ -1,5 +1,8 @@ import type { ApiCustomEmojiJSON } from '@/mastodon/api_types/custom_emoji'; import { loadCustomEmoji } from '@/mastodon/features/emoji'; +import { emojiLogger } from '@/mastodon/features/emoji/utils'; + +const log = emojiLogger('actions'); export async function importCustomEmoji(emojis: ApiCustomEmojiJSON[]) { if (emojis.length === 0) { @@ -18,5 +21,11 @@ export async function importCustomEmoji(emojis: ApiCustomEmojiJSON[]) { if (existingEmojis.length < emojis.length) { await clearCache('custom'); await loadCustomEmoji(); + + const { reloadCustomEmojis } = + await import('@/mastodon/features/emoji/picker'); + await reloadCustomEmojis(); + + log('Custom emojis updated, reloaded cache and picker data.'); } } diff --git a/app/javascript/mastodon/features/emoji/database.ts b/app/javascript/mastodon/features/emoji/database.ts index b74e21fe783..3dd2f95858a 100644 --- a/app/javascript/mastodon/features/emoji/database.ts +++ b/app/javascript/mastodon/features/emoji/database.ts @@ -85,13 +85,16 @@ export async function search({ // Only query the range for the last token to allow partial matches. const range = i === queryTokens.length - 1 - ? IDBKeyRange.bound(token, token + '\uffff') + ? IDBKeyRange.lowerBound(token) : IDBKeyRange.only(token); - const [unicodeResults, customResults] = await Promise.all([ - db.getAllFromIndex(locale, 'tokens', range), - db.getAllFromIndex('custom', 'tokens', range), - ]); + const [unicodeResults, customResults, shortcodeResults] = await Promise.all( + [ + db.getAllFromIndex(locale, 'tokens', range), + db.getAllFromIndex('custom', 'tokens', range), + db.getAllFromIndex('shortcodes', 'shortcodes', range), + ], + ); const resultMap: ScoreMap = new Map(); for (const emoji of unicodeResults) { const score = getScoreForEmoji(emoji, token); @@ -107,6 +110,22 @@ export async function search({ } resultMap.set(emoji.shortcode, { ...emoji, score }); } + + for (const shortcodeResult of shortcodeResults) { + if (resultMap.has(shortcodeResult.hexcode)) { + continue; + } + const emoji = await db.get(locale, shortcodeResult.hexcode); + if (!emoji) { + continue; + } + const score = getScoreForEmoji(emoji, token); + if (score === null) { + continue; + } + resultMap.set(emoji.hexcode, { ...emoji, score }); + } + log('found %d results for token "%s"', resultMap.size, token); resultArrays.push(resultMap); } @@ -147,7 +166,7 @@ function getScoreForEmoji(emoji: AnyEmojiData, query: string) { } let index = 1; - for (const token of [id, emoji.tokens]) { + for (const token of [id, ...emoji.tokens]) { const tokenIndex = token.indexOf(query); if (tokenIndex !== -1) { return index + tokenIndex / token.length; diff --git a/app/javascript/mastodon/features/emoji/index.ts b/app/javascript/mastodon/features/emoji/index.ts index b134d884415..a3ef9ffb252 100644 --- a/app/javascript/mastodon/features/emoji/index.ts +++ b/app/javascript/mastodon/features/emoji/index.ts @@ -2,6 +2,7 @@ import { initialState } from '@/mastodon/initial_state'; import type { EMOJI_DB_NAME_SHORTCODES } from './constants'; import { toSupportedLocale } from './locale'; +import { reloadCustomEmojis } from './picker'; import type { LocaleOrCustom } from './types'; import { emojiLogger } from './utils'; @@ -90,6 +91,7 @@ export async function loadCustomEmoji() { const emojis = await importCustomEmojiData(); if (emojis && emojis.length > 0) { log('loaded %d custom emojis', emojis.length); + await reloadCustomEmojis(); } } } diff --git a/app/javascript/mastodon/features/emoji/normalize.ts b/app/javascript/mastodon/features/emoji/normalize.ts index fd4f61c66d3..257cddfcb65 100644 --- a/app/javascript/mastodon/features/emoji/normalize.ts +++ b/app/javascript/mastodon/features/emoji/normalize.ts @@ -14,6 +14,7 @@ import { EMOJIS_REQUIRING_INVERSION_IN_DARK_MODE, EMOJI_MIN_TOKEN_LENGTH, } from './constants'; +import { localeToSegmenter } from './locale'; import type { CustomEmojiData, CustomEmojiMapArg, @@ -92,10 +93,11 @@ export function transformEmojiData( export function transformCustomEmojiData( emoji: ApiCustomEmojiJSON, ): CustomEmojiData { - const tokens = emoji.shortcode - .split('_') - .filter((word) => word.length >= EMOJI_MIN_TOKEN_LENGTH) - .map((word) => word.toLowerCase()); + const tokens = extractTokens(emoji.shortcode, localeToSegmenter('en')); + if (!tokens.includes(emoji.shortcode)) { + tokens.unshift(emoji.shortcode); + } + return { ...emoji, tokens, @@ -215,7 +217,9 @@ export function extractTokens( // Prefer to use Intl.Segmenter if available for better locale support. if (segmenter) { for (const { isWordLike, segment } of segmenter.segment( - input.replaceAll('_', ' '), // Handle underscores from shortcodes. + input + .replaceAll(/[_-]+/g, ' ') // Handle underscores from shortcodes. + .replaceAll(/([a-z])([A-Z])/g, '$1 $2'), // Handle camelCase. )) { if (isWordLike && segment.length >= EMOJI_MIN_TOKEN_LENGTH) { tokens.push(segment.toLowerCase()); diff --git a/app/javascript/mastodon/features/emoji/picker.ts b/app/javascript/mastodon/features/emoji/picker.ts index 1bc9bb2f122..fccf6769c37 100644 --- a/app/javascript/mastodon/features/emoji/picker.ts +++ b/app/javascript/mastodon/features/emoji/picker.ts @@ -82,13 +82,22 @@ type LegacyEmoji = custom: true; }; +export async function reloadCustomEmojis() { + customEmojis = null; + + const { loadEmojisIntoCache } = + await import('@/mastodon/hooks/useCustomEmojis'); + + await Promise.all([fetchCustomEmojiData(), loadEmojisIntoCache()]); +} + // Replicates the old legacy search function. export async function emojiMartSearch( token: string, locale: string, limit = 5, ): Promise { - const query = token.replace(':', '').toLowerCase().trim(); + const query = token.replace(':', '').trim(); if (!query.length) { return []; } diff --git a/app/javascript/mastodon/hooks/useCustomEmojis.ts b/app/javascript/mastodon/hooks/useCustomEmojis.ts index aeb77620dd0..6eb3c17fbfc 100644 --- a/app/javascript/mastodon/hooks/useCustomEmojis.ts +++ b/app/javascript/mastodon/hooks/useCustomEmojis.ts @@ -20,7 +20,7 @@ export function useCustomEmojis() { return emojis; } -async function loadEmojisIntoCache() { +export async function loadEmojisIntoCache() { const { loadAllCustomEmoji } = await import('../features/emoji/database'); const emojisRaw = await loadAllCustomEmoji(); if (emojisRaw === null) { From ceab04a1fddaf1389bd88994af913838a2c04652 Mon Sep 17 00:00:00 2001 From: diondiondion Date: Tue, 26 May 2026 16:33:37 +0200 Subject: [PATCH 25/70] Fix missing Translate button (#39170) --- app/javascript/mastodon/components/status_content.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/javascript/mastodon/components/status_content.jsx b/app/javascript/mastodon/components/status_content.jsx index 4d9ae4fa3f6..7e5cccf1986 100644 --- a/app/javascript/mastodon/components/status_content.jsx +++ b/app/javascript/mastodon/components/status_content.jsx @@ -69,7 +69,7 @@ class TranslateButton extends PureComponent { } const mapStateToProps = state => ({ - languages: state.server.translationLanguages.items, + languages: state.server.translationLanguages.item, }); class StatusContent extends PureComponent { @@ -187,7 +187,7 @@ class StatusContent extends PureComponent { const renderReadMore = this.props.onClick && status.get('collapsed'); const contentLocale = intl.locale.replace(/[_-].*/, ''); - const targetLanguages = this.props.languages?.get(status.get('language') || 'und'); + const targetLanguages = this.props.languages?.[status.get('language') || 'und']; const renderTranslate = this.props.onTranslate && this.props.identity.signedIn && ['public', 'unlisted'].includes(status.get('visibility')) && status.get('search_index').trim().length > 0 && targetLanguages?.includes(contentLocale); const content = statusContent ?? getStatusContent(status); From 1962e4743c3786b3694a802547271a6046da4c9a Mon Sep 17 00:00:00 2001 From: diondiondion Date: Tue, 26 May 2026 16:59:07 +0200 Subject: [PATCH 26/70] Fix advanced UI column crashing in development (#39171) --- app/javascript/mastodon/components/scrollable_list/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/mastodon/components/scrollable_list/index.jsx b/app/javascript/mastodon/components/scrollable_list/index.jsx index a80fe5581aa..e44a827a2ff 100644 --- a/app/javascript/mastodon/components/scrollable_list/index.jsx +++ b/app/javascript/mastodon/components/scrollable_list/index.jsx @@ -285,7 +285,7 @@ class ScrollableList extends PureComponent { if (this.props.bindToDocument) { document.removeEventListener('scroll', this.handleScroll); document.removeEventListener('wheel', this.handleWheel, listenerOptions); - } else { + } else if (this.node) { this.node.removeEventListener('scroll', this.handleScroll); this.node.removeEventListener('wheel', this.handleWheel, listenerOptions); } From d20d04922672ed016029c40ed64798f341ebca91 Mon Sep 17 00:00:00 2001 From: diondiondion Date: Tue, 26 May 2026 19:42:49 +0200 Subject: [PATCH 27/70] Accessibility: Ensure focus order of post elements matches visual reading order (#39169) --- .../mastodon/components/status/header.tsx | 22 +++++++++------ .../mastodon/components/status_quoted.tsx | 25 +++++++++-------- .../components/pinned_statuses.tsx | 28 +++++++++++-------- .../account_timeline/styles.module.scss | 3 ++ .../styles/mastodon/components.scss | 2 -- 5 files changed, 46 insertions(+), 34 deletions(-) diff --git a/app/javascript/mastodon/components/status/header.tsx b/app/javascript/mastodon/components/status/header.tsx index 65790bb4932..1ce5c4a36c6 100644 --- a/app/javascript/mastodon/components/status/header.tsx +++ b/app/javascript/mastodon/components/status/header.tsx @@ -20,7 +20,8 @@ export interface StatusHeaderProps { status: Status; account?: Account; avatarSize?: number; - children?: ReactNode; + contentBeforeDate?: ReactNode; + contentAfterDate?: ReactNode; wrapperProps?: HTMLAttributes; displayNameProps?: DisplayNameProps; onHeaderClick?: MouseEventHandler; @@ -33,10 +34,11 @@ export type StatusHeaderRenderFn = (args: StatusHeaderProps) => ReactNode; export const StatusHeader: FC = ({ status, account, - children, className, avatarSize = 48, wrapperProps, + contentBeforeDate, + contentAfterDate, onHeaderClick, }) => { const statusAccount = status.get('account') as Account | undefined; @@ -51,6 +53,14 @@ export const StatusHeader: FC = ({ className={classNames('status__info', className)} /* eslint-enable jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */ > + + + {contentBeforeDate} + = ({ {editedAt && } - - - {children} + {contentAfterDate}
); }; diff --git a/app/javascript/mastodon/components/status_quoted.tsx b/app/javascript/mastodon/components/status_quoted.tsx index 5c9804fb40e..b269792a5e3 100644 --- a/app/javascript/mastodon/components/status_quoted.tsx +++ b/app/javascript/mastodon/components/status_quoted.tsx @@ -225,17 +225,20 @@ export const QuotedStatus: React.FC = ({ const intl = useIntl(); const headerRenderFn: StatusHeaderRenderFn = useCallback( (props) => ( - - {onQuoteCancel && ( - - )} - + + ) + } + /> ), [intl, onQuoteCancel], ); diff --git a/app/javascript/mastodon/features/account_timeline/components/pinned_statuses.tsx b/app/javascript/mastodon/features/account_timeline/components/pinned_statuses.tsx index 11de336002b..c751af83ca5 100644 --- a/app/javascript/mastodon/features/account_timeline/components/pinned_statuses.tsx +++ b/app/javascript/mastodon/features/account_timeline/components/pinned_statuses.tsx @@ -22,18 +22,22 @@ export const renderPinnedStatusHeader: StatusHeaderRenderFn = ({ return ; } return ( - - } - label={ - - } - /> - + } + label={ + + } + /> + } + /> ); }; diff --git a/app/javascript/mastodon/features/account_timeline/styles.module.scss b/app/javascript/mastodon/features/account_timeline/styles.module.scss index cd5cef3f29d..9773861d222 100644 --- a/app/javascript/mastodon/features/account_timeline/styles.module.scss +++ b/app/javascript/mastodon/features/account_timeline/styles.module.scss @@ -126,4 +126,7 @@ .pinnedBadge { justify-self: end; + + // Allow "click to open post" event to pass through + pointer-events: none; } diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 3848b76377a..809634e8f5b 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -1613,7 +1613,6 @@ body > [data-popper-placement] { font-size: 15px; line-height: 22px; height: 40px; - order: 2; flex: 0 0 auto; color: var(--color-text-secondary); } @@ -1666,7 +1665,6 @@ body > [data-popper-placement] { .status__quote-cancel { align-self: self-start; - order: 5; } .status__info { From e146525e780bf8ccf893c2f3c01c35cfad5dcaa7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 27 May 2026 10:54:44 +0200 Subject: [PATCH 28/70] Update dependency aws-sdk-core to v3.249.0 (#39140) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 62d049d0333..b8d99a8c636 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -99,8 +99,8 @@ GEM ast (2.4.3) attr_required (1.0.2) aws-eventstream (1.4.0) - aws-partitions (1.1249.0) - aws-sdk-core (3.247.0) + aws-partitions (1.1253.0) + aws-sdk-core (3.249.0) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.992.0) aws-sigv4 (~> 1.9) From 32cb9e74508589155200b9dc1bf641e356b625f0 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 27 May 2026 04:56:30 -0400 Subject: [PATCH 29/70] Update rubocop-rails to version 2.35.2 (#39137) --- .rubocop/rails.yml | 3 +++ Gemfile.lock | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.rubocop/rails.yml b/.rubocop/rails.yml index bbd172e6560..d98c6fc4865 100644 --- a/.rubocop/rails.yml +++ b/.rubocop/rails.yml @@ -24,3 +24,6 @@ Rails/RakeEnvironment: Rails/SkipsModelValidations: Enabled: false + +Rails/StrongParametersExpect: + Enabled: false diff --git a/Gemfile.lock b/Gemfile.lock index b8d99a8c636..d37d8b0263e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -779,7 +779,7 @@ GEM lint_roller (~> 1.1) rubocop (>= 1.75.0, < 2.0) rubocop-ast (>= 1.47.1, < 2.0) - rubocop-rails (2.34.3) + rubocop-rails (2.35.2) activesupport (>= 4.2.0) lint_roller (~> 1.1) rack (>= 1.1) From f82334dd36fb984cb84758325ac4b73f04a0edc2 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 27 May 2026 05:11:31 -0400 Subject: [PATCH 30/70] Update rubocop to version 1.86.2 (#39136) --- .rubocop/style.yml | 3 +++ Gemfile.lock | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.rubocop/style.yml b/.rubocop/style.yml index f59340d452e..1d1c9f98797 100644 --- a/.rubocop/style.yml +++ b/.rubocop/style.yml @@ -33,6 +33,9 @@ Style/NumericLiterals: AllowedPatterns: - \d{4}_\d{2}_\d{2}_\d{6} +Style/OneClassPerFile: + Enabled: false + Style/PercentLiteralDelimiters: PreferredDelimiters: '%i': () diff --git a/Gemfile.lock b/Gemfile.lock index d37d8b0263e..4644688f468 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -588,7 +588,7 @@ GEM ostruct (0.6.3) ox (2.14.26) bigdecimal (>= 3.0) - parallel (1.28.0) + parallel (2.1.0) parser (3.3.11.1) ast (~> 2.4.1) racc @@ -755,11 +755,11 @@ GEM rspec-mocks (~> 3.0) sidekiq (>= 5, < 9) rspec-support (3.13.7) - rubocop (1.84.2) + rubocop (1.86.2) json (~> 2.3) language_server-protocol (~> 3.17.0.2) lint_roller (~> 1.1.0) - parallel (~> 1.10) + parallel (>= 1.10) parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 2.9.3, < 3.0) From 991a8af7a01330f399398adac15a5ff7421a0f7b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 27 May 2026 11:35:56 +0200 Subject: [PATCH 31/70] New Crowdin Translations (automated) (#39152) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/ar.json | 137 ++++++++++++++++++++ app/javascript/mastodon/locales/be.json | 8 ++ app/javascript/mastodon/locales/da.json | 8 ++ app/javascript/mastodon/locales/de.json | 10 +- app/javascript/mastodon/locales/el.json | 14 +- app/javascript/mastodon/locales/es-AR.json | 8 ++ app/javascript/mastodon/locales/es-MX.json | 6 +- app/javascript/mastodon/locales/es.json | 4 +- app/javascript/mastodon/locales/fi.json | 7 + app/javascript/mastodon/locales/fr-CA.json | 8 ++ app/javascript/mastodon/locales/fr.json | 8 ++ app/javascript/mastodon/locales/ga.json | 4 + app/javascript/mastodon/locales/gl.json | 10 ++ app/javascript/mastodon/locales/he.json | 10 ++ app/javascript/mastodon/locales/hu.json | 9 +- app/javascript/mastodon/locales/is.json | 19 +++ app/javascript/mastodon/locales/it.json | 12 +- app/javascript/mastodon/locales/kab.json | 3 + app/javascript/mastodon/locales/mk.json | 27 ++++ app/javascript/mastodon/locales/nan-TW.json | 11 ++ app/javascript/mastodon/locales/nl.json | 10 ++ app/javascript/mastodon/locales/pa.json | 8 ++ app/javascript/mastodon/locales/pt-BR.json | 116 +++++++++-------- app/javascript/mastodon/locales/sq.json | 8 ++ app/javascript/mastodon/locales/sv.json | 12 +- app/javascript/mastodon/locales/tr.json | 10 ++ app/javascript/mastodon/locales/vi.json | 8 ++ app/javascript/mastodon/locales/zh-CN.json | 2 + app/javascript/mastodon/locales/zh-TW.json | 8 ++ config/locales/ar.yml | 5 - config/locales/be.yml | 12 +- config/locales/bg.yml | 3 - config/locales/br.yml | 3 - config/locales/cs.yml | 5 - config/locales/cy.yml | 5 - config/locales/da.yml | 12 +- config/locales/de.yml | 5 +- config/locales/el.yml | 10 +- config/locales/en-GB.yml | 5 - config/locales/es-AR.yml | 12 +- config/locales/es-MX.yml | 5 - config/locales/es.yml | 7 +- config/locales/et.yml | 5 - config/locales/eu.yml | 5 - config/locales/fa.yml | 5 - config/locales/fi.yml | 12 +- config/locales/fo.yml | 5 - config/locales/fr-CA.yml | 10 +- config/locales/fr.yml | 10 +- config/locales/ga.yml | 6 +- config/locales/gd.yml | 5 - config/locales/gl.yml | 13 +- config/locales/he.yml | 13 +- config/locales/hu.yml | 10 +- config/locales/ia.yml | 5 - config/locales/is.yml | 12 +- config/locales/it.yml | 13 +- config/locales/ja.yml | 3 - config/locales/kab.yml | 4 - config/locales/ko.yml | 5 - config/locales/lad.yml | 4 - config/locales/nan-TW.yml | 28 +++- config/locales/nl.yml | 13 +- config/locales/nn.yml | 5 - config/locales/pl.yml | 5 - config/locales/pt-BR.yml | 10 +- config/locales/pt-PT.yml | 5 - config/locales/ru.yml | 5 - config/locales/sl.yml | 4 - config/locales/sq.yml | 13 +- config/locales/sv.yml | 7 +- config/locales/th.yml | 5 - config/locales/tr.yml | 6 +- config/locales/vi.yml | 8 +- config/locales/zh-CN.yml | 5 - config/locales/zh-TW.yml | 10 +- 76 files changed, 624 insertions(+), 244 deletions(-) diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json index b35f29e6b0b..cfd6160b924 100644 --- a/app/javascript/mastodon/locales/ar.json +++ b/app/javascript/mastodon/locales/ar.json @@ -86,18 +86,22 @@ "account.locked_info": "تم ضبط حالة خصوصية هذا الحساب على أنه مؤمّن. إذ يراجع صاحبه يدويًا من يُسمح له بالمتابعة.", "account.media": "وسائط", "account.mention": "أذكُر @{name}", + "account.menu.add_to_collection": "إضافة إلى المجموعة…", "account.menu.add_to_list": "إضافة إلى القائمة…", "account.menu.block": "حظر الحساب", "account.menu.block_domain": "حظر {domain}", "account.menu.copied": "تم نسخ رابط الحساب إلى الحافظة", "account.menu.copy": "نسخ الرابط", "account.menu.direct": "إشارة خاصة لـ", + "account.menu.hide_reblogs": "إخفاء التعزيزات في الجدول الزمني", "account.menu.mention": "إشارة", "account.menu.mute": "كتم الحساب", "account.menu.note.description": "مرئي لك فقط", + "account.menu.open_original_page": "عرض على {domain}", "account.menu.remove_follower": "إزالة المتابِع", "account.menu.report": "الإبلاغ عن الحساب", "account.menu.share": "مشاركة…", + "account.menu.show_reblogs": "عرض التعزيزات في الجدول الزمني", "account.menu.unblock": "رفع الحظر عن الحساب", "account.menu.unblock_domain": "رفع الحظر عن {domain}", "account.menu.unmute": "إلغاء كتم الحساب", @@ -108,8 +112,15 @@ "account.muted": "مَكتوم", "account.mutual": "أنتم تتابعون بعضكم البعض", "account.name.copy": "نسخ المعرف", + "account.name.help.domain": "{domain} هو الخادوم الذي يستضيف ملف المستخدم الشخصي ومنشوراته.", + "account.name.help.domain_self": "{domain} هو الخادوم الذي يستضيف ملفك الشخصي ومنشوراتك.", + "account.name.help.footer": "تمامًا كما يمكنك إرسال رسائل بريد إلكتروني إلى أشخاص يستخدمون مزوّدي بريد إلكتروني مختلفين، يمكنك التفاعل مع أشخاص على خواديم ماستودون أخرى، ومع أي شخص على تطبيقات فيديفيرس الأخرى.", + "account.name.help.header": "اللقب يشبه عنوان البريد الإلكتروني", + "account.name.help.username": "{username} هو اسم المستخدم الخاص بهذا الحساب على خادومهم. قد يكون لدى شخص آخر على خادم آخر نفس اسم المستخدم.", + "account.name.help.username_self": "{username} هو اسم المستخدم الخاص بك على هذا الخادوم. قد يكون لدى شخص آخر على خادوم آخر نفس اسم المستخدم.", "account.name_info": "ما معنى ذلك؟", "account.no_bio": "لم يتم تقديم وصف.", + "account.node_modal.callout": "الملاحظات الشخصية لا يراها سواك.", "account.node_modal.edit_title": "تعديل الملاحظة الشخصية", "account.node_modal.error_unknown": "تعذر حفظ الملاحظة", "account.node_modal.field_label": "ملاحظة شخصية", @@ -118,6 +129,7 @@ "account.note.edit_button": "تعديل", "account.note.title": "ملاحظة شخصية (مرئية لك فقط)", "account.open_original_page": "افتح الصفحة الأصلية", + "account.pending": "معلّق", "account.posts": "منشورات", "account.remove_from_followers": "إزالة {name} من المتابعين", "account.report": "الإبلاغ عن @{name}", @@ -136,10 +148,12 @@ "account.unmute": "إلغاء الكَتم عن @{name}", "account.unmute_notifications_short": "إلغاء كَتم الإشعارات", "account.unmute_short": "إلغاء الكتم", + "account_edit.advanced_settings.bot_hint": "أعلِم الآخرين بأن الحساب يجري إجراءات آلية بشكلٍ أساسي وقد لا تتم مراقبته", "account_edit.advanced_settings.bot_label": "حساب آلي", "account_edit.advanced_settings.title": "الإعدادات المتقدمة", "account_edit.bio.add_label": "إضافة سيرة ذاتية", "account_edit.bio.edit_label": "تعديل السيرة الذاتية", + "account_edit.bio.placeholder": "أضف مقدّمة قصيرة لمساعدة الآخرين على التعرف عليك.", "account_edit.bio.title": "نبذة عنك", "account_edit.bio_modal.add_title": "إضافة سيرة ذاتية", "account_edit.bio_modal.edit_title": "تعديل السيرة الذاتية", @@ -149,30 +163,50 @@ "account_edit.custom_fields.edit_label": "تعديل الحقل", "account_edit.custom_fields.placeholder": "أضف ضمائر أو روابط خارجية أو أي شيء آخر ترغب في مشاركته.", "account_edit.custom_fields.reorder_button": "إعادة ترتيب الحقول", + "account_edit.custom_fields.tip_content": "يمكنك بسهولة إضافة مصداقية إلى حسابك على منصة ماستودون عن طريق التحقق من الروابط المؤدّية إلى أي مواقع ويب تملكها.", "account_edit.custom_fields.tip_title": "نصيحة: إضافة روابط متحقق منها", "account_edit.custom_fields.title": "الحقول المخصصة", "account_edit.custom_fields.verified_hint": "كيف يمكنني إضافة رابط متحقق منه؟", "account_edit.display_name.add_label": "إضافة اسم علني", "account_edit.display_name.edit_label": "تعديل الاسم العلني", + "account_edit.display_name.placeholder": "اسم العرض الخاص بك هو كيف يظهر اسمك في ملفك الشخصي وفي الجداول الزمنية.", "account_edit.display_name.title": "الاسم العلني", "account_edit.featured_hashtags.edit_label": "إضافة وسوم", + "account_edit.featured_hashtags.placeholder": "ساعد الآخرين في تحديد مواضيعك المفضلة والوصول إليها بسرعة.", "account_edit.featured_hashtags.title": "الوسوم المروّجة", "account_edit.field_actions.delete": "حذف الحقل", "account_edit.field_actions.edit": "تعديل الحقل", + "account_edit.field_delete_modal.confirm": "هل أنت متأكد من رغبتك في حذف هذا الحقل المخصص؟ لا يمكن التراجع عن هذا الإجراء.", "account_edit.field_delete_modal.delete_button": "حذف", "account_edit.field_delete_modal.title": "أتريد حذف الحقل المخصص؟", "account_edit.field_edit_modal.add_title": "إضافة حقل مخصص", "account_edit.field_edit_modal.discard_confirm": "تجاهل", + "account_edit.field_edit_modal.discard_message": "لديك تغييرات غير محفوظة. هل أنت متأكد من رغبتك في حذفها؟", "account_edit.field_edit_modal.edit_title": "تعديل الحقل المخصص", + "account_edit.field_edit_modal.length_warning": "تم تجاوز الحد الأقصى الموصّى به لعدد الأحرف. قد لا يرى مستخدمو الهواتف الجوّالة حقل النص بالكامل.", + "account_edit.field_edit_modal.link_emoji_warning": "لا ننصح باستخدام الرموز التعبيرية المخصصة مع عناوين المواقع الإلكترونية. ستظهر الحقول المخصصة التي تحتوي على كليهما كنص فقط بدلًا من رابط، وذلك لتجنب إرباك المستخدم.", "account_edit.field_edit_modal.name_hint": "على سبيل المثال \"الموقع الشخصي\"", "account_edit.field_edit_modal.name_label": "التسمية", "account_edit.field_edit_modal.url_warning": "لإضافة رابط ، يرجى تضمين {protocol} في البداية.", "account_edit.field_edit_modal.value_hint": "على سبيل المثال \"https://example.me\"", "account_edit.field_edit_modal.value_label": "قيمة", + "account_edit.field_reorder_modal.drag_cancel": "تم إلغاء عملية السحب. تم حذف الحقل ”{item}“.", + "account_edit.field_reorder_modal.drag_end": "تم حذف الحقل ”{item}“.", + "account_edit.field_reorder_modal.drag_instructions": "لإعادة ترتيب الحقول المخصصة، اضغط على مفتاح المسافة أو مفتاح الإدخال. أثناء السحب، استخدم مفاتيح الأسهم لتحريك الحقل لأعلى أو لأسفل. اضغط على مفتاح المسافة أو مفتاح الإدخال مرة أخرى لإسقاط الحقل في موضعه الجديد، أو اضغط على زر Escape للإلغاء.", + "account_edit.field_reorder_modal.drag_move": "تم نقل الحقل ”{item}“.", + "account_edit.field_reorder_modal.drag_over": "تم نقل الحقل ”{item}“ إلى ”{over}“.", + "account_edit.field_reorder_modal.drag_start": "تم اختيار الحقل ”{item}“.", + "account_edit.field_reorder_modal.handle_label": "سحب الحقل ”{item}“", + "account_edit.field_reorder_modal.title": "إعادة ترتيب الحقول", "account_edit.image_alt_modal.add_title": "إضافة نص بديل", + "account_edit.image_alt_modal.details_content": "افعل:
  • صِف نفسك كما في الصورة
  • استخدِم ضمير الغائب (مثلًا ”ألِكس“ بدلًا من ”أنا“)
  • كُن موجزًا – بضع كلمات تكفي غالبًا
لا تفعل:
  • ابدأ بـ”صورة لـ“ – فهذا غير ضروري لقارئات الشاشة
مثال:
  • ”ألِكس يرتدي قميصًا أخضر ونظّارة“
", + "account_edit.image_alt_modal.details_title": "نصائح: نص بديل لصور الملف الشخصي", "account_edit.image_alt_modal.edit_title": "تعديل نص بديل", + "account_edit.image_alt_modal.text_hint": "يساعد النص البديل مستخدمي قارئات الشاشة على فهم المحتوى الخاص بك.", "account_edit.image_alt_modal.text_label": "نص بديل", + "account_edit.image_delete_modal.confirm": "هل أنت متأكد من رغبتك في حذف هذه الصورة؟ لا يمكن التراجع عن هذا الإجراء.", "account_edit.image_delete_modal.delete_button": "حذف", + "account_edit.image_delete_modal.title": "حذف الصورة؟", "account_edit.image_edit.add_button": "إضافة صورة", "account_edit.image_edit.alt_add_button": "إضافة نص بديل", "account_edit.image_edit.alt_edit_button": "تعديل نص بديل", @@ -180,7 +214,21 @@ "account_edit.image_edit.replace_button": "استبدال الصورة", "account_edit.item_list.delete": "حذف {name}", "account_edit.item_list.edit": "تعديل {name}", + "account_edit.name_modal.add_title": "إضافة اسم عرض", + "account_edit.name_modal.edit_title": "تعديل اسم العرض", "account_edit.profile_tab.button_label": "تخصيص", + "account_edit.profile_tab.hint.description": "تُخصّص هذه الإعدادات ما يراه المستخدمون على {server} في التطبيقات الرسمية، ولكنها قد لا تنطبق على المستخدمين على الخواديم الأخرى وتطبيقات الطرف الثالث.", + "account_edit.profile_tab.hint.title": "لا تزال العروض تختلف", + "account_edit.profile_tab.show_featured.description": "’المميّز‘ هو تبويب اختياري يمكنك من خلاله عرض حسابات أخرى.", + "account_edit.profile_tab.show_featured.title": "عرض علامة تبويب ’المميّز‘", + "account_edit.profile_tab.show_media.description": "’الوسائط‘ هي علامة تبويب اختيارية تعرض منشوراتك التي تحتوي على صور أو مقاطع فيديو.", + "account_edit.profile_tab.show_media.title": "إظهار علامة تبويب ’الوسائط‘", + "account_edit.profile_tab.show_media_replies.description": "عند تفعيلها، تعرض علامة تبويب الوسائط منشوراتك وردودك على منشورات الآخرين.", + "account_edit.profile_tab.show_media_replies.title": "تضمين الردود في علامة تبويب ’الوسائط‘", + "account_edit.profile_tab.show_relations.description": "يعرض هذا القسم الحسابات التي تتابعها والمتابعين للمستخدمين الآخرين في ملفك الشخصي. وسيظل بإمكان الآخرين معرفة ما إذا كنت تتابعهم أم لا.", + "account_edit.profile_tab.show_relations.title": "عرض ’يتابعوه‘ و’يتابع‘", + "account_edit.profile_tab.subtitle": "خصّص طريقة عرض ملفك الشخصي.", + "account_edit.profile_tab.title": "إعدادات عرض الملف الشخصي", "account_edit.save": "حفظ", "account_edit.upload_modal.back": "العودة", "account_edit.upload_modal.done": "تمّ", @@ -189,12 +237,27 @@ "account_edit.upload_modal.step_upload.button": "تصفح الملفات", "account_edit.upload_modal.step_upload.dragging": "إسقاط للتحميل", "account_edit.upload_modal.step_upload.header": "اختيار صورة", + "account_edit.upload_modal.step_upload.hint": "بصيغة WEBP أو PNG أو GIF أو JPG، حتى {limit} ميجابايت.{br} سيتم تغيير حجم الصورة إلى {width}×{height} بكسل.", "account_edit.upload_modal.title_add.avatar": "إضافة صورة الملف الشخصي", "account_edit.upload_modal.title_add.header": "إضافة صورة الغلاف", "account_edit.upload_modal.title_replace.avatar": "استبدال صورة الملف الشخصي", "account_edit.upload_modal.title_replace.header": "استبدال صورة الغلاف", + "account_edit.verified_modal.details": "أضف مصداقية إلى ملفك الشخصي على ماستودون من خلال التحقق من الروابط المؤدية إلى مواقعك الإلكترونية الشخصية. إليك كيفية عمل ذلك:", + "account_edit.verified_modal.invisible_link.details": "أضف الرابط إلى ترويسة صفحتك. الجزء المهم هو rel=\"me\" الذي يمنع انتحال الهوية على المواقع الإلكترونية التي تحتوي على محتوى من إنشاء المستخدمين. يمكنك حتى استخدام وسم الرابط في ترويسة الصفحة بدلًا من {tag}.", + "account_edit.verified_modal.invisible_link.summary": "كيف يمكنني إخفاء الرابط؟", + "account_edit.verified_modal.step1.header": "انسخ كود HTML أدناه والصقه في ترويسة موقعك الإلكتروني", + "account_edit.verified_modal.step2.details": "إذا كنت قد أضفت موقعك الإلكتروني فعلًا كحقل مخصّص، فستحتاج إلى حذفه وإعادة إضافته لتفعيل عملية التحقق.", + "account_edit.verified_modal.step2.header": "أضف موقعك الإلكتروني كحقل مخصّص", + "account_edit.verified_modal.title": "كيفية إضافة رابط موثّق", "account_edit_tags.add_tag": "إضافة #{tagName}", + "account_edit_tags.column_title": "تعديل الوسوم", + "account_edit_tags.help_text": "تساعد الهاشتاجات المميّزة المستخدمين على اكتشاف ملفك الشخصي والتفاعل معه. وتظهر هذه الهاشتاجات كمرشّحات في صفحة النشاطات الخاصة بملفك الشخصي.", + "account_edit_tags.max_tags_reached": "لقد وصلت إلى الحد الأقصى لعدد الهاشتاجات المميّزة.", + "account_edit_tags.search_placeholder": "أدخِل هاشتاج…", "account_edit_tags.suggestions": "الاقتراحات:", + "account_edit_tags.tag_status_count": "{count, plural, one {# منشور} two {# منشورَين} few {# منشورات} many {# منشور} other {# منشور}}", + "account_list.hidden_notice": "هذا المحتوى مرئي لك فقط. لعرض هذه القائمة للآخرين، انتقِل إلى {page} > {modal} > {field}.", + "account_list.total": "{total, plural, one {# حساب} two {# حسابَين} few {# حسابات} many {# حساب} other {# حساب}}", "admin.dashboard.daily_retention": "معدّل بقاء المستخدمين بعد إنشاء الحسابات، بالأيام", "admin.dashboard.monthly_retention": "معدّل بقاء المستخدمين بعد إنشاء الحسابات، بالشهور", "admin.dashboard.retention.average": "المعدل", @@ -217,27 +280,63 @@ "alt_text_modal.describe_for_people_with_visual_impairments": "قم بوصفها للأشخاص ذوي الإعاقة البصرية…", "alt_text_modal.done": "تمّ", "announcement.announcement": "إعلان", + "annual_report.announcement.action_build": "بناء الملخّص الخاص بي", "annual_report.announcement.action_dismiss": "لا شكراً", + "annual_report.announcement.action_view": "الاطّلاع على الملخّص الخاص بي", + "annual_report.announcement.description": "اكتشف المزيد حول تفاعلك على منصة ماستودون خلال العام الماضي.", + "annual_report.announcement.title": "الملخّص لعام {year} قد وصل", "annual_report.nav_item.badge": "جديد", "annual_report.shared_page.donate": "تبرع", + "annual_report.shared_page.footer": "صُنع بـ{heart} من قِبل فريق ماستودون", + "annual_report.shared_page.footer_server_info": "{username} يستخدم {domain}، وهو واحد من العديد من المجتمعات التي تعمل بواسطة ماستودون.", + "annual_report.summary.archetype.booster.desc_public": "واصَل {name} في البحث عن منشورات لتعزيزها، ممّا ساهم في تضخيم منشورات المبدعين الآخرين بدقّة متناهية.", + "annual_report.summary.archetype.booster.desc_self": "لقد واصلت البحث عن منشورات لتعزيزها، ممّا ساهم في تضخيم أعمال المبدعين الآخرين بدقّة متناهية.", + "annual_report.summary.archetype.booster.name": "النشّاب", + "annual_report.summary.archetype.die_drei_fragezeichen": "؟؟؟", + "annual_report.summary.archetype.lurker.desc_public": "نحن نعلم أنّ {name} كان هناك، في مكانٍ ما، يستمتع بماستودون بطريقته الهادئة الخاصة.", + "annual_report.summary.archetype.lurker.desc_self": "نحن نعلم أنّك كنت هناك، في مكان ما، تستمتع بماستودون بطريقتك الهادئة الخاصة.", + "annual_report.summary.archetype.lurker.name": "الرواقي", + "annual_report.summary.archetype.oracle.desc_public": "أنشأ {name} منشورات جديدة أكثر من الردود، ممّا حافَظ على تحديث ماستودون وتطلُّع المنصّة للمستقبَل.", + "annual_report.summary.archetype.oracle.desc_self": "لقد أنشأت منشورات جديدة أكثر من الردود، ممّا حافَظ على تحديث ماستودون وتطلُّع المنصّة للمستقبَل.", "annual_report.summary.archetype.oracle.name": "الحكيم", + "annual_report.summary.archetype.pollster.desc_public": "أنشأ {name} استطلاعات رأي أكثر من أنواع المنشورات الأخرى، ممّا أثار الفضول على منصّة ماستودون.", + "annual_report.summary.archetype.pollster.desc_self": "لقد أنشأت استطلاعات رأي أكثر من أنواع المنشورات الأخرى، ممّا أثار الفضول على منصّة ماستودون.", + "annual_report.summary.archetype.pollster.name": "المتأمّل", + "annual_report.summary.archetype.replier.desc_public": "كان {name} يردّ باستمرار على منشورات الآخرين، ممّا يساهم في إثراء منصّة ماستودون بمناقشات جديدة.", + "annual_report.summary.archetype.replier.desc_self": "كنت تردّ باستمرار على منشورات الآخرين، ممّا ساهم إلى إثراء منصّة ماستودون بمناقشات جديدة.", "annual_report.summary.archetype.replier.name": "الفراشة", + "annual_report.summary.archetype.reveal": "الكشف عن نمطي", + "annual_report.summary.archetype.reveal_description": "شكرًا لكونك جزءً من ماستودون! حان الوقت لمعرفة أي نمط جسّدته في {year}.", + "annual_report.summary.archetype.title_public": "نمط {name}", + "annual_report.summary.archetype.title_self": "نمطك", "annual_report.summary.close": "اغلق", "annual_report.summary.copy_link": "نسخ الرابط", + "annual_report.summary.followers.new_followers": "{count, plural, one {متابع جديد} two {متابعَين جديدَين} few {متابعين جديدين} many {متابع جديد} other {متابع جديد}}", + "annual_report.summary.highlighted_post.boost_count": "عُزِّز هذا المنشور {count, plural, one {مرة واحدة} two {مرتَين} few {# مرات} many {# مرة} other {# مرة}}.", + "annual_report.summary.highlighted_post.favourite_count": "أُضيف هذا المنشور إلى المفضّلة {count, plural, one {مرة واحدة} two {مرتَين} few {# مرات} many {# مرة} other {# مرة}}.", + "annual_report.summary.highlighted_post.reply_count": "تلقّى هذا المنشور {count, plural, one {ردًّا واحدًا} two {ردَّين} few {# ردود} many {# ردًّا} other {# ردّ}}.", + "annual_report.summary.highlighted_post.title": "المنشور الأكثر شعبية", "annual_report.summary.most_used_app.most_used_app": "التطبيق الأكثر استخداماً", "annual_report.summary.most_used_hashtag.most_used_hashtag": "الهاشتاق الأكثر استخداماً", + "annual_report.summary.most_used_hashtag.used_count": "لقد أدرجت هذا الهاشتاج في {count, plural, one {منشور واحد} two {منشورَين} few {# منشورات} many {# منشورًا} other {# منشور}}.", + "annual_report.summary.most_used_hashtag.used_count_public": "{name} أدرج هذا الهاشتاج في {count, plural, one {منشور واحد} two {منشورَين} few {# منشورات} many {# منشورًا} other {# منشور}}.", "annual_report.summary.new_posts.new_posts": "المنشورات الجديدة", "annual_report.summary.percentile.text": "هذا يجعلك من بين أكثر مستخدمي {domain} نشاطاً ", "annual_report.summary.percentile.we_wont_tell_bernie": "سيبقى هذا الأمر بيننا.", "annual_report.summary.share_elsewhere": "شاركها في مكان آخر", + "annual_report.summary.share_message": "حصلتُ على نمط {archetype}!", "annual_report.summary.share_on_mastodon": "شاركها على ماستدون", "attachments_list.unprocessed": "(غير معالَج)", "audio.hide": "إخفاء المقطع الصوتي", + "block_modal.no_collections": "لا يمكن لأيٍّ منكما إضافة الآخر إلى المجموعات. سيتمّ حذفكما تلقائيًّا من مجموعات بعضكما البعض الحالية، إن وُجدت.", "block_modal.remote_users_caveat": "سوف نطلب من الخادم {domain} أن يحترم قرارك، لكن الالتزام غير مضمون لأن بعض الخواديم قد تتعامل مع نصوص الكتل بشكل مختلف. قد تظل المنشورات العامة مرئية للمستخدمين غير المسجلين الدخول.", "block_modal.show_less": "تفاصيل أقلّ", "block_modal.show_more": "تفاصيل أكثر", + "block_modal.they_cant_mention": "لا يجوز لكم ذكر بعضكم البعض، أو متابعته، أو الاقتباس منه.", + "block_modal.they_cant_see_posts": "لا يمكنهم رؤية محتواك ولن ترى محتواه.", "block_modal.they_will_know": "سيعلم أنه قد حُظِر.", "block_modal.title": "أتريد حظر هذا المستخدم؟", + "block_modal.you_wont_see_mentions": "لن ترى منشورات من الآخرين تذكرهم.", "boost_modal.combo": "يُمكنك الضّغط على {combo} لتخطي هذا في المرة المُقبلة", "boost_modal.reblog": "أتريد إعادة نشر المنشور؟", "boost_modal.undo_reblog": "أتريد إلغاء إعادة نشر المنشور؟", @@ -254,6 +353,10 @@ "bundle_modal_error.message": "حدث خطأ أثناء تحميل هذه الشاشة.", "bundle_modal_error.retry": "إعادة المُحاولة", "callout.dismiss": "تجاهل", + "carousel.current": "الشريحة {current, number}/{max, number}", + "carousel.slide": "الشريحة {current, number} من {max, number}", + "character_counter.recommended": "{currentLength}/{maxLength} حرفًا موصّى بها", + "character_counter.required": "{currentLength}/{maxLength} حرف", "closed_registrations.other_server_instructions": "بما أن ماستدون لامركزي، يمكنك إنشاء حساب على خادم آخر للاستمرار في التفاعل مع هذا الخادم.", "closed_registrations_modal.description": "لا يمكن إنشاء حساب على {domain} حاليا، ولكن على فكرة لست بحاجة إلى حساب على {domain} بذاته لاستخدام ماستدون.", "closed_registrations_modal.find_another_server": "ابحث على خادم آخر", @@ -261,6 +364,16 @@ "closed_registrations_modal.title": "إنشاء حساب على ماستدون", "collection.share_modal.share_link_label": "مشاركة الرابط", "collection.share_modal.share_via_post": "نشر على ماستدون", + "collection.share_modal.share_via_system": "المشاركة مع…", + "collection.share_modal.title": "مشاركة المجموعة", + "collection.share_modal.title_new": "شارِك مجموعتك الجديدة!", + "collection.share_template_other": "ألقِ نظرة على هذه المجموعة الرائعة:", + "collection.share_template_own": "ألقِ نظرة على مجموعتي الجديدة:", + "collections.account_count": "{count, plural, zero {لا حسابات} one {حساب واحد} two {حسابَين} few {# حسابات} many {# حساب} other {# حساب}}", + "collections.accounts.empty_description": "أضف ما يصل إلى {count} من الحسابات", + "collections.accounts.empty_editor_title": "لا يوجد أحد في هذه المجموعة حتى الآن", + "collections.accounts.empty_title": "هذه المجموعة فارغة", + "collections.add_to_collection": "إضافة {name} إلى المجموعات", "collections.block_collection_owner": "حظر الحساب", "collections.by_account": "مِن {account_handle}", "collections.collection_description": "الوصف", @@ -268,17 +381,41 @@ "collections.collection_language_none": "لا شيء", "collections.collection_name": "الاسم", "collections.collection_topic": "الموضوع", + "collections.confirm_account_removal": "هل أنت متأكّد من رغبتك في إزالة هذا الحساب من هذه المجموعة؟", "collections.content_warning": "تحذير عن المحتوى", "collections.continue": "مواصلة", "collections.copy_link": "نسخ الرابط", "collections.copy_link_confirmation": "نسخ الرابط إلى الحافظة", + "collections.create.accounts_title": "من ستضمّ في هذه المجموعة؟", "collections.create.basic_details_title": "المعلومات الأساسية", "collections.create.steps": "الخطوة {step}/{total}", + "collections.create_collection": "إنشاء مجموعة", + "collections.delete_collection": "حذف المجموعة", + "collections.description_length_hint": "الحد الأقصى هو ١٠٠ حرف", + "collections.detail.author_added_you_on_date": "أضافك {author} في {date}", + "collections.detail.loading": "جارٍ تحميل المجموعة…", "collections.detail.revoke_inclusion": "أزلني", "collections.detail.sensitive_content": "محتوى حساس", + "collections.detail.sensitive_note": "قد لا يكون الوصف والحسابات مناسبة لجميع المشاهدين.", + "collections.detail.share": "مشاركة هذه المجموعة", + "collections.detail.you_are_in_this_collection": "أنت مضموم في هذه المجموعة", "collections.edit_details": "تعديل التفاصيل", + "collections.error_loading_collections": "حدث خطأ أثناء محاولة تحميل هذه المجموعات.", + "collections.hidden_accounts_description": "لقد حظرت {count, plural, one {هذا المستخدم} two {هذَين المستخدمَين} other {هؤلاء المستخدمين}} أو كتمه", + "collections.hidden_accounts_link": "{count, plural, one {حساب واحد مخفي} two {حسابَين مخفيَّين} few {# حسابات مخفية} many {# حساب مخفي} other {# حساب مخفي}}", "collections.hints.accounts_counter": "{count}/{max} حسابات", + "collections.last_updated_at": "آخر تحديث: {date}", + "collections.list.collections_with_count": "{count, plural, zero {لا مجموعات} one {مجموعة واحدة} two {مجموعتَين} few {# مجموعات} many {# مجموعة} other {# مجموعة}}", + "collections.list.created_by_author": "أنشأهُ {name}", + "collections.list.created_by_you": "من إنشائك", + "collections.list.featuring_you": "تضمّك", "collections.manage_accounts": "إدارة الحسابات", + "collections.mark_as_sensitive": "التصنيف كحسّاس", + "collections.mark_as_sensitive_hint": "يُخفي هذا الخيار وصف المجموعة وحساباتها خلف تحذير بشأن المحتوى. سيظل اسم المجموعة ظاهرًا.", + "collections.maximum_collection_count_description": "يسمح خادومك بإنشاء ما يصل إلى {count} مجموعة.", + "collections.maximum_collection_count_reached": "لقد أنشأت الحد الأقصى لعدد المجموعات", + "collections.name_length_hint": "الحد الأقصى هو ٤٠ حرفًا", + "collections.new_collection": "مجموعة جديدة", "collections.remove_account": "إزالة", "collections.sensitive": "حساس", "collections.share_short": "مشاركة", diff --git a/app/javascript/mastodon/locales/be.json b/app/javascript/mastodon/locales/be.json index 71cb3a553f1..1fff2a1fc7a 100644 --- a/app/javascript/mastodon/locales/be.json +++ b/app/javascript/mastodon/locales/be.json @@ -584,6 +584,12 @@ "copy_icon_button.copy_this_text": "Скапіяваць спасылку ў буфер абмену", "copypaste.copied": "Скапіравана", "copypaste.copy_to_clipboard": "Скапіяваць у буфер абмену", + "custom_homepage.about": "Падрабязна", + "custom_homepage.about_this_server": "Аб гэтым серверы", + "custom_homepage.administered_by": "Адміністратар", + "custom_homepage.contact": "Кантакты:", + "custom_homepage.latest_activity": "Апошняя актыўнасць", + "custom_homepage.these_are_the_latest_posts": "Гэта апошнія 40 допісаў з уліковых запісаў гэтага сервера.", "directory.federated": "З вядомага федэральнага сусвету", "directory.local": "Толькі з {domain}", "directory.new_arrivals": "Новыя карыстальнікі", @@ -908,6 +914,7 @@ "navigation_bar.live_feed_local": "Жывая стужка (лакальная)", "navigation_bar.live_feed_public": "Жывая стужка (публічная)", "navigation_bar.logout": "Выйсці", + "navigation_bar.main": "Галоўная", "navigation_bar.moderation": "Мадэрацыя", "navigation_bar.more": "Больш", "navigation_bar.mutes": "Ігнараваныя карыстальнікі", @@ -1305,6 +1312,7 @@ "tabs_bar.menu": "Меню", "tabs_bar.notifications": "Апавяшчэнні", "tabs_bar.publish": "Новы допіс", + "tabs_bar.quick_links": "Хуткія спасылкі", "tabs_bar.search": "Пошук", "tag.remove": "Выдаліць", "terms_of_service.effective_as_of": "Дзейнічае да {date}", diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json index 93b6dddbf9a..c9e86a3ae36 100644 --- a/app/javascript/mastodon/locales/da.json +++ b/app/javascript/mastodon/locales/da.json @@ -584,6 +584,12 @@ "copy_icon_button.copy_this_text": "Kopiér link til udklipsholderen", "copypaste.copied": "Kopieret", "copypaste.copy_to_clipboard": "Kopiér til udklipsholder", + "custom_homepage.about": "Om", + "custom_homepage.about_this_server": "Om denne server", + "custom_homepage.administered_by": "Administreret af", + "custom_homepage.contact": "Kontakt:", + "custom_homepage.latest_activity": "Seneste aktivitet", + "custom_homepage.these_are_the_latest_posts": "Disse er de seneste 40 indlæg fra konti på denne server.", "directory.federated": "Fra kendt fediverse", "directory.local": "Kun fra {domain}", "directory.new_arrivals": "Nyankomne", @@ -908,6 +914,7 @@ "navigation_bar.live_feed_local": "Live feed (lokalt)", "navigation_bar.live_feed_public": "Live feed (offentligt)", "navigation_bar.logout": "Log af", + "navigation_bar.main": "Primær", "navigation_bar.moderation": "Moderering", "navigation_bar.more": "Mere", "navigation_bar.mutes": "Skjulte brugere", @@ -1305,6 +1312,7 @@ "tabs_bar.menu": "Menu", "tabs_bar.notifications": "Notifikationer", "tabs_bar.publish": "Nyt indlæg", + "tabs_bar.quick_links": "Hurtig-links", "tabs_bar.search": "Søg", "tag.remove": "Fjern", "terms_of_service.effective_as_of": "Gældende pr. {date}", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index 14c4f481717..76767a271ed 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -429,7 +429,7 @@ "collections.share_short": "Teilen", "collections.sort_alphabetical": "Alphabetisch", "collections.sort_by": "Sortieren nach:", - "collections.sort_date_added": "Datum des Hinzufügens", + "collections.sort_date_added": "Hinzugefügt", "collections.sort_last_active": "Neueste Aktivität", "collections.sort_most_followers": "Followerzahl", "collections.suggestions.can_not_add": "Kann nicht hinzugefügt werden", @@ -584,6 +584,12 @@ "copy_icon_button.copy_this_text": "Link in die Zwischenablage kopieren", "copypaste.copied": "Kopiert", "copypaste.copy_to_clipboard": "In die Zwischenablage kopieren", + "custom_homepage.about": "Über", + "custom_homepage.about_this_server": "Über diesen Server", + "custom_homepage.administered_by": "Administriert von", + "custom_homepage.contact": "Kontakt:", + "custom_homepage.latest_activity": "Neueste Aktivität", + "custom_homepage.these_are_the_latest_posts": "Diese sind die 40 neuesten Beiträge von Konten dieses Servers.", "directory.federated": "Aus bekanntem Fediverse", "directory.local": "Nur von dieser Domain {domain}", "directory.new_arrivals": "Neue Profile", @@ -908,6 +914,7 @@ "navigation_bar.live_feed_local": "Live-Feed (Dieser Server)", "navigation_bar.live_feed_public": "Live-Feed (Alle Server)", "navigation_bar.logout": "Abmelden", + "navigation_bar.main": "Hauptmenü", "navigation_bar.moderation": "Moderation", "navigation_bar.more": "Mehr", "navigation_bar.mutes": "Stummgeschaltete Profile", @@ -1305,6 +1312,7 @@ "tabs_bar.menu": "Menü", "tabs_bar.notifications": "Benachrichtigungen", "tabs_bar.publish": "Neuer Beitrag", + "tabs_bar.quick_links": "Schnellzugriff", "tabs_bar.search": "Suche", "tag.remove": "Entfernen", "terms_of_service.effective_as_of": "Gültig ab {date}", diff --git a/app/javascript/mastodon/locales/el.json b/app/javascript/mastodon/locales/el.json index c1d03903203..745e23c335a 100644 --- a/app/javascript/mastodon/locales/el.json +++ b/app/javascript/mastodon/locales/el.json @@ -584,6 +584,12 @@ "copy_icon_button.copy_this_text": "Αντιγραφή συνδέσμου στο πρόχειρο", "copypaste.copied": "Αντιγράφηκε", "copypaste.copy_to_clipboard": "Αντιγραφή στο πρόχειρο", + "custom_homepage.about": "Σχετικά με", + "custom_homepage.about_this_server": "Σχετικά μ' αυτόν τον διακομιστή", + "custom_homepage.administered_by": "Διαχειρίζεται από", + "custom_homepage.contact": "Επικοινωνία:", + "custom_homepage.latest_activity": "Τελευταία δραστηριότητα", + "custom_homepage.these_are_the_latest_posts": "Αυτές είναι οι τελευταίες 40 αναρτήσεις από λογαριασμούς σε αυτόν τον διακομιστή.", "directory.federated": "Από το γνωστό fediverse", "directory.local": "Μόνο από {domain}", "directory.new_arrivals": "Νέες αφίξεις", @@ -805,7 +811,7 @@ "keyboard_shortcuts.column": "Εστίαση στη στήλη", "keyboard_shortcuts.compose": "Εστίαση στην περιοχή συγγραφής κειμένου", "keyboard_shortcuts.description": "Περιγραφή", - "keyboard_shortcuts.direct": "Άνοιγμα της στήλης ιδιωτικών επισημάνσεων", + "keyboard_shortcuts.direct": "Άνοιγμα στήλης ιδιωτικών επισημάνσεων", "keyboard_shortcuts.down": "Μετακίνηση προς τα κάτω στη λίστα", "keyboard_shortcuts.enter": "Άνοιγμα ανάρτησης", "keyboard_shortcuts.explore": "Άνοιγμα χρονολογίου τάσεων", @@ -829,9 +835,9 @@ "keyboard_shortcuts.reply": "Απάντηση στην ανάρτηση", "keyboard_shortcuts.requests": "Άνοιγμα λίστας αιτημάτων ακολούθησης", "keyboard_shortcuts.search": "Εστίαση στη γραμμή αναζήτησης", - "keyboard_shortcuts.spoilers": "Εμφάνιση/απόκρυψη πεδίου CW", + "keyboard_shortcuts.spoilers": "Εμφάνιση/απόκρυψη πεδίου προειδοποίησης περιεχομένου (CW)", "keyboard_shortcuts.start": "Άνοιγμα της στήλης \"Ας ξεκινήσουμε\"", - "keyboard_shortcuts.toggle_hidden": "Εμφάνιση/απόκρυψη κειμένου πίσω από το CW", + "keyboard_shortcuts.toggle_hidden": "Εμφάνιση/απόκρυψη κειμένου πίσω από προειδοποίηση περιεχομένου (CW)", "keyboard_shortcuts.toggle_sensitivity": "Εμφάνιση/απόκρυψη πολυμέσων", "keyboard_shortcuts.toot": "Δημιουργία νέας ανάρτησης", "keyboard_shortcuts.top": "Μετακίνηση στην κορυφή της λίστας", @@ -908,6 +914,7 @@ "navigation_bar.live_feed_local": "Ζωντανή ροή (τοπική)", "navigation_bar.live_feed_public": "Ζωντανή ροή (δημόσια)", "navigation_bar.logout": "Αποσύνδεση", + "navigation_bar.main": "Κύρια", "navigation_bar.moderation": "Συντονισμός", "navigation_bar.more": "Περισσότερα", "navigation_bar.mutes": "Αποσιωπημένοι χρήστες", @@ -1305,6 +1312,7 @@ "tabs_bar.menu": "Μενού", "tabs_bar.notifications": "Ειδοποιήσεις", "tabs_bar.publish": "Νέα Ανάρτηση", + "tabs_bar.quick_links": "Γρήγοροι σύνδεσμοι", "tabs_bar.search": "Αναζήτηση", "tag.remove": "Αφαίρεση", "terms_of_service.effective_as_of": "Ενεργό από {date}", diff --git a/app/javascript/mastodon/locales/es-AR.json b/app/javascript/mastodon/locales/es-AR.json index fddee1f6d41..4cf1086871e 100644 --- a/app/javascript/mastodon/locales/es-AR.json +++ b/app/javascript/mastodon/locales/es-AR.json @@ -584,6 +584,12 @@ "copy_icon_button.copy_this_text": "Copiar enlace al portapapeles", "copypaste.copied": "Copiado", "copypaste.copy_to_clipboard": "Copiar al portapapeles", + "custom_homepage.about": "Información", + "custom_homepage.about_this_server": "Acerca de este servidor", + "custom_homepage.administered_by": "Administrado por", + "custom_homepage.contact": "Contacto:", + "custom_homepage.latest_activity": "Última actividad", + "custom_homepage.these_are_the_latest_posts": "Estas son las últimas 40 publicaciones de cuentas de este servidor.", "directory.federated": "Desde fediverso conocido", "directory.local": "Solo de {domain}", "directory.new_arrivals": "Recién llegados", @@ -908,6 +914,7 @@ "navigation_bar.live_feed_local": "Línea temporal (local)", "navigation_bar.live_feed_public": "Línea temporal (federada)", "navigation_bar.logout": "Cerrar sesión", + "navigation_bar.main": "Principal", "navigation_bar.moderation": "Moderación", "navigation_bar.more": "Más", "navigation_bar.mutes": "Usuarios silenciados", @@ -1305,6 +1312,7 @@ "tabs_bar.menu": "Menú", "tabs_bar.notifications": "Notificaciones", "tabs_bar.publish": "Nuevo mensaje", + "tabs_bar.quick_links": "Enlaces rápidos", "tabs_bar.search": "Buscar", "tag.remove": "Quitar", "terms_of_service.effective_as_of": "Efectivo a partir de {date}", diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json index 6714d97b23f..2d9d8493d60 100644 --- a/app/javascript/mastodon/locales/es-MX.json +++ b/app/javascript/mastodon/locales/es-MX.json @@ -367,8 +367,8 @@ "collection.share_modal.share_via_system": "Compartir con…", "collection.share_modal.title": "Compartir la colección", "collection.share_modal.title_new": "¡Comparte tu nueva colección!", - "collection.share_template_other": "Mira esta colección tan chula:", - "collection.share_template_own": "Mira mi nueva colección:", + "collection.share_template_other": "Echa un vistazo a esta genial colección:", + "collection.share_template_own": "Echa un vistazo a mi nueva colección:", "collections.account_count": "{count, plural,one {# cuenta} other {# cuentas}}", "collections.accounts.empty_description": "Añade hasta {count} cuentas", "collections.accounts.empty_editor_title": "No hay nadie en esta colección todavía", @@ -908,6 +908,7 @@ "navigation_bar.live_feed_local": "Cronología local", "navigation_bar.live_feed_public": "Cronología pública", "navigation_bar.logout": "Cerrar sesión", + "navigation_bar.main": "Principal", "navigation_bar.moderation": "Moderación", "navigation_bar.more": "Más", "navigation_bar.mutes": "Usuarios silenciados", @@ -1305,6 +1306,7 @@ "tabs_bar.menu": "Menú", "tabs_bar.notifications": "Notificaciones", "tabs_bar.publish": "Nueva publicación", + "tabs_bar.quick_links": "Enlaces rápidos", "tabs_bar.search": "Buscar", "tag.remove": "Eliminar", "terms_of_service.effective_as_of": "En vigor a partir del {date}", diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json index 283da08a4fc..e685ccf1c81 100644 --- a/app/javascript/mastodon/locales/es.json +++ b/app/javascript/mastodon/locales/es.json @@ -59,7 +59,7 @@ "account.follow_request_cancel_short": "Cancelar", "account.follow_request_short": "Solicitar", "account.followers": "Seguidores", - "account.followers.empty": "Todavía nadie sigue a este usuario.", + "account.followers.empty": "Nadie sigue a este usuario todavía.", "account.followers_counter": "{count, plural, one {{counter} seguidor} other {{counter} seguidores}}", "account.followers_you_know_counter": "{counter} que conoces", "account.following": "Siguiendo", @@ -908,6 +908,7 @@ "navigation_bar.live_feed_local": "Cronología local", "navigation_bar.live_feed_public": "Cronología pública", "navigation_bar.logout": "Cerrar sesión", + "navigation_bar.main": "Principal", "navigation_bar.moderation": "Moderación", "navigation_bar.more": "Más", "navigation_bar.mutes": "Usuarios silenciados", @@ -1305,6 +1306,7 @@ "tabs_bar.menu": "Menú", "tabs_bar.notifications": "Notificaciones", "tabs_bar.publish": "Nueva Publicación", + "tabs_bar.quick_links": "Enlaces rápidos", "tabs_bar.search": "Buscar", "tag.remove": "Eliminar", "terms_of_service.effective_as_of": "En vigor a partir del {date}", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index de639481624..cc31f5c45b9 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -584,6 +584,12 @@ "copy_icon_button.copy_this_text": "Kopioi linkki leikepöydälle", "copypaste.copied": "Kopioitu", "copypaste.copy_to_clipboard": "Kopioi leikepöydälle", + "custom_homepage.about": "Tietoja", + "custom_homepage.about_this_server": "Tietoja tästä palvelimesta", + "custom_homepage.administered_by": "Ylläpitäjänä", + "custom_homepage.contact": "Yhteydenotto:", + "custom_homepage.latest_activity": "Viimeisin toiminta", + "custom_homepage.these_are_the_latest_posts": "Nämä ovat tämän palvelimen 40 viimeisintä julkaisua.", "directory.federated": "Tunnetusta fediversumista", "directory.local": "Vain palvelimelta {domain}", "directory.new_arrivals": "Äskettäin saapuneet", @@ -1305,6 +1311,7 @@ "tabs_bar.menu": "Valikko", "tabs_bar.notifications": "Ilmoitukset", "tabs_bar.publish": "Uusi julkaisu", + "tabs_bar.quick_links": "Pikalinkit", "tabs_bar.search": "Haku", "tag.remove": "Poista", "terms_of_service.effective_as_of": "Tulee voimaan {date}", diff --git a/app/javascript/mastodon/locales/fr-CA.json b/app/javascript/mastodon/locales/fr-CA.json index a2969fe6f85..906af6352b3 100644 --- a/app/javascript/mastodon/locales/fr-CA.json +++ b/app/javascript/mastodon/locales/fr-CA.json @@ -584,6 +584,12 @@ "copy_icon_button.copy_this_text": "Copier le lien dans le presse-papier", "copypaste.copied": "Copié", "copypaste.copy_to_clipboard": "Copier dans le presse-papiers", + "custom_homepage.about": "À propos", + "custom_homepage.about_this_server": "À propos de ce serveur", + "custom_homepage.administered_by": "Administré par", + "custom_homepage.contact": "Contact :", + "custom_homepage.latest_activity": "Dernière activité", + "custom_homepage.these_are_the_latest_posts": "Voici les 40 derniers messages des comptes de ce serveur.", "directory.federated": "D'un fediverse connu", "directory.local": "De {domain} seulement", "directory.new_arrivals": "Inscrit·e·s récemment", @@ -908,6 +914,7 @@ "navigation_bar.live_feed_local": "Flux en direct (local)", "navigation_bar.live_feed_public": "Flux en direct (public)", "navigation_bar.logout": "Se déconnecter", + "navigation_bar.main": "Accueil", "navigation_bar.moderation": "Modération", "navigation_bar.more": "Plus", "navigation_bar.mutes": "Utilisateurs masqués", @@ -1305,6 +1312,7 @@ "tabs_bar.menu": "Menu", "tabs_bar.notifications": "Notifications", "tabs_bar.publish": "Nouveau message", + "tabs_bar.quick_links": "Accès rapides", "tabs_bar.search": "Chercher", "tag.remove": "Supprimer", "terms_of_service.effective_as_of": "En vigueur à compter du {date}", diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index 9fa31894202..90341ac6de3 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -584,6 +584,12 @@ "copy_icon_button.copy_this_text": "Copier le lien dans le presse-papier", "copypaste.copied": "Copié", "copypaste.copy_to_clipboard": "Copier dans le presse-papiers", + "custom_homepage.about": "À propos", + "custom_homepage.about_this_server": "À propos de ce serveur", + "custom_homepage.administered_by": "Administré par", + "custom_homepage.contact": "Contact :", + "custom_homepage.latest_activity": "Dernière activité", + "custom_homepage.these_are_the_latest_posts": "Voici les 40 derniers messages des comptes de ce serveur.", "directory.federated": "Du fédivers connu", "directory.local": "De {domain} seulement", "directory.new_arrivals": "Inscrit·e·s récemment", @@ -908,6 +914,7 @@ "navigation_bar.live_feed_local": "Flux en direct (local)", "navigation_bar.live_feed_public": "Flux en direct (public)", "navigation_bar.logout": "Déconnexion", + "navigation_bar.main": "Accueil", "navigation_bar.moderation": "Modération", "navigation_bar.more": "Plus", "navigation_bar.mutes": "Comptes masqués", @@ -1305,6 +1312,7 @@ "tabs_bar.menu": "Menu", "tabs_bar.notifications": "Notifications", "tabs_bar.publish": "Nouveau message", + "tabs_bar.quick_links": "Accès rapides", "tabs_bar.search": "Chercher", "tag.remove": "Supprimer", "terms_of_service.effective_as_of": "En vigueur à compter du {date}", diff --git a/app/javascript/mastodon/locales/ga.json b/app/javascript/mastodon/locales/ga.json index 81ab906c87c..ae4ec98b68b 100644 --- a/app/javascript/mastodon/locales/ga.json +++ b/app/javascript/mastodon/locales/ga.json @@ -367,6 +367,8 @@ "collection.share_modal.share_via_system": "Comhroinn le…", "collection.share_modal.title": "Comhroinn bailiúchán", "collection.share_modal.title_new": "Roinn do bhailiúchán nua!", + "collection.share_template_other": "Féach ar an mbailiúchán fionnuar seo:", + "collection.share_template_own": "Féach ar mo bhailiúchán nua:", "collections.account_count": "{count, plural, one {# cuntas} two {# cuntais} few {# cuntais} many {# cuntais} other {# cuntais}}", "collections.accounts.empty_description": "Cuir suas le {count} cuntas leis", "collections.accounts.empty_editor_title": "Níl aon duine sa bhailiúchán seo fós", @@ -906,6 +908,7 @@ "navigation_bar.live_feed_local": "Fotha beo (áitiúil)", "navigation_bar.live_feed_public": "Fotha beo (poiblí)", "navigation_bar.logout": "Logáil Amach", + "navigation_bar.main": "Príomh", "navigation_bar.moderation": "Measarthacht", "navigation_bar.more": "Tuilleadh", "navigation_bar.mutes": "Úsáideoirí balbhaithe", @@ -1303,6 +1306,7 @@ "tabs_bar.menu": "Roghchlár", "tabs_bar.notifications": "Fógraí", "tabs_bar.publish": "Post Nua", + "tabs_bar.quick_links": "Naisc thapa", "tabs_bar.search": "Cuardaigh", "tag.remove": "Bain", "terms_of_service.effective_as_of": "I bhfeidhm ó {date}", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 216a6d1d1e2..9cbf31fe1f1 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -367,6 +367,8 @@ "collection.share_modal.share_via_system": "Compartir con…", "collection.share_modal.title": "Compartir colección", "collection.share_modal.title_new": "Comparte a túa nova colección!", + "collection.share_template_other": "Mira que colección máis boa:", + "collection.share_template_own": "Mira a miña nova colección:", "collections.account_count": "{count, plural, one {# conta} other {# contas}}", "collections.accounts.empty_description": "Engade ate {count} contas", "collections.accounts.empty_editor_title": "Aínda non hai ninguén nesta colección", @@ -582,6 +584,12 @@ "copy_icon_button.copy_this_text": "Copiar a ligazón ao portapapeis", "copypaste.copied": "Copiado", "copypaste.copy_to_clipboard": "Copiar ao portapapeis", + "custom_homepage.about": "Sobre", + "custom_homepage.about_this_server": "Sobre este servidor", + "custom_homepage.administered_by": "Xestionado por", + "custom_homepage.contact": "Contacto:", + "custom_homepage.latest_activity": "Actividade recente", + "custom_homepage.these_are_the_latest_posts": "Estas son as últimas 40 publicacións das contas deste servidor.", "directory.federated": "Do fediverso coñecido", "directory.local": "Só de {domain}", "directory.new_arrivals": "Recén chegadas", @@ -906,6 +914,7 @@ "navigation_bar.live_feed_local": "En directo (local)", "navigation_bar.live_feed_public": "En directo (federada)", "navigation_bar.logout": "Pechar sesión", + "navigation_bar.main": "Inicio", "navigation_bar.moderation": "Moderación", "navigation_bar.more": "Máis", "navigation_bar.mutes": "Usuarias silenciadas", @@ -1303,6 +1312,7 @@ "tabs_bar.menu": "Menú", "tabs_bar.notifications": "Notificacións", "tabs_bar.publish": "Nova publicación", + "tabs_bar.quick_links": "Acceso rápido", "tabs_bar.search": "Buscar", "tag.remove": "Retirar", "terms_of_service.effective_as_of": "Con efecto desde o {date}", diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json index af6e2cbdbc5..79d20d07ce3 100644 --- a/app/javascript/mastodon/locales/he.json +++ b/app/javascript/mastodon/locales/he.json @@ -367,6 +367,8 @@ "collection.share_modal.share_via_system": "לשתף אל…", "collection.share_modal.title": "שיתוף אוסף", "collection.share_modal.title_new": "שתפו את האוסף החדש שלכם!", + "collection.share_template_other": "הציצו על האוסף המעניין הזה:", + "collection.share_template_own": "הציצו על האוסף החדש שלי:", "collections.account_count": "{count, plural, one {חשבון אחד} other {# חשבונות}}", "collections.accounts.empty_description": "להוסיף עד ל־{count} חשבונות", "collections.accounts.empty_editor_title": "אוסף זה ריק כרגע", @@ -582,6 +584,12 @@ "copy_icon_button.copy_this_text": "העתקת הקישור", "copypaste.copied": "הועתק", "copypaste.copy_to_clipboard": "העתקה ללוח הגזירים", + "custom_homepage.about": "אודות", + "custom_homepage.about_this_server": "אודות שרת זה", + "custom_homepage.administered_by": "מנוהל ע\"י", + "custom_homepage.contact": "יצירת קשר:", + "custom_homepage.latest_activity": "הפעילות האחרונה", + "custom_homepage.these_are_the_latest_posts": "הנה 40 הפרסומים האחרונים מחשבונות שעל שרת זה.", "directory.federated": "מהפדרציה הידועה", "directory.local": "מ- {domain} בלבד", "directory.new_arrivals": "חדשים כאן", @@ -906,6 +914,7 @@ "navigation_bar.live_feed_local": "פיד ההודעות בזמן אמת (מקומי)", "navigation_bar.live_feed_public": "פיד ההודעות בזמן אמת (פומבי)", "navigation_bar.logout": "התנתקות", + "navigation_bar.main": "ראשי", "navigation_bar.moderation": "הנחיית דיונים", "navigation_bar.more": "עוד", "navigation_bar.mutes": "משתמשים בהשתקה", @@ -1303,6 +1312,7 @@ "tabs_bar.menu": "תפריט", "tabs_bar.notifications": "התראות", "tabs_bar.publish": "הודעה חדשה", + "tabs_bar.quick_links": "קישורים מהירים", "tabs_bar.search": "חיפוש", "tag.remove": "הסרה", "terms_of_service.effective_as_of": "בתוקף החל מתאריך {date}", diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index 5f421e7fde8..52a070728e7 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -456,7 +456,7 @@ "column.domain_blocks": "Letiltott domainek", "column.edit_list": "Lista módosítása", "column.favourites": "Kedvencek", - "column.firehose": "Hírfolyamok", + "column.firehose": "Élő hírfolyamok", "column.firehose_local": "Élő hírfolyam a kiszolgálóhoz", "column.firehose_singular": "Élő hírfolyam", "column.follow_requests": "Követési kérések", @@ -584,6 +584,12 @@ "copy_icon_button.copy_this_text": "Hivatkozás vágólapra másolása", "copypaste.copied": "Másolva", "copypaste.copy_to_clipboard": "Másolás vágólapra", + "custom_homepage.about": "Névjegy", + "custom_homepage.about_this_server": "A kiszolgáló névjegye", + "custom_homepage.administered_by": "Adminisztrátor:", + "custom_homepage.contact": "Kapcsolat:", + "custom_homepage.latest_activity": "Legújabb tevékenység", + "custom_homepage.these_are_the_latest_posts": "Ez a legutóbbi 40 bejegyzés a kiszolgáló fiókjaitól.", "directory.federated": "Az ismert födiverzumból", "directory.local": "Csak {domain} tartományból", "directory.new_arrivals": "Új csatlakozók", @@ -1305,6 +1311,7 @@ "tabs_bar.menu": "Menü", "tabs_bar.notifications": "Értesítések", "tabs_bar.publish": "Új bejegyzés", + "tabs_bar.quick_links": "Gyors hivatkozások", "tabs_bar.search": "Keresés", "tag.remove": "Eltávolítás", "terms_of_service.effective_as_of": "Hatálybalépés dátuma: {date}", diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json index 2ffafd985b0..da940775c50 100644 --- a/app/javascript/mastodon/locales/is.json +++ b/app/javascript/mastodon/locales/is.json @@ -86,6 +86,7 @@ "account.locked_info": "Staða gagnaleyndar á þessum aðgangi er stillt á læsingu. Eigandinn yfirfer handvirkt hverjir geti fylgst með honum.", "account.media": "Myndefni", "account.mention": "Minnast á @{name}", + "account.menu.add_to_collection": "Bæta við í safn…", "account.menu.add_to_list": "Bæta á lista…", "account.menu.block": "Útiloka notandaaðgang", "account.menu.block_domain": "Útiloka {domain}", @@ -366,10 +367,13 @@ "collection.share_modal.share_via_system": "Deila með…", "collection.share_modal.title": "Deila safni", "collection.share_modal.title_new": "Deildu nýja safninu þínu!", + "collection.share_template_other": "Kíktu á þetta áhugaverða safn:", + "collection.share_template_own": "Kíktu á nýja safnið mitt:", "collections.account_count": "{count, plural, one {# aðgangur} other {# aðgangar}}", "collections.accounts.empty_description": "Bættu við allt að {count} aðgöngum", "collections.accounts.empty_editor_title": "Enginn er enn í þessu safni", "collections.accounts.empty_title": "Þetta safn er tómt", + "collections.add_to_collection": "Bæta {name} við söfn", "collections.block_collection_owner": "Útiloka notandaaðgang", "collections.by_account": "frá {account_handle}", "collections.collection_description": "Lýsing", @@ -392,6 +396,7 @@ "collections.detail.loading": "Hleð inn safni…", "collections.detail.revoke_inclusion": "Fjarlægja mig", "collections.detail.sensitive_content": "Viðkvæmt efni", + "collections.detail.sensitive_note": "Lýsing og aðgangar gætu ekki hentað hverjum sem er.", "collections.detail.share": "Deila þessu safni", "collections.detail.you_are_in_this_collection": "Þú kemur fyrir í þessu safni", "collections.edit_details": "Breyta ítarupplýsingum", @@ -422,6 +427,11 @@ "collections.search_accounts_max_reached": "Þú hefur þegar bætt við leyfilegum hámarksfjölda aðganga", "collections.sensitive": "Viðkvæmt", "collections.share_short": "Deila", + "collections.sort_alphabetical": "Stafrófsröð", + "collections.sort_by": "Raða eftir:", + "collections.sort_date_added": "Dagsetning skráningar", + "collections.sort_last_active": "Síðasta virkni", + "collections.sort_most_followers": "Flestir fylgjendur", "collections.suggestions.can_not_add": "Er ekki hægt að bæta við", "collections.suggestions.can_not_add_desc": "Þessir aðgangar gætu hafa skráð sig úr almennri birtingu eða gætu verið á netþjónum sem ekki styðja söfn.", "collections.suggestions.must_follow": "Verður fyrst að fylgja", @@ -574,6 +584,12 @@ "copy_icon_button.copy_this_text": "Afrita tengil á klippispjald", "copypaste.copied": "Afritað", "copypaste.copy_to_clipboard": "Afrita á klippispjald", + "custom_homepage.about": "Um aðganginn", + "custom_homepage.about_this_server": "Um þennan netþjón", + "custom_homepage.administered_by": "Stýrt af", + "custom_homepage.contact": "Hafa samband:", + "custom_homepage.latest_activity": "Síðasta virkni", + "custom_homepage.these_are_the_latest_posts": "Þetta eru síðustu 40 færslur frá notendum á þessum netþjóni.", "directory.federated": "Frá samtengdum vefþjónum", "directory.local": "Einungis frá {domain}", "directory.new_arrivals": "Nýkomnir", @@ -633,6 +649,7 @@ "empty_column.blocks": "Þú hefur ekki ennþá útilokað neina notendur.", "empty_column.bookmarked_statuses": "Þú ert ekki ennþá með neinar bókamerktar færslur. Þegar þú bókamerkir færslu, mun það birtast hér.", "empty_column.collections.featured_in": "Þér hefur enn ekki verið bætt við nein söfn.", + "empty_column.collections.featured_in_undiscoverable": "Til þess að fólk geti bætt þér í söfn þá þarftu að leyfa að þú komir upp í leitum, en það er gert í Kjörstillingar > Gagnaleynd og útbreiðsla", "empty_column.community": "Staðværa tímalínan er tóm. Skrifaðu eitthvað opinberlega til að láta boltann fara að rúlla!", "empty_column.direct": "Þú ert ekki ennþá með neitt einkaspjall við neinn. Þegar þú sendir eða tekur við slíku, mun það birtast hér.", "empty_column.disabled_feed": "Þetta streymi hefur verið gert óvirkt af stjórnendum netþjónis þíns.", @@ -897,6 +914,7 @@ "navigation_bar.live_feed_local": "Bein streymi (á netþjóni)", "navigation_bar.live_feed_public": "Bein streymi (opinber)", "navigation_bar.logout": "Útskráning", + "navigation_bar.main": "Aðalstýring", "navigation_bar.moderation": "Umsjón", "navigation_bar.more": "Meira", "navigation_bar.mutes": "Þaggaðir notendur", @@ -1294,6 +1312,7 @@ "tabs_bar.menu": "Valmynd", "tabs_bar.notifications": "Tilkynningar", "tabs_bar.publish": "Ný færsla", + "tabs_bar.quick_links": "Flýtitenglar", "tabs_bar.search": "Leita", "tag.remove": "Fjarlægja", "terms_of_service.effective_as_of": "Gildir frá og með {date}", diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json index 9364e9bafb2..080e25da4e8 100644 --- a/app/javascript/mastodon/locales/it.json +++ b/app/javascript/mastodon/locales/it.json @@ -367,6 +367,8 @@ "collection.share_modal.share_via_system": "Condividi con…", "collection.share_modal.title": "Condividi la collezione", "collection.share_modal.title_new": "Condividi la tua nuova collezione!", + "collection.share_template_other": "Dai un'occhiata a questa fantastica collezione:", + "collection.share_template_own": "Dai un'occhiata alla mia nuova collezione:", "collections.account_count": "{count, plural, one {# account} other {# account}}", "collections.accounts.empty_description": "Aggiungi fino a {count} account", "collections.accounts.empty_editor_title": "Nessuno è ancora in questa collezione", @@ -582,6 +584,12 @@ "copy_icon_button.copy_this_text": "Copia il link negli appunti", "copypaste.copied": "Copiato", "copypaste.copy_to_clipboard": "Copia negli Appunti", + "custom_homepage.about": "Info", + "custom_homepage.about_this_server": "Informazioni su questo server", + "custom_homepage.administered_by": "Amministrato da", + "custom_homepage.contact": "Contatto:", + "custom_homepage.latest_activity": "Attività più recente", + "custom_homepage.these_are_the_latest_posts": "Questi sono gli ultimi 40 post da account presenti su questo server.", "directory.federated": "Da un fediverse noto", "directory.local": "Solo da {domain}", "directory.new_arrivals": "Nuovi arrivi", @@ -712,7 +720,7 @@ "follow_suggestions.hints.friends_of_friends": "Questo profilo è popolare tra le persone che segui.", "follow_suggestions.hints.most_followed": "Questo profilo è uno dei più seguiti su {domain}.", "follow_suggestions.hints.most_interactions": "Recentemente, questo profilo ha ricevuto molta attenzione su {domain}.", - "follow_suggestions.hints.similar_to_recently_followed": "Questo profilo è simile ai profili che hai seguito più recentemente.", + "follow_suggestions.hints.similar_to_recently_followed": "Questo profilo è simile a quelli che hai iniziato a seguire più recentemente.", "follow_suggestions.personalized_suggestion": "Suggerimento personalizzato", "follow_suggestions.popular_suggestion": "Suggerimento frequente", "follow_suggestions.popular_suggestion_longer": "Popolare su {domain}", @@ -906,6 +914,7 @@ "navigation_bar.live_feed_local": "Feed in diretta (locale)", "navigation_bar.live_feed_public": "Feed in diretta (pubblico)", "navigation_bar.logout": "Disconnettiti", + "navigation_bar.main": "Menù principale", "navigation_bar.moderation": "Moderazione", "navigation_bar.more": "Altro", "navigation_bar.mutes": "Utenti silenziati", @@ -1303,6 +1312,7 @@ "tabs_bar.menu": "Menu", "tabs_bar.notifications": "Notifiche", "tabs_bar.publish": "Nuovo post", + "tabs_bar.quick_links": "Collegamenti rapidi", "tabs_bar.search": "Cerca", "tag.remove": "Rimuovi", "terms_of_service.effective_as_of": "In vigore a partire dal giorno {date}", diff --git a/app/javascript/mastodon/locales/kab.json b/app/javascript/mastodon/locales/kab.json index 46a0d6e5642..a07c68efcb7 100644 --- a/app/javascript/mastodon/locales/kab.json +++ b/app/javascript/mastodon/locales/kab.json @@ -78,11 +78,13 @@ "account.locked_info": "Amiḍan-agi uslig isekweṛ. D bab-is kan i izemren ad yeǧǧ, s ufus-is, win ara t-iḍefṛen.", "account.media": "Timidyatin", "account.mention": "Bder-d @{name}", + "account.menu.add_to_collection": "Rnu-t ɣer telkensit…", "account.menu.add_to_list": "Rnu ɣer tebdart…", "account.menu.block": "Sewḥel amiḍan", "account.menu.block_domain": "Sewḥel {domain}", "account.menu.copied": "Aseɣwen n umiḍan yettwanɣel ɣer tecwafit", "account.menu.copy": "Nɣel aseɣwen", + "account.menu.direct": "Abdar uslig", "account.menu.mention": "Bder-d", "account.menu.mute": "Sgugem amiḍan", "account.menu.note.description": "Ad tettbin i kečč·mm kan", @@ -91,6 +93,7 @@ "account.menu.report": "Cetki ɣef umiḍan-a", "account.menu.share": "Zuzer…", "account.menu.unblock": "Kkes asewḥel i umiḍan", + "account.menu.unblock_domain": "Serreḥ i {domain}", "account.menu.unmute": "Kkes asgugem ɣef umiḍan", "account.moved_to": "{name} yenna-d dakken amiḍan-is amaynut yuɣal :", "account.mute": "Sgugem @{name}", diff --git a/app/javascript/mastodon/locales/mk.json b/app/javascript/mastodon/locales/mk.json index ee326baf5f7..567c586aff3 100644 --- a/app/javascript/mastodon/locales/mk.json +++ b/app/javascript/mastodon/locales/mk.json @@ -1,29 +1,56 @@ { "about.blocks": "Модерирани сервери", "about.contact": "Контакт:", + "about.default_locale": "Стандардно", "about.disclaimer": "Mastodon е бесплатен, open-source софтвер, и заштитен знак на Mastodon gGmbH.", + "about.domain_blocks.no_reason_available": "Причината не е достапна", "about.domain_blocks.preamble": "Mastodon вообичаено ви дозволува да прегледувате содржини и комуницирате со корисниците од било кој сервер во федиверзумот. На овој сервер има исклучоци.", "about.domain_blocks.silenced.explanation": "Вообичаено нема да гледате профили и содржина од овој сервер, освен ако не го пребарате намерно, или го заследите.", "about.domain_blocks.silenced.title": "Ограничено", "about.domain_blocks.suspended.explanation": "Податоците од овој сервер нема да бидат процесирани, зачувани или сменети и било која интеракција или комуникација со корисниците од овој сервер ќе биде невозможна.", "about.domain_blocks.suspended.title": "Суспендиран", + "about.language_label": "Јазик", "about.not_available": "Оваа информација не е достапна на овој сервер.", "about.powered_by": "Децентрализиран друштвен медиум овозможен од {mastodon}", "about.rules": "Правила на серверот", + "account.account_note_header": "Лична забелешка", + "account.activity": "Активност", + "account.add_note": "Додај лична забелешка", "account.add_or_remove_from_list": "Додади или одстрани од листа", + "account.badges.admin": "Админ", + "account.badges.blocked": "Блокиран", "account.badges.bot": "Бот", + "account.badges.domain_blocked": "Блокиран домен", "account.badges.group": "Група", + "account.badges.muted": "Исклучен глас", + "account.badges.muted_until": "Исклучен глас до {until}", "account.block": "Блокирај @{name}", "account.block_domain": "Сокријај се од {domain}", + "account.block_short": "Блокирај", "account.blocked": "Блокиран", "account.cancel_follow_request": "Withdraw follow request", + "account.copy": "Копирај линк до профилот", + "account.direct": "Тивко спомни @{name}", + "account.disable_notifications": "Престани да ме известуваш кога @{name} постира", + "account.edit_note": "Измени лична забелешка", "account.edit_profile": "Измени профил", + "account.edit_profile_short": "Измени", + "account.enable_notifications": "Извести ме кога @{name} постира", "account.endorse": "Карактеристики на профилот", + "account.featured.accounts": "Профили", + "account.featured.collections": "Колекции", + "account.featured.new_collection": "Нова колекција", + "account.field_overflow": "Покажи цела содржина", + "account.filters.all": "Сета активност", "account.follow": "Следи", + "account.follow_back": "Заследи назад", + "account.follow_back_short": "Заследи назад", + "account.follow_request_cancel_short": "Откажи", "account.followers": "Следбеници", "account.followers.empty": "Никој не го следи овој корисник сеуште.", "account.follows.empty": "Корисникот не следи никој сеуште.", "account.hide_reblogs": "Сокриј буст од @{name}", + "account.join_modal.day": "Ден", "account.link_verified_on": "Сопстевноста на овај линк беше проверен на {date}", "account.locked_info": "Статусот на приватност на овај корисник е сетиран како заклучен. Корисникот одлучува кој можи да го следи него.", "account.media": "Медија", diff --git a/app/javascript/mastodon/locales/nan-TW.json b/app/javascript/mastodon/locales/nan-TW.json index 450e9312883..72f28919d9d 100644 --- a/app/javascript/mastodon/locales/nan-TW.json +++ b/app/javascript/mastodon/locales/nan-TW.json @@ -86,6 +86,7 @@ "account.locked_info": "Tsit ê口座ê隱私狀態鎖起來ah。所有者ē手動審查thang kā跟tuè ê lâng。", "account.media": "媒體", "account.mention": "提起 @{name}", + "account.menu.add_to_collection": "編輯收藏……", "account.menu.add_to_list": "加入去列單……", "account.menu.block": "封鎖口座", "account.menu.block_domain": "封鎖 {domain}", @@ -366,10 +367,13 @@ "collection.share_modal.share_via_system": "分享kàu……", "collection.share_modal.title": "分享收藏", "collection.share_modal.title_new": "分享lí ê新收藏!", + "collection.share_template_other": "緊看覓chit ê時行ê收藏:", + "collection.share_template_own": "緊看覓我ê收藏:", "collections.account_count": "{count, plural, other {# ê口座}}", "collections.accounts.empty_description": "加上tsē {count} ê口座", "collections.accounts.empty_editor_title": "Tsit ê 收藏內底iáu無半ê lâng", "collections.accounts.empty_title": "收藏內底無半項", + "collections.add_to_collection": "Kā {name} 加入去收藏", "collections.block_collection_owner": "封鎖口座", "collections.by_account": "tuì {account_handle}", "collections.collection_description": "說明", @@ -392,6 +396,7 @@ "collections.detail.loading": "載入收藏……", "collections.detail.revoke_inclusion": "Kā我suá掉", "collections.detail.sensitive_content": "敏感ê內容", + "collections.detail.sensitive_note": "描述kap口座可能無適合逐ê檢視者。", "collections.detail.share": "分享tsit ê收藏", "collections.detail.you_are_in_this_collection": "Lí已經hőng加kàu tsit ê收藏", "collections.edit_details": "編輯詳細", @@ -422,6 +427,11 @@ "collections.search_accounts_max_reached": "Lí已經加kàu口座數ê盡磅ah。", "collections.sensitive": "敏感ê", "collections.share_short": "分享", + "collections.sort_alphabetical": "照字母排", + "collections.sort_by": "排序方法:", + "collections.sort_date_added": "加添ê日期", + "collections.sort_last_active": "頂kái活動ê時間", + "collections.sort_most_followers": "上tsē跟tuè ê", "collections.suggestions.can_not_add": "Bē當hőng加添", "collections.suggestions.can_not_add_desc": "Tsiah ê口座可能選擇退出探索,或者是in可能佇無支援收藏ê服侍器頂。", "collections.suggestions.must_follow": "Lí著sing跟tuè", @@ -633,6 +643,7 @@ "empty_column.blocks": "Lí iáu無封鎖任何用者。", "empty_column.bookmarked_statuses": "Lí iáu無加添任何冊籤。Nā是lí加添冊籤,伊ē佇tsia顯示。", "empty_column.collections.featured_in": "Lí iáu buē加添kàu任何收藏。", + "empty_column.collections.featured_in_undiscoverable": "若beh予lâng kā lí加入去收藏,lí需要kàu偏愛ê設定 > 隱私kap資訊ê及至佇探索經驗允准推薦", "empty_column.community": "本站時間線是空ê。緊來公開PO文oh!", "empty_column.direct": "Lí iáu無任何ê私人訊息。Nā是lí送á是收著私人訊息,ē佇tsia顯示。.", "empty_column.disabled_feed": "Tsit ê feed已經hōo lí ê服侍器ê管理員停用。", diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index 0c2a59a19c8..e298d758424 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -367,6 +367,8 @@ "collection.share_modal.share_via_system": "Delen met…", "collection.share_modal.title": "Verzameling delen", "collection.share_modal.title_new": "Je nieuwe verzameling delen!", + "collection.share_template_other": "Bekijk deze coole verzameling:", + "collection.share_template_own": "Bekijk mijn nieuwe verzameling:", "collections.account_count": "{count, plural, one {# account} other {# accounts}}", "collections.accounts.empty_description": "Tot {count} accounts toevoegen", "collections.accounts.empty_editor_title": "Er is nog nog niemand in deze verzameling", @@ -582,6 +584,12 @@ "copy_icon_button.copy_this_text": "Link naar klembord kopiëren", "copypaste.copied": "Gekopieerd", "copypaste.copy_to_clipboard": "Naar klembord kopiëren", + "custom_homepage.about": "Over", + "custom_homepage.about_this_server": "Over deze server", + "custom_homepage.administered_by": "Beheerd door", + "custom_homepage.contact": "Contact:", + "custom_homepage.latest_activity": "Meest recente activiteit", + "custom_homepage.these_are_the_latest_posts": "Dit zijn de meest recente 40 berichten van accounts op deze server.", "directory.federated": "Fediverse (wat bekend is)", "directory.local": "Alleen {domain}", "directory.new_arrivals": "Nieuwe accounts", @@ -906,6 +914,7 @@ "navigation_bar.live_feed_local": "Openbare tijdlijn (deze server)", "navigation_bar.live_feed_public": "Openbare tijdlijn (alles)", "navigation_bar.logout": "Uitloggen", + "navigation_bar.main": "Hoofdmenu", "navigation_bar.moderation": "Moderatie", "navigation_bar.more": "Meer", "navigation_bar.mutes": "Genegeerde gebruikers", @@ -1303,6 +1312,7 @@ "tabs_bar.menu": "Menu", "tabs_bar.notifications": "Meldingen", "tabs_bar.publish": "Nieuw bericht", + "tabs_bar.quick_links": "Snelkoppelingen", "tabs_bar.search": "Zoeken", "tag.remove": "Verwijderen", "terms_of_service.effective_as_of": "Van kracht met ingang van {date}", diff --git a/app/javascript/mastodon/locales/pa.json b/app/javascript/mastodon/locales/pa.json index 46cd68748f6..5dcbc67c43b 100644 --- a/app/javascript/mastodon/locales/pa.json +++ b/app/javascript/mastodon/locales/pa.json @@ -56,6 +56,7 @@ "account.follows_you": "ਤੁਹਾਨੂੰ ਫ਼ਾਲੋ ਕਰਦੇ ਹਨ", "account.go_to_profile": "ਪਰੋਫਾਇਲ ਉੱਤੇ ਜਾਓ", "account.hide_reblogs": "{name} ਵਲੋਂ ਬੂਸਟ ਨੂੰ ਲੁਕਾਓ", + "account.join_modal.day": "ਦਿਨ", "account.joined_short": "ਜੁਆਇਨ ਕੀਤਾ", "account.media": "ਮੀਡੀਆ", "account.mention": "@{name} ਦਾ ਜ਼ਿਕਰ", @@ -103,6 +104,13 @@ "account.unmute": "@{name} ਲਈ ਮੌਨ ਹਟਾਓ", "account.unmute_notifications_short": "ਨੋਟਫਿਕੇਸ਼ਨਾਂ ਨੂੰ ਅਣ-ਮੌਨ ਕਰੋ", "account.unmute_short": "ਮੌਨ-ਰਹਿਤ ਕਰੋ", + "account_edit.bio.title": "ਜਾਣਕਾਰੀ", + "account_edit.bio_modal.add_title": "ਜਾਣਕਾਰੀ ਨੂੰ ਜੋੜੋ", + "account_edit.bio_modal.edit_title": "ਜਾਣਕਾਰੀ ਨੂੰ ਸੋਧੋ", + "account_edit.column_button": "ਮੁਕੰਮਲ", + "account_edit.column_title": "ਪਰੋਫਾਈਲ ਨੂੰ ਸੋਧੋ", + "account_edit.field_delete_modal.delete_button": "ਹਟਾਓ", + "account_edit.field_edit_modal.discard_confirm": "ਖਾਰਜ ਕਰੋ", "admin.dashboard.retention.average": "ਔਸਤ", "admin.dashboard.retention.cohort_size": "ਨਵੇਂ ਵਰਤੋਂਕਾਰ", "alert.unexpected.title": "ਓਹੋ!", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index e6e97aea183..778740e2749 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -178,13 +178,13 @@ "account_edit.field_actions.edit": "Editar campo", "account_edit.field_delete_modal.confirm": "Tem certeza que deseja excluir este campo personalizado? Esta ação não pode ser desfeita.", "account_edit.field_delete_modal.delete_button": "Excluir", - "account_edit.field_delete_modal.title": "Remover espaço?", - "account_edit.field_edit_modal.add_title": "Adicionar espaço", + "account_edit.field_delete_modal.title": "Remover campo?", + "account_edit.field_edit_modal.add_title": "Adicionar campo", "account_edit.field_edit_modal.discard_confirm": "Descartar", "account_edit.field_edit_modal.discard_message": "Você possui alterações não salvas. Deseja mesmo descartá-las?", - "account_edit.field_edit_modal.edit_title": "Editar espaço", - "account_edit.field_edit_modal.length_warning": "Limite de caracteres excedido. Usuários móveis talvez não consigam ver seus espaços por inteiro.", - "account_edit.field_edit_modal.link_emoji_warning": "Recomendamos não usar emojis personalizados com URLs. Espaços contendo ambos serão exibidos apenas como um texto invés de um link para evitar confusão.", + "account_edit.field_edit_modal.edit_title": "Editar campo", + "account_edit.field_edit_modal.length_warning": "Limite de caracteres excedido. Usuários móveis talvez não consigam ver seus campos por inteiro.", + "account_edit.field_edit_modal.link_emoji_warning": "Recomendamos não usar emojis personalizados com URLs. Campos contendo ambos serão exibidos apenas como um texto invés de um link para evitar confusão.", "account_edit.field_edit_modal.name_hint": "p. e.x.: “Site pessoal”", "account_edit.field_edit_modal.name_label": "Rótulo", "account_edit.field_edit_modal.url_warning": "Para adicionar links, inclua {protocol} no início.", @@ -323,21 +323,21 @@ "annual_report.summary.new_posts.new_posts": "novas publicações", "annual_report.summary.percentile.text": "Isso lhe coloca no topode usuários de {domain}.", "annual_report.summary.percentile.we_wont_tell_bernie": "Não contaremos ao Bernie.", - "annual_report.summary.share_elsewhere": "Compartilhar em outro lugar", + "annual_report.summary.share_elsewhere": "Compartilhar fora", "annual_report.summary.share_message": "Eu obtive o arquétipo {archetype}!", "annual_report.summary.share_on_mastodon": "Compartilhar no Mastodon", "attachments_list.unprocessed": "(não processado)", "audio.hide": "Ocultar áudio", - "block_modal.no_collections": "Nenhum de vocês pode adicionar um ao outro a coleções. Vocês serão automaticamente removidos um da coleção do outro, se for o caso.", - "block_modal.remote_users_caveat": "Pediremos ao servidor {domain} que respeite sua decisão. No entanto, a conformidade não é garantida, já que alguns servidores podem lidar com bloqueios de maneira diferente. As publicações abertas ainda podem estar visíveis para usuários não logados.", + "block_modal.no_collections": "Nenhum dos dois podem se adicionar a uma coleção. Você será automaticamente removido da coleção do outro, se possível.", + "block_modal.remote_users_caveat": "Pediremos ao servidor {domain} para respeitar sua decisão. Porém, não é garantido, já que os servidores podem lidar com bloqueios de formas diferentes. Publicações ainda poderão ser visíveis para usuários não registrados.", "block_modal.show_less": "Mostrar menos", "block_modal.show_more": "Mostrar mais", - "block_modal.they_cant_mention": "Vocês não podem mencionar, seguir ou citar um ao outro.", - "block_modal.they_cant_see_posts": "Vocês não podem ver o conteúdo um do outro.", + "block_modal.they_cant_mention": "Você não poderá mencionar, seguir ou citar esta pessoa.", + "block_modal.they_cant_see_posts": "Vocês não poderão ver o conteúdo um do outro.", "block_modal.they_will_know": "Poderá ver que você bloqueou.", "block_modal.title": "Bloquear usuário?", - "block_modal.you_wont_see_mentions": "Você não verá publicações de outros que mencionem essa conta.", - "boost_modal.combo": "Pressione {combo} para pular isto na próxima vez", + "block_modal.you_wont_see_mentions": "Você não verá publicações de usuários que mencionarem esta pessoa.", + "boost_modal.combo": "Pressione {combo} para pular da próxima vez", "boost_modal.reblog": "Impulsionar a publicação?", "boost_modal.undo_reblog": "Retirar o impulso da publicação?", "bundle_column_error.copy_stacktrace": "Copiar relatório do erro", @@ -367,6 +367,8 @@ "collection.share_modal.share_via_system": "Enviar para…", "collection.share_modal.title": "Compartilhar coleção", "collection.share_modal.title_new": "Compartilhe sua nova coleção!", + "collection.share_template_other": "Confira esta coleção incrível:", + "collection.share_template_own": "Confira minha nova coleção:", "collections.account_count": "{count, plural, one {# conta} other {# conta}}", "collections.accounts.empty_description": "Adicione até {count} contas", "collections.accounts.empty_editor_title": "Ainda não há ninguém nesta coleção", @@ -380,11 +382,11 @@ "collections.collection_name": "Nome", "collections.collection_topic": "Tópico", "collections.confirm_account_removal": "Tem certeza que deseja remover esta conta da sua coleção?", - "collections.content_warning": "Aviso de conteúdo", + "collections.content_warning": "Alerta de conteúdo", "collections.continue": "Continuar", "collections.copy_link": "Copiar link", "collections.copy_link_confirmation": "Link de coleção copiado", - "collections.create.accounts_title": "Quen você vai apresentar nesta coleção?", + "collections.create.accounts_title": "Quem você adicionará a esta coleção?", "collections.create.basic_details_title": "Detalhes básicos", "collections.create.steps": "Passo {step}/{total}", "collections.create_collection": "Criar coleção", @@ -406,23 +408,23 @@ "collections.list.collections_with_count": "{count, plural, one {# Coleção} other {# Coleções}}", "collections.list.created_by_author": "Criado por {name}", "collections.list.created_by_you": "Criadas por você", - "collections.list.featuring_you": "Apresentado por ti", + "collections.list.featuring_you": "Com você presente", "collections.manage_accounts": "Gerenciar contas", "collections.mark_as_sensitive": "Marcar como sensível", - "collections.mark_as_sensitive_hint": "Oculta a descrição e as contas da coleção por trás de um aviso de conteúdo. O nome da coleção ainda será visível.", - "collections.maximum_collection_count_description": "Seu servidor permite a criação de, no máximo, {count} coleções.", + "collections.mark_as_sensitive_hint": "Oculta a descrição e contas da coleção atrás de um alerta de conteúdo. O nome da coleção ainda será visível.", + "collections.maximum_collection_count_description": "Seu servidor permite criar até {count} coleções.", "collections.maximum_collection_count_reached": "Você criou a quantidade máxima de coleções", "collections.name_length_hint": "limite de 40 caracteres", "collections.new_collection": "Nova coleção", - "collections.pending_accounts.message": "Contas podem aparecer como pendentes quando estamos aguardando uma resposta do usuário ou de seu servidor. Apenas você pode ver contas pendentes.", + "collections.pending_accounts.message": "Contas talvez apareçam pendentes se estivermos aguardando a resposta do usuário ou do servidor. Só você pode ver contas pendentes.", "collections.pending_accounts.title": "Por que estou vendo contas pendentes?", "collections.remove_account": "Remover", - "collections.report_collection": "Denunciar esta coleção", - "collections.revoke_collection_inclusion": "Remover-me desta coleção", + "collections.report_collection": "Denunciar coleção", + "collections.revoke_collection_inclusion": "Me remover desta coleção", "collections.revoke_inclusion.confirmation": "Você foi removido de \"{collection}\"", - "collections.revoke_inclusion.error": "Houve um erro, por favor tente novamente mais tarde.", - "collections.search_accounts_label": "Pesquisar por uma conta para adicionar", - "collections.search_accounts_max_reached": "Você acrescentou o número máximo de contas", + "collections.revoke_inclusion.error": "Ocorreu um erro, tente novamente mais tarde.", + "collections.search_accounts_label": "Buscar uma conta para adicionar", + "collections.search_accounts_max_reached": "Você adicionou o número máximo de contas", "collections.sensitive": "Sensível", "collections.share_short": "Compartilhar", "collections.sort_alphabetical": "Alfabética", @@ -430,20 +432,20 @@ "collections.sort_date_added": "Data adicionada", "collections.sort_last_active": "Última atividade", "collections.sort_most_followers": "Mais seguidores", - "collections.suggestions.can_not_add": "Não pôde ser adicionado", - "collections.suggestions.can_not_add_desc": "Estas contas podem ter optado para não serem exibidas na página de descobrir, ou podem estar em um servidor que não suporta coleções.", + "collections.suggestions.can_not_add": "Não pode ser adicionado", + "collections.suggestions.can_not_add_desc": "Estas contas talvez não permitem aparecer na página Descobrir ou talvez estejam em um servidor que não suporte coleções.", "collections.suggestions.must_follow": "Você deve seguir primeiro", - "collections.suggestions.must_follow_desc": "Essas contas revisam todas as solicitações de seguir. Seguidores podem os adicionar às coleções.", - "collections.topic_hint": "Adicione uma hashtag que ajude os outros a entender o tópico principal desta coleção.", - "collections.topic_special_chars_hint": "Caracteres especiais serão removidos ao salvar", - "collections.unlisted_collections_description": "Estes não aparecem em seu perfil aos outros. Qualquer um com um link pode os descobrir.", + "collections.suggestions.must_follow_desc": "Estas contas revisam as solicitações de seguidores. Seguidores podem adicioná-los às coleções.", + "collections.topic_hint": "Adicione uma hashtag que ajude a todos compreenderem o tópico da coleção.", + "collections.topic_special_chars_hint": "Caracteres especiais não serão incluídos ao salvar", + "collections.unlisted_collections_description": "Estes não aparecem em seu perfil para todos. Qualquer um com link pode descobri-los.", "collections.unlisted_collections_with_count": "Coleções não listadas ({count})", "collections.view_collection": "Ver coleção", "collections.visibility_public": "Público", - "collections.visibility_public_hint": "Localizável em resultados de buscas e outras áreas onde recomendações aparecem.", + "collections.visibility_public_hint": "Descobrível em resultados de busca e qualquer outra área de recomendações.", "collections.visibility_title": "Visibilidade", "collections.visibility_unlisted": "Não listado", - "collections.visibility_unlisted_hint": "Visível para qualquer um com um link. Oculto nos resultados de busca e recomendações.", + "collections.visibility_unlisted_hint": "Visível apenas com um link. Oculto de resultados de buscas e recomendações.", "column.about": "Sobre", "column.blocks": "Usuários bloqueados", "column.bookmarks": "Salvos", @@ -455,7 +457,7 @@ "column.edit_list": "Editar lista", "column.favourites": "Favoritos", "column.firehose": "Feeds ao vivo", - "column.firehose_local": "Feed ao vivo deste servidor", + "column.firehose_local": "Feed ao vivo do servidor", "column.firehose_singular": "Feed ao vivo", "column.follow_requests": "Seguidores pendentes", "column.home": "Página inicial", @@ -550,7 +552,7 @@ "confirmations.private_quote_notify.title": "Compartilhar com seguidores e usuários mencionados?", "confirmations.quiet_post_quote_info.dismiss": "Não me lembrar novamente", "confirmations.quiet_post_quote_info.got_it": "Entendi", - "confirmations.quiet_post_quote_info.message": "Ao citar uma publicação pública silenciosa, sua postagem será oculta das linhas de tempo em tendência.", + "confirmations.quiet_post_quote_info.message": "Ao citar uma publicação silenciosa, sua publicação será oculta das timelines em alta.", "confirmations.quiet_post_quote_info.title": "Citando publicações públicas silenciosas", "confirmations.redraft.confirm": "Excluir e rascunhar", "confirmations.redraft.message": "Você tem certeza de que quer apagar esta publicação e rascunhá-la? Favoritos e impulsos serão perdidos, e respostas à publicação original ficarão órfãs.", @@ -582,6 +584,12 @@ "copy_icon_button.copy_this_text": "Copiar link para área de transferência", "copypaste.copied": "Copiado", "copypaste.copy_to_clipboard": "Copiar para a área de transferência", + "custom_homepage.about": "Sobre", + "custom_homepage.about_this_server": "Sobre este servidor", + "custom_homepage.administered_by": "Administrado por", + "custom_homepage.contact": "Contato:", + "custom_homepage.latest_activity": "Última atividade", + "custom_homepage.these_are_the_latest_posts": "Estas são as últimas 40 publicações das contas neste servidor.", "directory.federated": "Do fediverso conhecido", "directory.local": "Somente de {domain}", "directory.new_arrivals": "Acabaram de chegar", @@ -595,7 +603,7 @@ "domain_block_modal.block_account_instead": "Bloquear @{name} em vez disso", "domain_block_modal.they_can_interact_with_old_posts": "Pessoas deste servidor podem interagir com suas publicações antigas.", "domain_block_modal.they_cant_follow": "Ninguém deste servidor pode lhe seguir.", - "domain_block_modal.they_wont_know": "O/A usuário/a não saberá que foi bloqueado/a.", + "domain_block_modal.they_wont_know": "O usuário não saberá que foi bloqueado.", "domain_block_modal.title": "Bloquear domínio?", "domain_block_modal.you_will_lose_num_followers": "Você perderá {followersCount, plural, one {{followersCountDisplay} seguidor} other {{followersCountDisplay} seguidores}} e {followingCount, plural, one {{followingCountDisplay} pessoa que você segue} other {{followingCountDisplay} pessoas que você segue}}.", "domain_block_modal.you_will_lose_relationships": "Você irá perder todos os seguidores e pessoas que você segue neste servidor.", @@ -605,9 +613,9 @@ "email_subscriptions.form.action": "Inscrever-se", "email_subscriptions.form.bottom": "Receba publicações em sua caixa de entrada sem criar uma conta do Mastodon. Desinscreva-se a qualquer momento. Para mais informações, consulte a Política de Privacidade.", "email_subscriptions.form.title": "Inscrever-se para atualizações por email de {name}", - "email_subscriptions.submitted.lead": "Verifique sua caixa de entrada para finalizar sua inscrição para receber atualizações por email.", + "email_subscriptions.submitted.lead": "Verifique a caixa de entrada por algum e-mail para encerrar inscrição de atualizações por e-mail.", "email_subscriptions.submitted.title": "Mais um passo", - "email_subscriptions.validation.email.blocked": "Provedor de email bloqueado", + "email_subscriptions.validation.email.blocked": "Fornecedor de e-mail bloqueado", "email_subscriptions.validation.email.invalid": "Endereço de email inválido", "embed.instructions": "Incorpore esta publicação no seu site ao copiar o código abaixo.", "embed.preview": "Aqui está como vai ficar:", @@ -626,24 +634,24 @@ "emoji_button.search_results": "Resultado da pesquisa", "emoji_button.symbols": "Símbolos", "emoji_button.travel": "Viagem e Lugares", - "empty_column.account_featured.other": "{acct} ainda não colocou nada em destaque.", + "empty_column.account_featured.other": "{acct} não destacou nada ainda.", "empty_column.account_featured_self.no_collections_button": "Criar uma coleção", - "empty_column.account_featured_self.no_collections_hide_tab": "Ocultar esta aba em vez disso", - "empty_column.account_featured_self.pre_collections": "Acompanhe este espaço para Coleções", - "empty_column.account_featured_self.pre_collections_desc": "Coleções (chegando no Mastodon 4.6) permitem que você crie sua própria lista curada de contas para recomendar aos outros.", - "empty_column.account_featured_self.showcase_accounts": "Exibir suas contas favoritas", - "empty_column.account_featured_self.showcase_accounts_desc": "Coleções são listas curadas de contas que ajudam os outros a descobrir mais do Fediverso.", - "empty_column.account_featured_unknown.other": "Esta conta ainda não pôs nada em destaque.", - "empty_column.account_hides_collections": "A pessoa optou por não disponibilizar esta informação", + "empty_column.account_featured_self.no_collections_hide_tab": "Ao invés, ocultar esta aba", + "empty_column.account_featured_self.pre_collections": "Fique ligado às Coleções", + "empty_column.account_featured_self.pre_collections_desc": "Coleções (em breve no Mastodon 4.6) permite que você crie listas curadas de contas de recomendação para os outros.", + "empty_column.account_featured_self.showcase_accounts": "Exibir contas favoritas", + "empty_column.account_featured_self.showcase_accounts_desc": "Coleções são listas curadas de contas para ajudar todos a descobrir mais do Fediverso.", + "empty_column.account_featured_unknown.other": "Esta conta não destacou nada ainda.", + "empty_column.account_hides_collections": "O usuário decidiu não tornar esta informação disponível", "empty_column.account_suspended": "Conta suspensa", "empty_column.account_timeline": "Nada aqui.", "empty_column.account_unavailable": "Perfil indisponível", "empty_column.blocks": "Nada aqui.", "empty_column.bookmarked_statuses": "Nada aqui. Quando você salvar uma publicação, ela aparecerá aqui.", - "empty_column.collections.featured_in": "Você ainda não foi adicionado a nenhuma coleção.", + "empty_column.collections.featured_in": "Você ainda não foi adicionado a uma coleção.", "empty_column.collections.featured_in_undiscoverable": "Para as pessoas adicionarem você às coleções, você precisa permitir destaque de experiências de descoberta através de Preferências > Privacidade e alcance", "empty_column.community": "A linha local está vazia. Publique algo para começar!", - "empty_column.direct": "Você ainda não tem mensagens privadas. Quando você enviar ou receber uma, será exibida aqui.", + "empty_column.direct": "Você ainda não possui menções privadas. Caso você enviar ou receber uma, ela aparecerá aqui.", "empty_column.disabled_feed": "Este feed foi desativado pelos administradores de seu servidor.", "empty_column.domain_blocks": "Nada aqui.", "empty_column.explore_statuses": "Nada está em alta no momento. Volte mais tarde!", @@ -652,7 +660,7 @@ "empty_column.follow_requests": "Nada aqui. Quando você tiver seguidores pendentes, eles aparecerão aqui.", "empty_column.followed_tags": "Você ainda não seguiu nenhuma hashtag. Quando seguir, elas serão exibidas aqui.", "empty_column.hashtag": "Nada aqui.", - "empty_column.home": "Sua página inicial está vazia! Siga mais pessoas para preenchê-la.", + "empty_column.home": "Sua timeline inicial está vazia! Siga mais pessoas para preenchê-la.", "empty_column.list": "Nada aqui. Quando membros da lista publicarem, elas aparecerão aqui.", "empty_column.mutes": "Nada aqui.", "empty_column.notification_requests": "Tudo limpo! Não há nada aqui. Quando você receber novas notificações, elas aparecerão aqui de acordo com suas configurações.", @@ -675,16 +683,16 @@ "featured_carousel.header": "{count, plural, one {Publicação fixada} other {Publicações fixadas}}", "featured_carousel.slide": "Publicação {current, number} de {max, number}", "featured_tags.more_items": "+{count}", - "featured_tags.suggestions": "Anteriormente você postou sobre {items}. Adicionar estas como hashtags em destaque?", + "featured_tags.suggestions": "Recentemente, você publicou sobre {items}. Adicioná-los como hashtags destacadas?", "featured_tags.suggestions.add": "Adicionar", - "featured_tags.suggestions.added": "Gerencie suas hashtags a qualquer momento sob Editar Perfil > Hashtags em destaque.", + "featured_tags.suggestions.added": "Gerencie as hashtags destacadas em Editar perfil > Hashtags destacadas.", "featured_tags.suggestions.dismiss": "Não, obrigado", "filter_modal.added.context_mismatch_explanation": "Esta categoria de filtro não se aplica ao contexto no qual você acessou esta publicação. Se quiser que a publicação seja filtrada nesse contexto também, você terá que editar o filtro.", "filter_modal.added.context_mismatch_title": "Incompatibilidade de contexto!", "filter_modal.added.expired_explanation": "Esta categoria de filtro expirou, você precisará alterar a data de expiração para aplicar.", "filter_modal.added.expired_title": "Filtro expirado!", "filter_modal.added.review_and_configure": "Para revisar e configurar ainda mais esta categoria de filtro, vá para {settings_link}.", - "filter_modal.added.review_and_configure_title": "Configurações de filtro", + "filter_modal.added.review_and_configure_title": "Opções de filtro", "filter_modal.added.settings_link": "página de configurações", "filter_modal.added.short_explanation": "Esta publicação foi adicionada à seguinte categoria de filtro: {title}.", "filter_modal.added.title": "Filtro adicionado!", @@ -692,11 +700,11 @@ "filter_modal.select_filter.expired": "expirado", "filter_modal.select_filter.prompt_new": "Nova categoria: {name}", "filter_modal.select_filter.search": "Buscar ou criar", - "filter_modal.select_filter.subtitle": "Use uma categoria existente ou crie uma nova", + "filter_modal.select_filter.subtitle": "Use uma categoria existente ou crie uma", "filter_modal.select_filter.title": "Filtrar esta publicação", "filter_modal.title.status": "Filtrar uma publicação", - "filter_warning.matches_filter": "Corresponder filtro “{title}”", - "filtered_notifications_banner.pending_requests": "Por {count, plural, =0 {no one} one {one person} other {# people}} que você talvez conheça", + "filter_warning.matches_filter": "Corresponde ao filtro “{title}”", + "filtered_notifications_banner.pending_requests": "De {count, plural, =0 {ninguém} one {uma pessoa} other {# pessoas}} que você talvez conheça", "filtered_notifications_banner.title": "Notificações filtradas", "firehose.all": "Tudo", "firehose.local": "Este servidor", @@ -906,6 +914,7 @@ "navigation_bar.live_feed_local": "Feed ao vivo (local)", "navigation_bar.live_feed_public": "Feed ao vivo (público)", "navigation_bar.logout": "Sair", + "navigation_bar.main": "Principal", "navigation_bar.moderation": "Moderação", "navigation_bar.more": "Mais", "navigation_bar.mutes": "Usuários silenciados", @@ -1303,6 +1312,7 @@ "tabs_bar.menu": "Menu", "tabs_bar.notifications": "Notificações", "tabs_bar.publish": "Nova publicação", + "tabs_bar.quick_links": "Links rápidos", "tabs_bar.search": "Buscar", "tag.remove": "Remover", "terms_of_service.effective_as_of": "Em vigor a partir de {date}", diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json index 6e11e0e94ec..4c4427083e8 100644 --- a/app/javascript/mastodon/locales/sq.json +++ b/app/javascript/mastodon/locales/sq.json @@ -579,6 +579,12 @@ "copy_icon_button.copy_this_text": "Kopjoje lidhjen në të papastër", "copypaste.copied": "U kopjua", "copypaste.copy_to_clipboard": "Kopjoje në të papastër", + "custom_homepage.about": "Mbi", + "custom_homepage.about_this_server": "Rreth këtij shërbyesi", + "custom_homepage.administered_by": "Administruar nga", + "custom_homepage.contact": "Kontakt:", + "custom_homepage.latest_activity": "Veprimtaria e fundit", + "custom_homepage.these_are_the_latest_posts": "Këto janë 40 postimet më të reja nga llogari në këtë shërbyes.", "directory.federated": "Nga fedivers i njohur", "directory.local": "Vetëm nga {domain}", "directory.new_arrivals": "Të ardhur rishtas", @@ -903,6 +909,7 @@ "navigation_bar.live_feed_local": "Pryrje e atypëratyshme (vendore)", "navigation_bar.live_feed_public": "Prurje e atypëratyshme (publike)", "navigation_bar.logout": "Dalje", + "navigation_bar.main": "Kryesorja", "navigation_bar.moderation": "Moderim", "navigation_bar.more": "Më tepër", "navigation_bar.mutes": "Përdorues të heshtuar", @@ -1299,6 +1306,7 @@ "tabs_bar.menu": "Menu", "tabs_bar.notifications": "Njoftime", "tabs_bar.publish": "Postimi i Ri", + "tabs_bar.quick_links": "Lidhje të shpejta", "tabs_bar.search": "Kërkim", "tag.remove": "Hiqe", "terms_of_service.effective_as_of": "Hyn në fuqi që prej {date}", diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json index 10a037a9c68..e310aca816a 100644 --- a/app/javascript/mastodon/locales/sv.json +++ b/app/javascript/mastodon/locales/sv.json @@ -86,6 +86,7 @@ "account.locked_info": "Detta konto har låst integritetsstatus. Ägaren väljer manuellt vem som kan följa det.", "account.media": "Media", "account.mention": "Nämn @{name}", + "account.menu.add_to_collection": "Lägg till i samling…", "account.menu.add_to_list": "Lägg till i lista…", "account.menu.block": "Blockera konto", "account.menu.block_domain": "Blockera {domain}", @@ -366,10 +367,13 @@ "collection.share_modal.share_via_system": "Dela med…", "collection.share_modal.title": "Dela samling", "collection.share_modal.title_new": "Dela din nya samling!", + "collection.share_template_other": "Kolla in denna coola samling:", + "collection.share_template_own": "Kolla in min nya samling:", "collections.account_count": "{count, plural, one {# konto} other {# konton}}", "collections.accounts.empty_description": "Lägg till upp till {count} konton", "collections.accounts.empty_editor_title": "Ingen finns i denna samling ännu", "collections.accounts.empty_title": "Denna samling är tom", + "collections.add_to_collection": "Lägg till {name} i samlingar", "collections.block_collection_owner": "Blockera konto", "collections.by_account": "av {account_handle}", "collections.collection_description": "Beskrivning", @@ -392,6 +396,7 @@ "collections.detail.loading": "Laddar samling…", "collections.detail.revoke_inclusion": "Ta bort mig", "collections.detail.sensitive_content": "Känsligt innehåll", + "collections.detail.sensitive_note": "Beskrivningen och dessa konton är kanske inte lämpliga för alla tittare.", "collections.detail.share": "Dela denna samling", "collections.detail.you_are_in_this_collection": "Du är med i denna samling", "collections.edit_details": "Redigera detaljer", @@ -424,6 +429,7 @@ "collections.share_short": "Dela", "collections.sort_alphabetical": "Alfabetiskt", "collections.sort_by": "Sortera efter:", + "collections.sort_date_added": "Datum tillagd", "collections.sort_last_active": "Senast aktiv", "collections.sort_most_followers": "Flest följare", "collections.suggestions.can_not_add": "Kan inte läggas till", @@ -637,6 +643,7 @@ "empty_column.blocks": "Du har ännu ej blockerat några användare.", "empty_column.bookmarked_statuses": "Du har inte bokmärkt några inlägg än. När du bokmärker ett inlägg kommer det synas här.", "empty_column.collections.featured_in": "Du har inte lagts till i några samlingar än.", + "empty_column.collections.featured_in_undiscoverable": "För att personer ska kunna lägga till dig i samlingar, måste du tillåta att inkluderas i upptäcktsupplevelser från Inställningar> Sekretess och räckvidd", "empty_column.community": "Den lokala tidslinjen är tom. Skriv något offentligt för att sätta bollen i rullning!", "empty_column.direct": "Du har inga privata omnämnanden. När du skickar eller tar emot ett direktmeddelande kommer det att visas här.", "empty_column.disabled_feed": "Detta flöde har inaktiverats av dina serveradministratörer.", @@ -1000,8 +1007,8 @@ "notifications.column_settings.show": "Visa i kolumnen", "notifications.column_settings.sound": "Spela upp ljud", "notifications.column_settings.status": "Nya inlägg:", - "notifications.column_settings.unread_notifications.category": "O-lästa aviseringar", - "notifications.column_settings.unread_notifications.highlight": "Markera o-lästa aviseringar", + "notifications.column_settings.unread_notifications.category": "Olästa aviseringar", + "notifications.column_settings.unread_notifications.highlight": "Markera olästa aviseringar", "notifications.column_settings.update": "Redigeringar:", "notifications.filter.all": "Alla", "notifications.filter.boosts": "Boostar", @@ -1298,6 +1305,7 @@ "tabs_bar.menu": "Meny", "tabs_bar.notifications": "Aviseringar", "tabs_bar.publish": "Nytt inlägg", + "tabs_bar.quick_links": "Snabblänkar", "tabs_bar.search": "Sök", "tag.remove": "Ta bort", "terms_of_service.effective_as_of": "Gäller från och med {date}", diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json index e7930a84f97..2280b14b71d 100644 --- a/app/javascript/mastodon/locales/tr.json +++ b/app/javascript/mastodon/locales/tr.json @@ -367,6 +367,8 @@ "collection.share_modal.share_via_system": "Paylaş…", "collection.share_modal.title": "Koleksiyonu paylaş", "collection.share_modal.title_new": "Yeni koleksiyonunuzu paylaşın!", + "collection.share_template_other": "Bu harika koleksiyona göz atın:", + "collection.share_template_own": "Yeni koleksiyonuma göz atın:", "collections.account_count": "{count, plural, one {# hesap} other {# hesap}}", "collections.accounts.empty_description": "{count} hesap ekleyebilirsiniz", "collections.accounts.empty_editor_title": "Koleksiyonda henüz kimse yok", @@ -582,6 +584,12 @@ "copy_icon_button.copy_this_text": "Bağlantıyı panoya kopyala", "copypaste.copied": "Kopyalandı", "copypaste.copy_to_clipboard": "Panoya kopyala", + "custom_homepage.about": "Hakkında", + "custom_homepage.about_this_server": "Bu sunucu hakkında", + "custom_homepage.administered_by": "Yönetici:", + "custom_homepage.contact": "İletişim:", + "custom_homepage.latest_activity": "En son etkinlik", + "custom_homepage.these_are_the_latest_posts": "Bu sunucudaki hesaplardan yapılan son 40 gönderi.", "directory.federated": "Bilinen fediverse'lerden", "directory.local": "Yalnızca {domain} adresinden", "directory.new_arrivals": "Yeni gelenler", @@ -906,6 +914,7 @@ "navigation_bar.live_feed_local": "Canlı akış (yerel)", "navigation_bar.live_feed_public": "Canlı akış (herkese açık)", "navigation_bar.logout": "Oturumu kapat", + "navigation_bar.main": "Ana", "navigation_bar.moderation": "Moderasyon", "navigation_bar.more": "Daha fazla", "navigation_bar.mutes": "Sessize alınmış kullanıcılar", @@ -1303,6 +1312,7 @@ "tabs_bar.menu": "Menü", "tabs_bar.notifications": "Bildirimler", "tabs_bar.publish": "Yeni Gönderi", + "tabs_bar.quick_links": "Hızlı erişim", "tabs_bar.search": "Arama", "tag.remove": "Kaldır", "terms_of_service.effective_as_of": "{date} itibariyle yürürlükte", diff --git a/app/javascript/mastodon/locales/vi.json b/app/javascript/mastodon/locales/vi.json index 5dccafb2af9..547ebd7a5f3 100644 --- a/app/javascript/mastodon/locales/vi.json +++ b/app/javascript/mastodon/locales/vi.json @@ -584,6 +584,12 @@ "copy_icon_button.copy_this_text": "Sao chép liên kết vào clipboard", "copypaste.copied": "Đã sao chép", "copypaste.copy_to_clipboard": "Sao chép vào bộ nhớ tạm", + "custom_homepage.about": "Giới thiệu", + "custom_homepage.about_this_server": "Về máy chủ này", + "custom_homepage.administered_by": "Quản trị bởi", + "custom_homepage.contact": "Liên hệ:", + "custom_homepage.latest_activity": "Hoạt động gần nhất", + "custom_homepage.these_are_the_latest_posts": "Đây là 40 tút mới nhất từ ​​các tài khoản trên máy chủ này.", "directory.federated": "Ở mạng liên hợp", "directory.local": "Ở {domain}", "directory.new_arrivals": "Mới tham gia", @@ -907,6 +913,7 @@ "navigation_bar.live_feed_local": "Bảng tin (máy chủ)", "navigation_bar.live_feed_public": "Bảng tin (công khai)", "navigation_bar.logout": "Đăng xuất", + "navigation_bar.main": "Chính", "navigation_bar.moderation": "Kiểm duyệt", "navigation_bar.more": "Khác", "navigation_bar.mutes": "Tài khoản đã phớt lờ", @@ -1304,6 +1311,7 @@ "tabs_bar.menu": "Menu", "tabs_bar.notifications": "Thông báo", "tabs_bar.publish": "Soạn tút", + "tabs_bar.quick_links": "Lối tắt", "tabs_bar.search": "Tìm kiếm", "tag.remove": "Gỡ bỏ", "terms_of_service.effective_as_of": "Có hiệu lực vào {date}", diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json index 03237b2cbe1..96f8ffbe95d 100644 --- a/app/javascript/mastodon/locales/zh-CN.json +++ b/app/javascript/mastodon/locales/zh-CN.json @@ -908,6 +908,7 @@ "navigation_bar.live_feed_local": "实时动态(本站)", "navigation_bar.live_feed_public": "实时动态(公开)", "navigation_bar.logout": "退出登录", + "navigation_bar.main": "首页", "navigation_bar.moderation": "审核", "navigation_bar.more": "更多", "navigation_bar.mutes": "已隐藏的用户", @@ -1305,6 +1306,7 @@ "tabs_bar.menu": "菜单", "tabs_bar.notifications": "通知", "tabs_bar.publish": "新嘟文", + "tabs_bar.quick_links": "快捷链接", "tabs_bar.search": "搜索", "tag.remove": "移除", "terms_of_service.effective_as_of": "自 {date} 起生效", diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index 8295c699917..0793407f650 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -584,6 +584,12 @@ "copy_icon_button.copy_this_text": "複製連結至剪貼簿", "copypaste.copied": "已複製", "copypaste.copy_to_clipboard": "複製到剪貼簿", + "custom_homepage.about": "關於", + "custom_homepage.about_this_server": "關於此伺服器", + "custom_homepage.administered_by": "管理者為", + "custom_homepage.contact": "聯絡我們:", + "custom_homepage.latest_activity": "最新動態", + "custom_homepage.these_are_the_latest_posts": "這些為此伺服器上帳號的最新 40 篇嘟文。", "directory.federated": "來自已知聯邦宇宙", "directory.local": "僅來自 {domain}", "directory.new_arrivals": "新人", @@ -908,6 +914,7 @@ "navigation_bar.live_feed_local": "即時內容(本站)", "navigation_bar.live_feed_public": "即時內容(公開)", "navigation_bar.logout": "登出", + "navigation_bar.main": "主要", "navigation_bar.moderation": "站務", "navigation_bar.more": "更多", "navigation_bar.mutes": "已靜音的使用者", @@ -1305,6 +1312,7 @@ "tabs_bar.menu": "選單", "tabs_bar.notifications": "通知", "tabs_bar.publish": "新增嘟文", + "tabs_bar.quick_links": "快速連結", "tabs_bar.search": "搜尋", "tag.remove": "移除", "terms_of_service.effective_as_of": "{date} 起生效", diff --git a/config/locales/ar.yml b/config/locales/ar.yml index 70aabf1d5b6..3cf3650280b 100644 --- a/config/locales/ar.yml +++ b/config/locales/ar.yml @@ -908,11 +908,6 @@ ar: feed_access: modes: public: الجميع - landing_page: - values: - about: عن - local_feed: الخيط المحلي - trends: المتداوَلة registrations: moderation_recommandation: الرجاء التأكد من أن لديك فريق إشراف كافي وفعال قبل فتح التسجيلات للجميع! preamble: تحكّم في مَن الذي يمكنه إنشاء حساب على خادمك الخاص. diff --git a/config/locales/be.yml b/config/locales/be.yml index 244857c6dd5..c12ac65d745 100644 --- a/config/locales/be.yml +++ b/config/locales/be.yml @@ -988,10 +988,16 @@ be: disabled: Запатрабаваць адмысловую ролю карыстальніка public: Усе landing_page: + hints: + about_html: Старонка з апісаннем, правіламі, кантактнай і іншай інфармацыяй адносна сервера. + local_feed_html: Жывая стужка, у якой прадстаўленыя самыя свежыя допісы карыстальнікаў гэтага сервера. + overview_html: Старонка, якая паказвае апісанне Вашага сервера разам з самымі свежымі лакальнымі допісамі карыстальнікаў гэтага сервера. + trends_html: Старонка, якая паказвае, што зараз папулярна на серверы. values: - about: Падрабязна - local_feed: Тутэйшая стужка - trends: Трэнды + about: Аб старонцы + local_feed: Лакальная жывая стужка + overview: Змест + trends: Трэндавае registrations: moderation_recommandation: Пераканайцеся, што ў вас ёсць адэкватная і аператыўная каманда мадэратараў, перш чым адчыняць рэгістрацыю для ўсіх жадаючых! preamble: Кантралюйце, хто можа ствараць уліковы запіс на вашым серверы. diff --git a/config/locales/bg.yml b/config/locales/bg.yml index 67c7d6944ac..08a744f62b1 100644 --- a/config/locales/bg.yml +++ b/config/locales/bg.yml @@ -838,9 +838,6 @@ bg: authenticated: Само удостоверени потребители disabled: Изисква особена потребителска роля public: Всеки - landing_page: - values: - trends: Пламенности registrations: moderation_recommandation: Уверете се, че имате адекватен и реактивен модераторски екип преди да отворите регистриранията за всеки! preamble: Управлява кой може да създава акаунт на сървъра ви. diff --git a/config/locales/br.yml b/config/locales/br.yml index 75cdbae8ba0..9cc3ee0fb4d 100644 --- a/config/locales/br.yml +++ b/config/locales/br.yml @@ -389,9 +389,6 @@ br: all: D'an holl dud disabled: Da zen ebet users: D'an implijerien·ezed lec'hel kevreet - landing_page: - values: - about: Diwar-benn title: Arventennoù ar servijer site_uploads: delete: Dilemel ar restr pellgaset diff --git a/config/locales/cs.yml b/config/locales/cs.yml index 94f5babb094..4a02903cbe3 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -921,11 +921,6 @@ cs: authenticated: Pouze autentifikovaní uživatelé disabled: Vyžadovat specifickou uživatelskou roli public: Všichni - landing_page: - values: - about: O službě - local_feed: Místní kanál - trends: Trendy registrations: moderation_recommandation: Před otevřením registrací všem se ujistěte, že máte vhodný a reaktivní moderační tým! preamble: Mějte pod kontrolou, kdo může vytvořit účet na vašem serveru. diff --git a/config/locales/cy.yml b/config/locales/cy.yml index caf98e6cbd9..95c91dda394 100644 --- a/config/locales/cy.yml +++ b/config/locales/cy.yml @@ -1019,11 +1019,6 @@ cy: authenticated: Defnyddwyr dilys yn unig disabled: Gofyn am rôl defnyddiwr penodol public: Pawb - landing_page: - values: - about: Ynghylch - local_feed: Ffrwd leol - trends: Trendiau registrations: moderation_recommandation: Gwnewch yn siŵr bod gennych chi dîm cymedroli digonol ac adweithiol cyn i chi agor cofrestriadau i bawb! preamble: Rheoli pwy all greu cyfrif ar eich gweinydd. diff --git a/config/locales/da.yml b/config/locales/da.yml index 8bbc546ad6d..f1fdb1c1a27 100644 --- a/config/locales/da.yml +++ b/config/locales/da.yml @@ -956,10 +956,16 @@ da: disabled: Kræv specifik brugerrolle public: Alle landing_page: + hints: + about_html: En side med beskrivelsen, kontaktoplysninger, regler og andre oplysninger vedrørende denne server. + local_feed_html: Et live feed med de seneste indlæg fra brugere på denne server. + overview_html: En side, der viser beskrivelsen af din server sammen med de seneste lokale indlæg af brugere på denne server. + trends_html: En side, der viser, hvad der er populært på denne server lige nu. values: - about: Om - local_feed: Lokalt feed - trends: Trends + about: Om-side + local_feed: Lokalt live-feed + overview: Oversigt + trends: Trender registrations: moderation_recommandation: Sørg for, at der er et tilstrækkeligt og reaktivt moderationsteam, før registrering åbnes for alle! preamble: Styr, hvem der kan oprette en konto på din server. diff --git a/config/locales/de.yml b/config/locales/de.yml index 4d20c155286..129a42708ec 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -957,9 +957,8 @@ de: public: Alle landing_page: values: - about: Über - local_feed: Lokaler Feed - trends: Trends + overview: Übersicht + trends: Trendet registrations: moderation_recommandation: Bitte vergewissere dich, dass du ein geeignetes und reaktionsschnelles Moderationsteam hast, bevor du die Registrierungen uneingeschränkt zulässt! preamble: Lege fest, wer auf deinem Server ein Konto erstellen darf. diff --git a/config/locales/el.yml b/config/locales/el.yml index ce46ac37a78..a4be9b34c61 100644 --- a/config/locales/el.yml +++ b/config/locales/el.yml @@ -956,9 +956,15 @@ el: disabled: Να απαιτείται συγκεκριμένος ρόλος χρήστη public: Όλοι landing_page: + hints: + about_html: Μια σελίδα με την περιγραφή, τις πληροφορίες επικοινωνίας, τους κανόνες και άλλες πληροφορίες σχετικά με αυτόν τον διακομιστή. + local_feed_html: Μια ζωντανή ροή που αναδεικνύει τις πιο πρόσφατες αναρτήσεις από τους χρήστες σε αυτόν τον διακομιστή. + overview_html: Μια σελίδα που παρουσιάζει την περιγραφή του διακομιστή σας μαζί με τις πιο πρόσφατες τοπικές αναρτήσεις από τους χρήστες σε αυτόν τον διακομιστή. + trends_html: Μια σελίδα που αναδεικνύει τι είναι δημοφιλές σε αυτόν τον διακομιστή αυτήν τη στιγμή. values: - about: Σχετικά - local_feed: Τοπική ροή + about: Σελίδα Σχετικά με + local_feed: Τοπική ζωντανή ροή + overview: Επισκόπηση trends: Τάσεις registrations: moderation_recommandation: Παρακαλώ βεβαιώσου ότι έχεις μια επαρκής και ενεργή ομάδα συντονισμού πριν ανοίξεις τις εγγραφές για όλους! diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml index c1b2407446d..5fa15b01879 100644 --- a/config/locales/en-GB.yml +++ b/config/locales/en-GB.yml @@ -879,11 +879,6 @@ en-GB: authenticated: Authenticated users only disabled: Require specific user role public: Everyone - landing_page: - values: - about: About - local_feed: Local feed - trends: Trends registrations: moderation_recommandation: Please make sure you have an adequate and reactive moderation team before you open registrations to everyone! preamble: Control who can create an account on your server. diff --git a/config/locales/es-AR.yml b/config/locales/es-AR.yml index e8838d5e2c0..b41df68af48 100644 --- a/config/locales/es-AR.yml +++ b/config/locales/es-AR.yml @@ -956,10 +956,16 @@ es-AR: disabled: Requerir un rol de específico de usuario public: Todos landing_page: + hints: + about_html: Una página con la descripción, información de contacto, reglas y otra información relacionada a este servidor. + local_feed_html: Una línea temporal en vivo con los mensajes más recientes de los usuarios en este servidor. + overview_html: Una página que muestra la descripción de tu servidor junto a los mensajes locales más recientes de tus usuarios. + trends_html: Una página con lo que es popular en este servidor ahora mismo. values: - about: Información - local_feed: Línea temporal local - trends: Tendencias + about: Acerca de la página + local_feed: Línea temporal local en vivo + overview: Visión general + trends: En tendencia registrations: moderation_recommandation: Por favor, ¡asegurate de tener un equipo de moderación adecuado y reactivo antes de abrir los registros a todos! preamble: Controlá quién puede crear una cuenta en tu servidor. diff --git a/config/locales/es-MX.yml b/config/locales/es-MX.yml index e7e3a1d0f7d..d5b34b78147 100644 --- a/config/locales/es-MX.yml +++ b/config/locales/es-MX.yml @@ -955,11 +955,6 @@ es-MX: authenticated: Solo usuarios registrados disabled: Requerir un rol de usuario específico public: Todos - landing_page: - values: - about: Acerca de - local_feed: Feed local - trends: Tendencias registrations: moderation_recommandation: "¡Por favor, asegúrate de contar con un equipo de moderación adecuado y activo antes de abrir el registro al público!" preamble: Controla quién puede crear una cuenta en tu servidor. diff --git a/config/locales/es.yml b/config/locales/es.yml index c234628964f..44b7d0517ac 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -955,11 +955,6 @@ es: authenticated: Solo usuarios autenticados disabled: Requerir un rol de usuario específico public: Todos - landing_page: - values: - about: Acerca de - local_feed: Cronología local - trends: Tendencias registrations: moderation_recommandation: Por favor, ¡asegúrate de tener un equipo de moderación adecuado y reactivo antes de abrir los registros a todo el mundo! preamble: Controla quién puede crear una cuenta en tu servidor. @@ -979,7 +974,7 @@ es: site_uploads: delete: Eliminar archivo subido destroyed_msg: "¡Carga del sitio eliminada con éxito!" - skip_to_content: Ir al contenido + skip_to_content: Saltar al contenido software_updates: critical_update: Crítica— por favor actualiza rápidamente description: Se recomienda mantener actualizada tu instalación de Mastodon para beneficiarte de las últimas correcciones y características. Además, a veces es crítico actualizar Mastodon de manera oportuna para evitar problemas de seguridad. Por estas razones, Mastodon comprueba si hay actualizaciones cada 30 minutos, y te notificará de acuerdo a tus preferencias de notificación por correo electrónico. diff --git a/config/locales/et.yml b/config/locales/et.yml index 5c20dd2f6eb..34227ceb483 100644 --- a/config/locales/et.yml +++ b/config/locales/et.yml @@ -955,11 +955,6 @@ et: authenticated: Vaid autenditud kasutajad disabled: Eelda konkreetse kasutajarolli olemasolu public: Kõik - landing_page: - values: - about: Teave - local_feed: Kohalik sisuvoog - trends: Trendid registrations: moderation_recommandation: Enne kõigi jaoks registreerimise avamist veendu, et oleks olemas adekvaatne ja reageerimisvalmis modereerijaskond! preamble: Kes saab serveril konto luua. diff --git a/config/locales/eu.yml b/config/locales/eu.yml index 4d8398b08ab..2a762afde02 100644 --- a/config/locales/eu.yml +++ b/config/locales/eu.yml @@ -841,11 +841,6 @@ eu: authenticated: Saioa hasi duten erabiltzaileentzat soilik disabled: Erabiltzaile-rol jakin bat behar da public: Edonork - landing_page: - values: - about: Honi buruz - local_feed: Jario lokala - trends: Joerak registrations: moderation_recommandation: Mesedez, ziurtatu moderazio-talde egokia eta erreaktiboa duzula erregistroak guztiei ireki aurretik! preamble: Kontrolatu nork sortu dezakeen kontua zerbitzarian. diff --git a/config/locales/fa.yml b/config/locales/fa.yml index 8c2f5ebb0ba..96c0cb1ba2b 100644 --- a/config/locales/fa.yml +++ b/config/locales/fa.yml @@ -935,11 +935,6 @@ fa: authenticated: تنها کاربران تأیید شده disabled: نیازمند نقش کاربری خاص public: هرکسی - landing_page: - values: - about: درباره - local_feed: خوراک محلی - trends: داغ‌ها registrations: moderation_recommandation: لطفاً قبل از اینکه ثبت نام را برای همه باز کنید، مطمئن شوید که یک تیم نظارتی مناسب و واکنشی دارید! preamble: کنترل کنید چه کسی می تواند در سرور شما یک حساب ایجاد کند. diff --git a/config/locales/fi.yml b/config/locales/fi.yml index 2f4ecc5bcdc..a965d214e31 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -948,10 +948,16 @@ fi: disabled: Vaadi tiettyä käyttäjäroolia public: Kaikki landing_page: + hints: + about_html: Sivu, jolla on kuvaus, yhteystiedot, säännöt ja muita tietoja tästä palvelimesta. + local_feed_html: Livesyöte, joka esittelee tämän palvelimen viimeisimpiä julkaisuja. + overview_html: Sivu, joka esittelee palvelimesi kuvauksen viimeisimpien tämän palvelimen käyttäjien paikallisten julkaisujen ohella. + trends_html: Sivu, joka esittelee, mikä on suosittua palvelimella juuri nyt. values: - about: Tietoja - local_feed: Paikallinen syöte - trends: Trendit + about: Tietoja-sivu + local_feed: Paikallinen livesyöte + overview: Yleiskatsaus + trends: Suosittua registrations: moderation_recommandation: Varmista, että sinulla on riittävä ja toimintavalmis joukko moderaattoreita, ennen kuin avaat rekisteröitymisen kaikille! preamble: Määritä, kuka voi luoda tilin palvelimellesi. diff --git a/config/locales/fo.yml b/config/locales/fo.yml index 9493ffbc070..c061badd2c0 100644 --- a/config/locales/fo.yml +++ b/config/locales/fo.yml @@ -875,11 +875,6 @@ fo: authenticated: Einans váttaðir brúkarar disabled: Krev serstakan brúkaraleiklut public: Øll - landing_page: - values: - about: Um - local_feed: Lokal rás - trends: Rák registrations: moderation_recommandation: Vinarliga tryggja tær, at tú hevur eitt nøktandi og klárt umsjónartoymi, áðreen tú letur upp fyri skrásetingum frá øllum! preamble: Stýr, hvør kann stovna eina kontu á tínum ambætara. diff --git a/config/locales/fr-CA.yml b/config/locales/fr-CA.yml index 11791c5d9d4..3b877f339b0 100644 --- a/config/locales/fr-CA.yml +++ b/config/locales/fr-CA.yml @@ -956,9 +956,15 @@ fr-CA: disabled: Nécessite un rôle spécifique public: Tout le monde landing_page: + hints: + about_html: Une page avec la description, les informations de contact, les règles et d'autres informations concernant ce serveur. + local_feed_html: Un flux en direct avec les messages les plus récents des utilisateur·rice·s sur ce serveur. + overview_html: Une page montrant la description de votre serveur avec les derniers messages locaux des utilisateur·rice·s sur ce serveur. + trends_html: Une page présentant ce qui est populaire sur ce serveur en ce moment. values: - about: À propos - local_feed: Fil local + about: Page À propos + local_feed: Flux local en direct + overview: Aperçu  trends: Tendances registrations: moderation_recommandation: Veuillez vous assurer d'avoir une équipe de modération adéquate et réactive avant d'ouvrir les inscriptions à tout le monde ! diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 5e88e2d1c1c..8b8326e8e0f 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -956,9 +956,15 @@ fr: disabled: Nécessite un rôle spécifique public: Tout le monde landing_page: + hints: + about_html: Une page avec la description, les informations de contact, les règles et d'autres informations concernant ce serveur. + local_feed_html: Un flux en direct avec les messages les plus récents des utilisateur·rice·s sur ce serveur. + overview_html: Une page montrant la description de votre serveur avec les derniers messages locaux des utilisateur·rice·s sur ce serveur. + trends_html: Une page présentant ce qui est populaire sur ce serveur en ce moment. values: - about: À propos - local_feed: Fil local + about: Page À propos + local_feed: Flux local en direct + overview: Aperçu  trends: Tendances registrations: moderation_recommandation: Veuillez vous assurer d'avoir une équipe de modération adéquate et réactive avant d'ouvrir les inscriptions à tout le monde ! diff --git a/config/locales/ga.yml b/config/locales/ga.yml index 7b3eb3c13cb..e0accf79cf3 100644 --- a/config/locales/ga.yml +++ b/config/locales/ga.yml @@ -1003,11 +1003,6 @@ ga: authenticated: Úsáideoirí fíordheimhnithe amháin disabled: Éiligh ról úsáideora sonrach public: Gach duine - landing_page: - values: - about: Maidir - local_feed: Fotha áitiúil - trends: Treochtaí registrations: moderation_recommandation: Cinntigh le do thoil go bhfuil foireann mhodhnóireachta imoibríoch leordhóthanach agat sula n-osclaíonn tú clárúcháin do gach duine! preamble: Rialú cé atá in ann cuntas a chruthú ar do fhreastalaí. @@ -1027,6 +1022,7 @@ ga: site_uploads: delete: Scrios comhad uaslódáilte destroyed_msg: D'éirigh le huaslódáil an tsuímh a scriosadh! + skip_to_content: Léim go dtí an t-ábhar software_updates: critical_update: Criticiúil - nuashonraigh go tapa le do thoil description: Moltar do shuiteáil Mastodon a choinneáil cothrom le dáta chun leas a bhaint as na socruithe agus na gnéithe is déanaí. Ina theannta sin, tá sé ríthábhachtach uaireanta Mastodon a nuashonrú go tráthúil chun saincheisteanna slándála a sheachaint. Ar na cúiseanna seo, seiceálann Mastodon nuashonruithe gach 30 nóiméad, agus tabharfaidh sé fógra duit de réir do shainroghanna fógra ríomhphoist. diff --git a/config/locales/gd.yml b/config/locales/gd.yml index 8ba20031e8a..af419f999f6 100644 --- a/config/locales/gd.yml +++ b/config/locales/gd.yml @@ -911,11 +911,6 @@ gd: authenticated: Cleachdaichean a chlàraich a-steach a-mhàin disabled: Iarr dreuchd shònraichte a’ chleachdaiche public: A h-uile duine - landing_page: - values: - about: Mu dhèidhinn - local_feed: Loidhne-ama ionadail - trends: Treandaichean registrations: moderation_recommandation: Dèan cinnteach gu bheil sgioba maoir deiseil is deònach agad mus fhosgail thu an clàradh dhan a h-uile duine! preamble: Stiùirich cò dh’fhaodas cunntas a chruthachadh air an fhrithealaiche agad. diff --git a/config/locales/gl.yml b/config/locales/gl.yml index 33f1a2ec22e..a61826206ca 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -956,10 +956,16 @@ gl: disabled: Requerir un rol da usuaria específico public: Para calquera landing_page: + hints: + about_html: Unha páxina coa descrición, información de contacto, regras e outra información relativa a este servidor. + local_feed_html: Unha cronoloxía actual que mostra as publicacións máis recentes das usuarias deste servidor. + overview_html: Unha páxina que mostra a descrición do teu servidor xunto ás publicacións locais máis recentes das usuarias do servidor. + trends_html: Unha páxina que mostra as publicacións populares no servidor neste momento. values: - about: Sobre - local_feed: Cronoloxía Local - trends: Tendencias + about: Páxina sobre + local_feed: Cronoloxía local en directo + overview: Visión xeral + trends: Popular registrations: moderation_recommandation: Por favor, pon interese en crear un equipo de moderación competente e reactivo antes de permitir que calquera poida crear unha conta! preamble: Xestiona quen pode crear unha conta no teu servidor. @@ -979,6 +985,7 @@ gl: site_uploads: delete: Eliminar o ficheiro subido destroyed_msg: Eliminado correctamente o subido! + skip_to_content: Ir ao contido software_updates: critical_update: Crítica - actualiza axiña description: Aconsellamos manter actualizado o teu servidor Mastodon para beneficiarte dos últimos arranxos e características. A maiores, de cando en vez hai actualizacións para evitar problemas importantes de seguridade. Debido a isto, Mastodon comproba cada 30 minutos se hai actualizacións e avisarate seguindo as túas preferencias de notificación por correo electrónico. diff --git a/config/locales/he.yml b/config/locales/he.yml index 724e702e64a..f1533e601a6 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -988,10 +988,16 @@ he: disabled: נדרש תפקיד משתמש מסוים public: כולם landing_page: + hints: + about_html: עמוד עם תיאור השרת, פרטי התקשרות, חוקים ושאר המידע. + local_feed_html: זרם הודעות חי של הפרסומים האחרונים של משתמשים בשרת זה. + overview_html: עמוד המציג את תיאור השרת לצד ההודעות המקומיות האחרונות של משתמשיו ומשתמשותיו. + trends_html: עמוד המציג את התכנים המושכים כניין כרגע על שרת זה. values: - about: אודות - local_feed: פיד מקומי - trends: נושאים חמים + about: דף אודות השרת + local_feed: זרם הודעות בזמן אמת + overview: סקירה כללית + trends: מגמות registrations: moderation_recommandation: יש לוודא שלאתר יש צוות מנחות ומנחי שיחה מספק ושירותי בטרם תבחרו לפתוח הרשמה לכולם! preamble: שליטה בהרשאות יצירת חשבון בשרת שלך. @@ -1011,6 +1017,7 @@ he: site_uploads: delete: מחיקת קובץ שהועלה destroyed_msg: העלאת אתר נמחקה בהצלחה! + skip_to_content: דילוג לתוכן software_updates: critical_update: חשוב -- יש לעדכן במהירות description: מומלץ לשמור את התקנת המסטודון שלך עדכנית כדי להרוויח מהיכולות והתיקונים האחרונים. למעלה מכך, לעיתים קריטי לעדכן את מסטודון בהקדם כדי להמנע מפרצות אבטחה. מסיבות אלו, השרת יבדוק כל 30 דקות, ויודיע לך לפי העדפות הדואל שלך. diff --git a/config/locales/hu.yml b/config/locales/hu.yml index 6f12ea2f225..568716e259a 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -956,10 +956,14 @@ hu: disabled: Konkrét felhasználói szerepkör megkövetelése public: Mindenki landing_page: + hints: + about_html: Egy oldal a leírással, névjegyinformációkkal, szabályokkal és a kiszolgálóval kapcsolatos egyéb információkkal. + local_feed_html: Élő hírfolyam a kiszolgálón lévő felhasználók legfrissebb bejegyzéseivel. values: - about: Névjegy - local_feed: Helyi idővonal - trends: Trendek + about: Névjegy oldal + local_feed: Helyi élő hírfolyam + overview: Áttekintés + trends: Felkapott registrations: moderation_recommandation: Győződj meg arról, hogy megfelelő és gyors reagálású moderátor csapatod van, mielőtt mindenki számára megnyitod a regisztrációt! preamble: Szabályozd, hogy ki hozhat létre fiókot a kiszolgálón. diff --git a/config/locales/ia.yml b/config/locales/ia.yml index c5afddfab0c..4b499c04682 100644 --- a/config/locales/ia.yml +++ b/config/locales/ia.yml @@ -853,11 +853,6 @@ ia: authenticated: Solmente usatores authenticate disabled: Requirer un rolo de usator specific public: Omnes - landing_page: - values: - about: A proposito - local_feed: Canal local - trends: Tendentias registrations: moderation_recommandation: Per favor assecura te de haber un equipa de moderation adequate e reactive ante de aperir le inscription a omnes! preamble: Controla qui pote crear un conto sur tu servitor. diff --git a/config/locales/is.yml b/config/locales/is.yml index 3ae19b479cc..299086d2012 100644 --- a/config/locales/is.yml +++ b/config/locales/is.yml @@ -349,6 +349,7 @@ is: back_to_report: Til baka á kærusíðu batch: add_to_report: 'Bæta við skýrslu #%{id}' + remove_from_report: Fjarlægja úr kæru report: Kæra collection_title: Safn frá %{name} contents: Efni @@ -957,9 +958,15 @@ is: disabled: Krefjast sérstaks hlutverks notanda public: Allir landing_page: + hints: + about_html: Síða með lýsingu, upplýsingum um tengiliði, reglur og annað varðandi þennan netþjón. + local_feed_html: Streymi í beinni með nýjustu færslunum frá notendum á þessum netþjóni. + overview_html: Síða með lýsingu á netþjóninum ásamt nýjustu staðbundnu færslunum frá notendum á þessum netþjóni. + trends_html: Síða með því sem núna er vinsælast á þessum netþjóni. values: - about: Um - local_feed: Staðbundið streymi + about: Upplýsingasíða + local_feed: Staðvært beint streymi + overview: Yfirlit trends: Vinsælt registrations: moderation_recommandation: Tryggðu að þú hafir hæft og aðgengilegt umsjónarteymi til taks áður en þú opnar á skráningar fyrir alla! @@ -980,6 +987,7 @@ is: site_uploads: delete: Eyða innsendri skrá destroyed_msg: Það tókst að eyða innsendingu á vefsvæði! + skip_to_content: Fara beint í efni software_updates: critical_update: Áríðandi - uppfærðu eins fljótt og auðið er description: Mælt er með því að þú haldir Mastodon-uppsetningunni þinni uppfærðri til að vera með nýjustu lagfæringar og eiginleika. Aukinheldur er mikilvægt að halda Mastodon uppfærðu til að komast hjá öryggisveilum. Af þessum ástæðum athugar Mastodon með uppfærslur á 30 mínútna fresti og mun gera þér viðvart í samræmi við stillingar þínar á tilkynningum í tölvupósti. diff --git a/config/locales/it.yml b/config/locales/it.yml index f3223099115..bbd2ed304c3 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -956,10 +956,16 @@ it: disabled: Richiedi un ruolo utente specifico public: Tutti landing_page: + hints: + about_html: Una pagina con la descrizione, informazioni di contatto, regole e altre informazioni riguardanti questo server. + local_feed_html: Un feed in diretta con i post più recenti da parte degli utenti su questo server. + overview_html: Una pagina che mostra la descrizione del tuo server insieme ai post locali più recenti da parte degli utenti su questo server. + trends_html: Una pagina che mostra i contenuti popolari su questo server in questo momento. values: - about: Info - local_feed: Feed locale - trends: Tendenze + about: Pagina delle Info + local_feed: Feed locale in diretta + overview: Panoramica + trends: Di tendenza registrations: moderation_recommandation: Assicurati di avere un team di moderazione adeguato e reattivo prima di aprire le registrazioni a tutti! preamble: Controlla chi può creare un account sul tuo server. @@ -979,6 +985,7 @@ it: site_uploads: delete: Cancella il file caricato destroyed_msg: Caricamento sito eliminato! + skip_to_content: Vai al contenuto software_updates: critical_update: 'Critico: ti preghiamo di aggiornare rapidamente' description: Si consiglia di mantenere aggiornata l'installazione di Mastodon per beneficiare delle ultime correzioni e funzionalità. Inoltre, a volte è fondamentale aggiornare Mastodon in modo tempestivo per evitare problemi di sicurezza. Per queste ragioni, Mastodon verifica la presenza di aggiornamenti ogni 30 minuti e ti avviserà in base alle tue preferenze di notifica e-mail. diff --git a/config/locales/ja.yml b/config/locales/ja.yml index e3111821d4e..677df5da933 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -841,9 +841,6 @@ ja: authenticated: ログイン済みユーザーのみ disabled: 特定ロールのユーザーのみ public: 制限なし - landing_page: - values: - trends: トレンド registrations: moderation_recommandation: 登録受付を開始する前に、迅速かつ適切にモデレーションを行うチームを編成しましょう! preamble: あなたのサーバー上でアカウントを作成できるユーザーを制御します。 diff --git a/config/locales/kab.yml b/config/locales/kab.yml index 5d62dc1570f..c2e8a0e4685 100644 --- a/config/locales/kab.yml +++ b/config/locales/kab.yml @@ -498,10 +498,6 @@ kab: feed_access: modes: public: Yal yiwen - landing_page: - values: - about: Ɣef - trends: Inezzaɣ registrations: title: Ajerred registrations_mode: diff --git a/config/locales/ko.yml b/config/locales/ko.yml index 616b6e7a64a..f7e44fec7df 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -845,11 +845,6 @@ ko: authenticated: 로그인한 사용자들만 disabled: 특정한 사용자 역할 필요 public: 모두 - landing_page: - values: - about: 정보 - local_feed: 로컬 피드 - trends: 유행 registrations: moderation_recommandation: 모두에게 가입을 열기 전에 적절하고 반응이 빠른 중재 팀을 데리고 있는지 확인해 주세요! preamble: 누가 이 서버에 계정을 만들 수 있는지 제어합니다. diff --git a/config/locales/lad.yml b/config/locales/lad.yml index dedb87bf7a4..66f987c5754 100644 --- a/config/locales/lad.yml +++ b/config/locales/lad.yml @@ -841,10 +841,6 @@ lad: feed_access: modes: public: Todos - landing_page: - values: - about: Sovre esto - trends: Trendes registrations: moderation_recommandation: Por favor, asigurate ke tyenes una taifa de moderasyon adekuada i reaktiva antes de avrir los enrejistramyentos a todos! preamble: Kontrola ken puede kriyar un kuento en tu sirvidor. diff --git a/config/locales/nan-TW.yml b/config/locales/nan-TW.yml index 89369022874..3dd63ba515e 100644 --- a/config/locales/nan-TW.yml +++ b/config/locales/nan-TW.yml @@ -345,6 +345,7 @@ nan-TW: back_to_report: Tńg去檢舉ê頁 batch: add_to_report: '加kàu檢舉 #%{id}' + remove_from_report: Tuì檢舉suá掉 report: 檢舉 collection_title: "%{name} ê收藏" contents: 內容 @@ -505,6 +506,28 @@ nan-TW: compliance_settings: additional_footer_text: action: 管理 + hint: Kan-ta佇電子報ê phue ê註kha出現ê通選ê文字 + title: 其他註kha ê文字 + lead: 電子報ê phue可能hőng掠做行銷ê電子批,根據lí pháng ê服侍器ê司法管轄區決定。 + privacy_policy: + action: 管理 + hint: 逐封電子phue ê下kha lóng ē有連kàu tsit ê政策ê連結 + title: 隱私權政策 + title: 守法ê設定 + danger_zone: + disable_feature: + action: 停止使用 + hint: 替逐ê口座關tsit ê功能 + title: Kā功能停止使用 + erase_all_data: + action: 消除資料 + hint: 佇逐ê郵件列單內底ê逐封phue lóng永永thâi掉 + title: 消除所有資料 + title: 危險ê所在 + disabled_msg: 停止使用訂電子批成功ah。 + index: + disabled: + cannot_be_enabled: Lí ê技術提供者iáu buē替lí ê服侍器啟用tsit ê功能。 export_domain_allows: new: title: 輸入允准ê域名 @@ -891,11 +914,6 @@ nan-TW: authenticated: Kan-ta hōo登入ê用者 disabled: 愛特別ê用者角色 public: Ta̍k lâng - landing_page: - values: - about: 關係本站 - local_feed: 本地ê動態 - trends: 趨勢 registrations: moderation_recommandation: 佇開放hōo ta̍k ê lâng註冊進前,請確認lí有夠額koh主動反應ê管理團隊! preamble: 控制ē當佇lí ê服侍器註冊ê人。 diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 399db1a9cd4..bfe797d0c22 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -800,7 +800,7 @@ nl: reported_with_application: Gerapporteerd met applicatie resolved: Opgelost resolved_msg: Rapportage succesvol opgelost! - skip_to_actions: Ga direct naar de maatregelen + skip_to_actions: Ga naar de acties status: Rapportages statuses: Berichten (%{count}) statuses_description_html: De problematische inhoud wordt aan het gerapporteerde account medegedeeld @@ -956,9 +956,15 @@ nl: disabled: Specifieke gebruikersrol vereisen public: Iedereen landing_page: + hints: + about_html: Een pagina met de beschrijving, contactgegevens, regels en andere informatie over deze server. + local_feed_html: Een openbaar toegankelijke tijdlijn met de meest recente berichten van gebruikers op deze server. + overview_html: Een pagina die de beschrijving van je server laat zien, naast de meest recente lokale berichten van gebruikers op deze server. + trends_html: Een pagina met wat momenteel populair op deze server is. values: - about: Over - local_feed: Lokale tijdlijn + about: Pagina over ons + local_feed: Openbare lokale tijdlijn + overview: Overzicht trends: Trends registrations: moderation_recommandation: Zorg ervoor dat je een adequaat en responsief moderatieteam hebt voordat je registraties voor iedereen openstelt! @@ -979,6 +985,7 @@ nl: site_uploads: delete: Geüpload bestand verwijderen destroyed_msg: Verwijderen website-upload geslaagd! + skip_to_content: Ga naar de inhoud software_updates: critical_update: Kritiek — update snel description: Het wordt aanbevolen om je Mastodon-installatie up-to-date te houden om gebruik te kunnen maken van de nieuwste oplossingen en functies. Bovendien is het soms cruciaal om Mastodon tijdig bij te werken om veiligheidsproblemen te voorkomen. Om deze redenen controleert Mastodon elke 30 minuten updates en brengt je hiervan op de hoogte volgens jouw voorkeuren voor e-mailmeldingen. diff --git a/config/locales/nn.yml b/config/locales/nn.yml index 7e329904526..56d7c4331b0 100644 --- a/config/locales/nn.yml +++ b/config/locales/nn.yml @@ -879,11 +879,6 @@ nn: authenticated: Berre godkjende brukarar disabled: Krev ei spesifikk brukarrolle public: Alle - landing_page: - values: - about: Om - local_feed: Lokal tidsline - trends: Populært registrations: moderation_recommandation: Pass på at du har mange og kjappe redaktørar og moderatorar på laget ditt før du opnar for allmenn registrering! preamble: Kontroller kven som kan oppretta konto på tenaren din. diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 56045f676d1..7518ff3630f 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -874,11 +874,6 @@ pl: authenticated: tylko zalogowani użytkownicy disabled: Wymagaj określonej roli użytkownika public: Wszyscy - landing_page: - values: - about: O nas - local_feed: Lokalny kanał - trends: Trendy registrations: moderation_recommandation: Upewnij się, że masz adekwatny i szybko reagujący zespół moderacyjny przed otwarciem rejestracji! preamble: Kontroluj, kto może utworzyć konto na Twoim serwerze. diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index e9cddeac988..7091c370f29 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -956,9 +956,15 @@ pt-BR: disabled: Exige função específica de usuário public: Todos landing_page: + hints: + about_html: Uma página com descrição, informações de contato, regra e qualquer outra informação sobre este servidor. + local_feed_html: Um feed ao vivo exibindo as últimas publicações de usuários neste servidor. + overview_html: Uma página exibindo a descrição do seu servidor junto às últimas publicações locais de usuários neste servidor. + trends_html: Uma página exibindo o que está em alta neste servidor. values: - about: Sobre - local_feed: Feed local + about: Sobre a página + local_feed: Feed local ao vivo + overview: Visão Geral trends: Em alta registrations: moderation_recommandation: Por favor, certifique-se de ter uma equipe de moderação adequada e reativa antes de abrir as inscrições para todos! diff --git a/config/locales/pt-PT.yml b/config/locales/pt-PT.yml index 84cec11eab7..b2fb77bbb74 100644 --- a/config/locales/pt-PT.yml +++ b/config/locales/pt-PT.yml @@ -879,11 +879,6 @@ pt-PT: authenticated: Apesar utilizadores autenticados disabled: Requerer função de utilizador especifica public: Todos - landing_page: - values: - about: Sobre - local_feed: Cronologia local - trends: Tendências registrations: moderation_recommandation: Certifique-se de que dispõe de uma equipa de moderação adequada e reativa antes de abrir as inscrições a todos! preamble: Controle quem pode criar uma conta no seu servidor. diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 03c8e025811..a8f1d03c198 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -909,11 +909,6 @@ ru: authenticated: Только авторизованные пользователи disabled: Только пользователи с особой ролью public: Кто угодно - landing_page: - values: - about: О сервере - local_feed: Локальная лента - trends: Актуальное registrations: moderation_recommandation: Прежде чем открывать регистрацию для всех желающих, убедитесь, что у вас есть компетентная команда модераторов, способная на быструю реакцию! preamble: Контролируйте, кто может создать учётную запись на вашем сервере. diff --git a/config/locales/sl.yml b/config/locales/sl.yml index ca0fd7fe7dc..75b0036b812 100644 --- a/config/locales/sl.yml +++ b/config/locales/sl.yml @@ -868,10 +868,6 @@ sl: modes: authenticated: Samo overjeni uporabniki public: Vsi - landing_page: - values: - local_feed: Krajevni vir - trends: Trendi registrations: moderation_recommandation: Preden prijave odprete za vse poskrbite, da imate v ekipi moderatorjev zadosti aktivnih članov. preamble: Nadzirajte, kdo lahko ustvari račun na vašem strežniku. diff --git a/config/locales/sq.yml b/config/locales/sq.yml index 2580b348507..1c2b70242c3 100644 --- a/config/locales/sq.yml +++ b/config/locales/sq.yml @@ -559,6 +559,9 @@ sq: important_information: Informacion i rëndësishëm list: 1_permission_explanation: Kur aktivizohet kjo veçroi, llogaritë me lejet e caktuara mund të shtojnë te profilet e tyre një formular koleksionesh email. + 2_feature_explanation: Kur vizitorët regjistrohen në faqen e profilit të një llogarie dhe ripohojnë pajtimin e tyre, ata do të fillojnë të marrin përditësime me email, kur llogaria krijon postime të reja publike. + 3_privacy_policy_warning: Përgjegjësit e shërbyesit do të mund të shohin PII (adresat email) të grumbulluara. Prej kësaj, rregullat e privatësisë dhe Kushtet e Shërbimit për shëbyesin duhen përditësuar, para përdorimit të kësaj veçorie. + 4_cost_warning: Email-et mund të sjellin tarifë, varet nga ujdisja e strehimit. Diskutojeni me shërbimin tuaj të strehimit, para se ta aktivizoni, ngaqë kjo veçori mund të rrisë në mënyrë drastike sasinë e email-eve të dërguar nga shërbyesi juaj. export_domain_allows: new: title: Importoni lejime përkatësish @@ -945,9 +948,15 @@ sq: disabled: Lyp doemos rol specifik përdoruesi public: Kushdo landing_page: + hints: + about_html: Një faqe me përshkrimin, hollësi kontakti, rregulla dhe tjetër informacion që lidhet me këtë shërbyes. + local_feed_html: Një prurje e drejtpërdrejtë që përmban postimet më të reja nga përdorues në këtë shërbyes. + overview_html: Një faqe që shpalos përshkrimin e shërbyesit tuaj took me postimet vendore më të freskëta nga përdorues në këtë shërbyes. + trends_html: Një faqe që përmban ç’është popullore në këtë shërbyes mu tani. values: - about: Mbi - local_feed: Prurje vendore + about: Faqe “Mbi” + local_feed: Prurje e drejtpërdrejtë vendore + overview: Përmbledhje trends: Në modë registrations: moderation_recommandation: Ju lutemi, sigurohuni si keni një ekip adekuat dhe reagues moderimi, përpara se të hapni regjistrimet për këdo! diff --git a/config/locales/sv.yml b/config/locales/sv.yml index 762f428e3df..31fc1d7aae3 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -349,6 +349,7 @@ sv: back_to_report: Tillbaka till rapportsidan batch: add_to_report: 'Lägg till i rapport #%{id}' + remove_from_report: Ta bort från rapport report: Rapportera collection_title: Samling av %{name} contents: Innehåll @@ -954,11 +955,6 @@ sv: authenticated: Endast autentiserade användare disabled: Kräv specifik användarroll public: Alla - landing_page: - values: - about: Om - local_feed: Lokalt flöde - trends: Trender registrations: moderation_recommandation: Se till att du har ett tillräckligt och reaktivt modereringsteam innan du öppnar registreringar till alla! preamble: Kontrollera vem som kan skapa ett konto på din server. @@ -978,6 +974,7 @@ sv: site_uploads: delete: Radera uppladdad fil destroyed_msg: Webbplatsuppladdningen har raderats! + skip_to_content: Hoppa till innehåll software_updates: critical_update: Kritiskt — vänligen uppdatera omgående description: Det rekommenderas att hålla din Mastodon-installation uppdaterad för att ta nytta av de senaste fixarna och funktionerna. Dessutom är det ibland viktigt att uppdatera Mastodon i tid för att undvika säkerhetsproblem. Av dessa skäl kontrollerar Mastodon efter uppdateringar var 30:e minut och meddelar dig i enlighet med dina e-postaviseringsinställningar. diff --git a/config/locales/th.yml b/config/locales/th.yml index f94f0641504..a599276c507 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -801,11 +801,6 @@ th: feed_access: modes: public: ทุกคน - landing_page: - values: - about: เกี่ยวกับ - local_feed: ฟีดในเซิร์ฟเวอร์ - trends: แนวโน้ม registrations: moderation_recommandation: โปรดตรวจสอบให้แน่ใจว่าคุณมีทีมการกลั่นกรองที่เพียงพอและมีปฏิกิริยาตอบสนองก่อนที่คุณจะเปิดการลงทะเบียนให้กับทุกคน! preamble: ควบคุมผู้ที่สามารถสร้างบัญชีในเซิร์ฟเวอร์ของคุณ diff --git a/config/locales/tr.yml b/config/locales/tr.yml index 8834eb7ad61..7ec25d873e8 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -957,9 +957,8 @@ tr: public: Herkes landing_page: values: - about: Hakkında - local_feed: Yerel akış - trends: Öne çıkanlar + about: Hakkında sayfası + overview: Genel Bakış registrations: moderation_recommandation: Lütfen kayıtları herkese açmadan önce yeterli ve duyarlı bir denetleyici ekibine sahip olduğunuzdan emin olun! preamble: Sunucunuzda kimin hesap oluşturabileceğini denetleyin. @@ -979,6 +978,7 @@ tr: site_uploads: delete: Yüklenen dosyayı sil destroyed_msg: Site yüklemesi başarıyla silindi! + skip_to_content: İçeriğe atla software_updates: critical_update: Kritik — lütfen hemen güncelleyin description: Son düzeltme ve özelliklerden yararlanmak için Mastodon kurulumunu güncel tutmanızı öneriyoruz. Üstelik güvenlik sorunlarından kaçınmak için Mastodon'u zamanında güncellemek kritiktir. Bu nedenlerle Mastodon her 30 dakikada bir güncellemeleri denetler ve e-posta bildirim seçeneğinize göre size haber verir. diff --git a/config/locales/vi.yml b/config/locales/vi.yml index edc0eaed026..ebb147bc7cb 100644 --- a/config/locales/vi.yml +++ b/config/locales/vi.yml @@ -940,9 +940,15 @@ vi: disabled: Yêu cầu vai trò người dùng cụ thể public: Mọi người landing_page: + hints: + about_html: Trang này chứa mô tả, thông tin liên hệ, nội quy và các thông tin khác liên quan đến máy chủ này. + local_feed_html: Đây là bảng tin hiển thị các tút mới nhất của người dùng trên máy chủ này. + overview_html: Trang này hiển thị mô tả về máy chủ của bạn cùng với các tút gần đây nhất của người dùng trên máy chủ này. + trends_html: Trang này hiển thị những nội dung đang phổ biến trên máy chủ này hiện tại. values: - about: Giới thiệu + about: Trang Giới thiệu local_feed: Bảng tin máy chủ + overview: Tổng quan trends: Xu hướng registrations: moderation_recommandation: Vui lòng đảm bảo rằng bạn có một đội ngũ kiểm duyệt và phản ứng nhanh trước khi mở đăng ký cho mọi người! diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index f1d56319dc9..8ecfbdc16f3 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -939,11 +939,6 @@ zh-CN: authenticated: 仅已登录用户 disabled: 需要特定的用户角色 public: 每个人 - landing_page: - values: - about: 关于 - local_feed: 本站动态 - trends: 热门 registrations: moderation_recommandation: 在向每个人开放注册之前,请确保你拥有一个人手足够且反应迅速的管理团队! preamble: 控制谁可以在你的服务器上创建账号。 diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index 0a14e2f4877..27142c99c40 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -942,9 +942,15 @@ zh-TW: disabled: 需要特定使用者權限 public: 任何人 landing_page: + hints: + about_html: 此為關於此伺服器之描述、聯絡資訊、規則、及其他資訊之頁面。 + local_feed_html: 此為展示此伺服器使用者最新嘟文之即時內容。 + overview_html: 此為展示您的伺服器描述及本站使用者最新嘟文之頁面。 + trends_html: 此為展示此伺服器現正熱門內容之頁面。 values: - about: 關於 - local_feed: 本站時間軸 + about: 關於本站 + local_feed: 本地即時內容 + overview: 總覽 trends: 熱門趨勢 registrations: moderation_recommandation: 對所有人開放註冊之前,請確保您有人手充足且反應靈敏的管理員團隊! From 5f998507ece25be175ceb06e3729c411f3c0f37c Mon Sep 17 00:00:00 2001 From: diondiondion Date: Wed, 27 May 2026 11:38:18 +0200 Subject: [PATCH 32/70] Fix navigation overflow issue in advanced UI (#39178) --- .../mastodon/features/getting_started/index.tsx | 6 ++---- .../mastodon/features/navigation_panel/index.tsx | 15 ++++++++------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/app/javascript/mastodon/features/getting_started/index.tsx b/app/javascript/mastodon/features/getting_started/index.tsx index 5497b2de89e..84c786fa068 100644 --- a/app/javascript/mastodon/features/getting_started/index.tsx +++ b/app/javascript/mastodon/features/getting_started/index.tsx @@ -4,16 +4,14 @@ import { Helmet } from '@unhead/react/helmet'; import { Column } from 'mastodon/components/column'; -import { NavigationPanel, messages } from '../navigation_panel'; +import { NavigationPanel } from '../navigation_panel'; import { LinkFooter } from '../ui/components/link_footer'; const GettingStarted: React.FC = () => { const intl = useIntl(); return ( - + diff --git a/app/javascript/mastodon/features/navigation_panel/index.tsx b/app/javascript/mastodon/features/navigation_panel/index.tsx index 9ac2ee461ee..a734cb882b2 100644 --- a/app/javascript/mastodon/features/navigation_panel/index.tsx +++ b/app/javascript/mastodon/features/navigation_panel/index.tsx @@ -60,7 +60,7 @@ import { MoreLink } from './components/more_link'; import { SignInBanner } from './components/sign_in_banner'; import { Trends } from './components/trends'; -export const messages = defineMessages({ +const messages = defineMessages({ home: { id: 'tabs_bar.home', defaultMessage: 'Home' }, notifications: { id: 'tabs_bar.notifications', @@ -238,7 +238,10 @@ export const NavigationPanel: React.FC<{ multiColumn?: boolean }> = ({ } return ( -
+ ); }; export const CollapsibleNavigationPanel: React.FC = () => { - const intl = useIntl(); const open = useAppSelector((state) => state.navigation.open); const dispatch = useAppDispatch(); const openable = useBreakpoint('openable'); @@ -534,8 +536,7 @@ export const CollapsibleNavigationPanel: React.FC = () => { const showOverlay = openable && open; return ( - +
); }; From bd2e86d7f4f30b290ad1fb4dce6c1b9846776a3d Mon Sep 17 00:00:00 2001 From: diondiondion Date: Wed, 27 May 2026 12:03:45 +0200 Subject: [PATCH 33/70] Refactor "copy to clipboard" functionality into hook (#39180) --- .../components/account_header/buttons.tsx | 2 +- .../components/account_header/name.tsx | 48 +++++------- .../mastodon/components/copy_button.tsx | 75 +++++++++++++++++++ .../mastodon/components/copy_icon_button.tsx | 47 ------------ .../form_fields/copy_link_field.tsx | 2 +- 5 files changed, 97 insertions(+), 77 deletions(-) create mode 100644 app/javascript/mastodon/components/copy_button.tsx delete mode 100644 app/javascript/mastodon/components/copy_icon_button.tsx diff --git a/app/javascript/mastodon/components/account_header/buttons.tsx b/app/javascript/mastodon/components/account_header/buttons.tsx index 7a5ca4332cd..7d7f6e7d8b6 100644 --- a/app/javascript/mastodon/components/account_header/buttons.tsx +++ b/app/javascript/mastodon/components/account_header/buttons.tsx @@ -11,7 +11,7 @@ import NotificationsIcon from '@/material-icons/400-24px/notifications.svg?react import NotificationsActiveIcon from '@/material-icons/400-24px/notifications_active-fill.svg?react'; import ShareIcon from '@/material-icons/400-24px/share.svg?react'; -import { CopyIconButton } from '../copy_icon_button'; +import { CopyIconButton } from '../copy_button'; import { FollowButton } from '../follow_button'; import { IconButton } from '../icon_button'; diff --git a/app/javascript/mastodon/components/account_header/name.tsx b/app/javascript/mastodon/components/account_header/name.tsx index 2b3f1907b4d..b46e849765f 100644 --- a/app/javascript/mastodon/components/account_header/name.tsx +++ b/app/javascript/mastodon/components/account_header/name.tsx @@ -7,17 +7,16 @@ import classNames from 'classnames'; import Overlay from 'react-overlays/esm/Overlay'; -import { showAlert } from '@/mastodon/actions/alerts'; import { useAccount } from '@/mastodon/hooks/useAccount'; import { useRelationship } from '@/mastodon/hooks/useRelationship'; -import { useAppDispatch, useAppSelector } from '@/mastodon/store'; +import { useAppSelector } from '@/mastodon/store'; import AtIcon from '@/material-icons/400-24px/alternate_email.svg?react'; import ContentCopyIcon from '@/material-icons/400-24px/content_copy.svg?react'; import HelpIcon from '@/material-icons/400-24px/help.svg?react'; import DomainIcon from '@/material-icons/400-24px/language.svg?react'; import { FollowsYouBadge } from '../badge'; -import { Button } from '../button'; +import { CopyButton } from '../copy_button'; import { DisplayName } from '../display_name'; import { Icon } from '../icon'; @@ -90,17 +89,6 @@ const AccountNameHelp: FC<{ const handle = `@${username}@${domain}`; - const dispatch = useAppDispatch(); - const [copied, setCopied] = useState(false); - const handleCopy = useCallback(() => { - void navigator.clipboard.writeText(handle); - setCopied(true); - dispatch(showAlert({ message: messages.copied })); - setTimeout(() => { - setCopied(false); - }, 700); - }, [handle, dispatch]); - return ( <> +
)} diff --git a/app/javascript/mastodon/components/copy_button.tsx b/app/javascript/mastodon/components/copy_button.tsx new file mode 100644 index 00000000000..1812054d427 --- /dev/null +++ b/app/javascript/mastodon/components/copy_button.tsx @@ -0,0 +1,75 @@ +import { useState, useCallback } from 'react'; + +import { defineMessages } from 'react-intl'; + +import classNames from 'classnames'; + +import ContentCopyIcon from '@/material-icons/400-24px/content_copy.svg?react'; +import { showAlert } from 'mastodon/actions/alerts'; +import { IconButton } from 'mastodon/components/icon_button'; +import { useAppDispatch } from 'mastodon/store'; + +import { Button } from './button'; + +const messages = defineMessages({ + copied: { + id: 'copy_icon_button.copied', + defaultMessage: 'Copied to clipboard', + }, +}); + +export function useCopyToClipboard({ text }: { text: string }) { + const [wasCopied, setWasCopied] = useState(false); + const dispatch = useAppDispatch(); + + const copyText = useCallback(() => { + void navigator.clipboard.writeText(text); + setWasCopied(true); + dispatch(showAlert({ message: messages.copied })); + setTimeout(() => { + setWasCopied(false); + }, 700); + }, [setWasCopied, text, dispatch]); + + return { copyText, wasCopied }; +} + +export const CopyButton: React.FC< + Omit< + React.ComponentPropsWithoutRef, + 'onClick' | 'text' | 'children' + > & { + value: string; + children: React.ReactNode | ((wasCopied: boolean) => React.ReactNode); + } +> = ({ value, children, ...otherProps }) => { + const { copyText, wasCopied } = useCopyToClipboard({ text: value }); + + const label = typeof children === 'function' ? children(wasCopied) : children; + + return ( + + ); +}; + +export const CopyIconButton: React.FC<{ + title: string; + value: string; + className?: string; + 'aria-describedby'?: string; +}> = ({ title, value, className, 'aria-describedby': ariaDescribedBy }) => { + const { copyText, wasCopied } = useCopyToClipboard({ text: value }); + + return ( + + ); +}; diff --git a/app/javascript/mastodon/components/copy_icon_button.tsx b/app/javascript/mastodon/components/copy_icon_button.tsx deleted file mode 100644 index 51cffe6292e..00000000000 --- a/app/javascript/mastodon/components/copy_icon_button.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { useState, useCallback } from 'react'; - -import { defineMessages } from 'react-intl'; - -import classNames from 'classnames'; - -import ContentCopyIcon from '@/material-icons/400-24px/content_copy.svg?react'; -import { showAlert } from 'mastodon/actions/alerts'; -import { IconButton } from 'mastodon/components/icon_button'; -import { useAppDispatch } from 'mastodon/store'; - -const messages = defineMessages({ - copied: { - id: 'copy_icon_button.copied', - defaultMessage: 'Copied to clipboard', - }, -}); - -export const CopyIconButton: React.FC<{ - title: string; - value: string; - className?: string; - 'aria-describedby'?: string; -}> = ({ title, value, className, 'aria-describedby': ariaDescribedBy }) => { - const [copied, setCopied] = useState(false); - const dispatch = useAppDispatch(); - - const handleClick = useCallback(() => { - void navigator.clipboard.writeText(value); - setCopied(true); - dispatch(showAlert({ message: messages.copied })); - setTimeout(() => { - setCopied(false); - }, 700); - }, [setCopied, value, dispatch]); - - return ( - - ); -}; diff --git a/app/javascript/mastodon/components/form_fields/copy_link_field.tsx b/app/javascript/mastodon/components/form_fields/copy_link_field.tsx index d772315adeb..ab8849d45aa 100644 --- a/app/javascript/mastodon/components/form_fields/copy_link_field.tsx +++ b/app/javascript/mastodon/components/form_fields/copy_link_field.tsx @@ -4,7 +4,7 @@ import { useIntl } from 'react-intl'; import classNames from 'classnames'; -import { CopyIconButton } from 'mastodon/components/copy_icon_button'; +import { CopyIconButton } from '@/mastodon/components/copy_button'; import classes from './copy_link_field.module.scss'; import { FormFieldWrapper } from './form_field_wrapper'; From b5879fd61fe6c6e570920fca0501ba7fa2568a72 Mon Sep 17 00:00:00 2001 From: diondiondion Date: Wed, 27 May 2026 12:33:52 +0200 Subject: [PATCH 34/70] Refactor `BundleColumnError` to TS (#39177) --- .../empty_state/empty_state.module.scss | 23 ++-- .../empty_state/empty_state.stories.tsx | 8 ++ .../mastodon/components/empty_state/index.tsx | 9 +- app/javascript/mastodon/components/gif.tsx | 2 +- .../account_edit/components/column.tsx | 2 +- .../features/account_featured/index.tsx | 2 +- .../features/account_gallery/index.tsx | 2 +- .../features/account_timeline/index.tsx | 2 +- .../features/followers/components/list.tsx | 2 +- .../features/terms_of_service/index.tsx | 2 +- .../ui/components/bundle_column_error.jsx | 116 ----------------- .../components/bundle_column_error/index.tsx | 122 ++++++++++++++++++ .../bundle_column_error/styles.module.scss | 12 ++ .../features/ui/components/columns_area.tsx | 2 +- .../styles/mastodon/components.scss | 48 +------ 15 files changed, 173 insertions(+), 181 deletions(-) delete mode 100644 app/javascript/mastodon/features/ui/components/bundle_column_error.jsx create mode 100644 app/javascript/mastodon/features/ui/components/bundle_column_error/index.tsx create mode 100644 app/javascript/mastodon/features/ui/components/bundle_column_error/styles.module.scss diff --git a/app/javascript/mastodon/components/empty_state/empty_state.module.scss b/app/javascript/mastodon/components/empty_state/empty_state.module.scss index 64d9a4e584e..cb2332aec6f 100644 --- a/app/javascript/mastodon/components/empty_state/empty_state.module.scss +++ b/app/javascript/mastodon/components/empty_state/empty_state.module.scss @@ -13,8 +13,7 @@ .content { max-width: 370px; - svg, - img { + :where(svg, img) { width: 200px; aspect-ratio: 1; object-fit: contain; @@ -22,16 +21,10 @@ margin-bottom: 16px; } - h3 { - font-size: 17px; - font-weight: 500; - text-wrap: balance; - line-height: 1.2; - } - p { margin-top: 8px; font-size: 15px; + line-height: 1.4; color: var(--color-text-secondary); text-wrap: pretty; } @@ -41,6 +34,18 @@ } } +.heading { + font-size: 17px; + font-weight: 500; + text-wrap: balance; + line-height: 1.2; +} + +.errorImage { + width: 280px; + margin: -10% 0; +} + [data-color-scheme='dark'] .defaultImage { --color-skin-1: #3a3a50; --color-skin-2: #67678e; diff --git a/app/javascript/mastodon/components/empty_state/empty_state.stories.tsx b/app/javascript/mastodon/components/empty_state/empty_state.stories.tsx index 83fce034686..c1faaf6f399 100644 --- a/app/javascript/mastodon/components/empty_state/empty_state.stories.tsx +++ b/app/javascript/mastodon/components/empty_state/empty_state.stories.tsx @@ -29,6 +29,14 @@ export const Default: Story = { }, }; +export const Error: Story = { + args: { + image: 'error', + title: 'Error', + message: 'Something went wrong loading the page.', + }, +}; + export const WithAction: Story = { args: { ...Default.args, diff --git a/app/javascript/mastodon/components/empty_state/index.tsx b/app/javascript/mastodon/components/empty_state/index.tsx index e332aaedb5c..3f0738ce5a5 100644 --- a/app/javascript/mastodon/components/empty_state/index.tsx +++ b/app/javascript/mastodon/components/empty_state/index.tsx @@ -4,10 +4,15 @@ import classNames from 'classnames'; import ElephantImage from '@/images/elephant_ui.svg?react'; +import { GIF } from '../gif'; + import classes from './empty_state.module.scss'; const images = { default: , + error: ( + + ), }; /** @@ -21,6 +26,7 @@ export const EmptyState: React.FC<{ title?: React.ReactNode; message?: React.ReactNode; children?: React.ReactNode; + headingLevel?: 'h2' | 'h3' | 'h4'; className?: string; }> = ({ image = 'default', @@ -29,6 +35,7 @@ export const EmptyState: React.FC<{ ), message, children, + headingLevel: Heading = 'h2', className, }) => { const imageToRender = typeof image === 'string' ? images[image] : image; @@ -38,7 +45,7 @@ export const EmptyState: React.FC<{ {(title || message || imageToRender) && (
{imageToRender} - {!!title &&

{title}

} + {!!title && {title}} {!!message &&

{message}

}
)} diff --git a/app/javascript/mastodon/components/gif.tsx b/app/javascript/mastodon/components/gif.tsx index 1cc0881a5a3..7bce9857845 100644 --- a/app/javascript/mastodon/components/gif.tsx +++ b/app/javascript/mastodon/components/gif.tsx @@ -4,7 +4,7 @@ import { autoPlayGif } from 'mastodon/initial_state'; export const GIF: React.FC<{ src: string; staticSrc: string; - className: string; + className?: string; animate?: boolean; }> = ({ src, staticSrc, className, animate = autoPlayGif }) => { const { hovering, handleMouseEnter, handleMouseLeave } = useHovering(animate); diff --git a/app/javascript/mastodon/features/account_edit/components/column.tsx b/app/javascript/mastodon/features/account_edit/components/column.tsx index a9b0f8cbd5d..2718aab7f21 100644 --- a/app/javascript/mastodon/features/account_edit/components/column.tsx +++ b/app/javascript/mastodon/features/account_edit/components/column.tsx @@ -9,7 +9,7 @@ import { Helmet } from '@unhead/react/helmet'; import { Column } from '@/mastodon/components/column'; import { ColumnHeader } from '@/mastodon/components/column_header'; import { LoadingIndicator } from '@/mastodon/components/loading_indicator'; -import BundleColumnError from '@/mastodon/features/ui/components/bundle_column_error'; +import { BundleColumnError } from '@/mastodon/features/ui/components/bundle_column_error'; import { useColumnsContext } from '../../ui/util/columns_context'; import classes from '../styles.module.scss'; diff --git a/app/javascript/mastodon/features/account_featured/index.tsx b/app/javascript/mastodon/features/account_featured/index.tsx index 3082f19abc9..bccdddeda83 100644 --- a/app/javascript/mastodon/features/account_featured/index.tsx +++ b/app/javascript/mastodon/features/account_featured/index.tsx @@ -19,7 +19,7 @@ import { } from '@/mastodon/components/scrollable_list/components'; import type { TruncatedListItemInfo } from '@/mastodon/components/truncated_list'; import { TruncatedListItems } from '@/mastodon/components/truncated_list'; -import BundleColumnError from '@/mastodon/features/ui/components/bundle_column_error'; +import { BundleColumnError } from '@/mastodon/features/ui/components/bundle_column_error'; import Column from '@/mastodon/features/ui/components/column'; import { useAccount } from '@/mastodon/hooks/useAccount'; import { useAccountId } from '@/mastodon/hooks/useAccountId'; diff --git a/app/javascript/mastodon/features/account_gallery/index.tsx b/app/javascript/mastodon/features/account_gallery/index.tsx index feba6f454d5..25ad8c88c10 100644 --- a/app/javascript/mastodon/features/account_gallery/index.tsx +++ b/app/javascript/mastodon/features/account_gallery/index.tsx @@ -11,7 +11,7 @@ import { ColumnBackButton } from '@/mastodon/components/column_back_button'; import { LimitedAccountHint } from '@/mastodon/components/limited_account_hint'; import { RemoteHint } from '@/mastodon/components/remote_hint'; import ScrollableList from '@/mastodon/components/scrollable_list'; -import BundleColumnError from '@/mastodon/features/ui/components/bundle_column_error'; +import { BundleColumnError } from '@/mastodon/features/ui/components/bundle_column_error'; import Column from '@/mastodon/features/ui/components/column'; import { useAccountId } from '@/mastodon/hooks/useAccountId'; import { useAccountVisibility } from '@/mastodon/hooks/useAccountVisibility'; diff --git a/app/javascript/mastodon/features/account_timeline/index.tsx b/app/javascript/mastodon/features/account_timeline/index.tsx index ce1e99a45fa..450236386a1 100644 --- a/app/javascript/mastodon/features/account_timeline/index.tsx +++ b/app/javascript/mastodon/features/account_timeline/index.tsx @@ -19,7 +19,7 @@ import { LimitedAccountHint } from '@/mastodon/components/limited_account_hint'; import { LoadingIndicator } from '@/mastodon/components/loading_indicator'; import { RemoteHint } from '@/mastodon/components/remote_hint'; import StatusList from '@/mastodon/components/status_list'; -import BundleColumnError from '@/mastodon/features/ui/components/bundle_column_error'; +import { BundleColumnError } from '@/mastodon/features/ui/components/bundle_column_error'; import { useAccountId, useCurrentAccountId, diff --git a/app/javascript/mastodon/features/followers/components/list.tsx b/app/javascript/mastodon/features/followers/components/list.tsx index 6c600d570f3..3c593e10b8b 100644 --- a/app/javascript/mastodon/features/followers/components/list.tsx +++ b/app/javascript/mastodon/features/followers/components/list.tsx @@ -6,7 +6,7 @@ import { Column } from '@/mastodon/components/column'; import { ColumnBackButton } from '@/mastodon/components/column_back_button'; import { LoadingIndicator } from '@/mastodon/components/loading_indicator'; import ScrollableList from '@/mastodon/components/scrollable_list'; -import BundleColumnError from '@/mastodon/features/ui/components/bundle_column_error'; +import { BundleColumnError } from '@/mastodon/features/ui/components/bundle_column_error'; import { useAccount } from '@/mastodon/hooks/useAccount'; import { useAccountVisibility } from '@/mastodon/hooks/useAccountVisibility'; import { useLayout } from '@/mastodon/hooks/useLayout'; diff --git a/app/javascript/mastodon/features/terms_of_service/index.tsx b/app/javascript/mastodon/features/terms_of_service/index.tsx index 669fb18b926..0a7c2d5669f 100644 --- a/app/javascript/mastodon/features/terms_of_service/index.tsx +++ b/app/javascript/mastodon/features/terms_of_service/index.tsx @@ -14,7 +14,7 @@ import { Helmet } from '@unhead/react/helmet'; import { apiGetTermsOfService } from 'mastodon/api/instance'; import type { ApiTermsOfServiceJSON } from 'mastodon/api_types/instance'; import { Column } from 'mastodon/components/column'; -import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error'; +import { BundleColumnError } from 'mastodon/features/ui/components/bundle_column_error'; const messages = defineMessages({ title: { id: 'terms_of_service.title', defaultMessage: 'Terms of Service' }, diff --git a/app/javascript/mastodon/features/ui/components/bundle_column_error.jsx b/app/javascript/mastodon/features/ui/components/bundle_column_error.jsx deleted file mode 100644 index 81fb8f48c7e..00000000000 --- a/app/javascript/mastodon/features/ui/components/bundle_column_error.jsx +++ /dev/null @@ -1,116 +0,0 @@ -import PropTypes from 'prop-types'; -import { PureComponent } from 'react'; - -import { FormattedMessage } from 'react-intl'; - -import classNames from 'classnames'; -import { Helmet } from '@unhead/react/helmet'; -import { Link } from 'react-router-dom'; - -import { Button } from 'mastodon/components/button'; -import Column from 'mastodon/components/column'; -import { injectIntl } from '@/mastodon/components/intl'; -import { GIF } from 'mastodon/components/gif'; - -class CopyButton extends PureComponent { - - static propTypes = { - children: PropTypes.node.isRequired, - value: PropTypes.string.isRequired, - }; - - state = { - copied: false, - }; - - handleClick = () => { - const { value } = this.props; - navigator.clipboard.writeText(value); - this.setState({ copied: true }); - this.timeout = setTimeout(() => this.setState({ copied: false }), 700); - }; - - componentWillUnmount () { - if (this.timeout) clearTimeout(this.timeout); - } - - render () { - const { children } = this.props; - const { copied } = this.state; - - return ( - - ); - } - -} - -class BundleColumnError extends PureComponent { - - static propTypes = { - errorType: PropTypes.oneOf(['routing', 'network', 'error']), - onRetry: PropTypes.func, - intl: PropTypes.object.isRequired, - multiColumn: PropTypes.bool, - stacktrace: PropTypes.string, - }; - - static defaultProps = { - errorType: 'routing', - }; - - handleRetry = () => { - const { onRetry } = this.props; - - if (onRetry) { - onRetry(); - } - }; - - render () { - const { errorType, multiColumn, stacktrace } = this.props; - - let title, body; - - switch(errorType) { - case 'routing': - title = ; - body = ; - break; - case 'network': - title = ; - body = ; - break; - case 'error': - title = ; - body = ; - break; - } - - return ( - -
- - -
-

{title}

-

{body}

- -
- {errorType === 'network' && } - {errorType === 'error' && } - -
-
-
- - - - -
- ); - } - -} - -export default injectIntl(BundleColumnError); diff --git a/app/javascript/mastodon/features/ui/components/bundle_column_error/index.tsx b/app/javascript/mastodon/features/ui/components/bundle_column_error/index.tsx new file mode 100644 index 00000000000..f4acb3059f3 --- /dev/null +++ b/app/javascript/mastodon/features/ui/components/bundle_column_error/index.tsx @@ -0,0 +1,122 @@ +import { FormattedMessage } from 'react-intl'; + +import classNames from 'classnames'; +import { Link } from 'react-router-dom'; + +import { Helmet } from '@unhead/react/helmet'; + +import { CopyButton } from '@/mastodon/components/copy_button'; +import { EmptyState } from '@/mastodon/components/empty_state'; +import { Button } from 'mastodon/components/button'; +import { Column } from 'mastodon/components/column'; + +import classes from './styles.module.scss'; + +interface BundleColumnErrorProps { + errorType?: 'routing' | 'network' | 'error'; + onRetry?: () => void; + multiColumn?: boolean; + stacktrace?: string; +} + +export const BundleColumnError: React.FC = ({ + errorType = 'routing', + onRetry, + multiColumn, + stacktrace, +}) => { + let title, body; + + switch (errorType) { + case 'routing': + title = ( + + ); + body = ( + + ); + break; + case 'network': + title = ( + + ); + body = ( + + ); + break; + case 'error': + title = ( + + ); + body = ( + + ); + break; + } + + return ( + + +
+ {errorType === 'network' && onRetry && ( + + )} + {errorType === 'error' && stacktrace && ( + + + + )} + + + +
+
+ + + + +
+ ); +}; + +// eslint-disable-next-line import/no-default-export +export default BundleColumnError; diff --git a/app/javascript/mastodon/features/ui/components/bundle_column_error/styles.module.scss b/app/javascript/mastodon/features/ui/components/bundle_column_error/styles.module.scss new file mode 100644 index 00000000000..62549efffc2 --- /dev/null +++ b/app/javascript/mastodon/features/ui/components/bundle_column_error/styles.module.scss @@ -0,0 +1,12 @@ +.error { + flex-grow: 1; + border: 1px solid var(--color-border-primary); + border-radius: 4px; +} + +.actions { + display: flex; + flex-wrap: wrap; + gap: 8px 12px; + justify-content: center; +} diff --git a/app/javascript/mastodon/features/ui/components/columns_area.tsx b/app/javascript/mastodon/features/ui/components/columns_area.tsx index f5ab3de849e..cd94f34ec07 100644 --- a/app/javascript/mastodon/features/ui/components/columns_area.tsx +++ b/app/javascript/mastodon/features/ui/components/columns_area.tsx @@ -33,7 +33,7 @@ import { import { useColumnsContext } from '../util/columns_context'; import Bundle from './bundle'; -import BundleColumnError from './bundle_column_error'; +import { BundleColumnError } from './bundle_column_error'; import { ColumnLoading } from './column_loading'; import { ComposePanel, RedirectToMobileComposeIfNeeded } from './compose_panel'; import DrawerLoading from './drawer_loading'; diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 809634e8f5b..a2771815abc 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -3374,8 +3374,7 @@ a.account__display-name { .column-header, .column-back-button, - .scrollable, - .error-column { + .scrollable { border-radius: 0 !important; } @@ -5288,51 +5287,6 @@ a.status-card { margin-bottom: 0; } -.error-column { - padding: 20px; - border: 1px solid var(--color-border-primary); - border-radius: 4px; - display: flex; - flex: 1 1 auto; - align-items: center; - justify-content: center; - flex-direction: column; - cursor: default; - - &__image { - width: 70%; - max-width: 350px; - margin-top: -50px; - } - - &__message { - text-align: center; - color: var(--color-text-secondary); - font-size: 15px; - line-height: 22px; - - h1 { - font-size: 28px; - line-height: 33px; - font-weight: 700; - margin-bottom: 15px; - color: var(--color-text-primary); - } - - p { - max-width: 48ch; - } - - &__actions { - margin-top: 30px; - display: flex; - gap: 10px; - align-items: center; - justify-content: center; - } - } -} - @keyframes heartbeat { 0% { transform: scale(1); From 888011de6970f337a154127a63823043997e5f8f Mon Sep 17 00:00:00 2001 From: diondiondion Date: Wed, 27 May 2026 12:35:15 +0200 Subject: [PATCH 35/70] [Accessibility] Differentiate accessible labels of About links in footer (#39181) --- app/javascript/mastodon/features/ui/components/link_footer.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/javascript/mastodon/features/ui/components/link_footer.tsx b/app/javascript/mastodon/features/ui/components/link_footer.tsx index 1f4ee7cde95..2b73bad152b 100644 --- a/app/javascript/mastodon/features/ui/components/link_footer.tsx +++ b/app/javascript/mastodon/features/ui/components/link_footer.tsx @@ -29,6 +29,7 @@ export const LinkFooter: React.FC<{ id='footer.about_this_server' defaultMessage='About' /> + {domain} {statusPageUrl && ( @@ -82,6 +83,7 @@ export const LinkFooter: React.FC<{
  • + Mastodon
  • From d229157f193e1394718151c5048e2e2857dee46d Mon Sep 17 00:00:00 2001 From: Echo Date: Wed, 27 May 2026 15:13:38 +0200 Subject: [PATCH 36/70] Collections: Handle URLs in search (#39182) --- app/javascript/mastodon/api_types/search.ts | 2 ++ .../mastodon/features/compose/components/search.tsx | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/app/javascript/mastodon/api_types/search.ts b/app/javascript/mastodon/api_types/search.ts index 795cbb2b41f..961dd65699a 100644 --- a/app/javascript/mastodon/api_types/search.ts +++ b/app/javascript/mastodon/api_types/search.ts @@ -1,4 +1,5 @@ import type { ApiAccountJSON } from './accounts'; +import type { ApiCollectionJSON } from './collections'; import type { ApiStatusJSON } from './statuses'; import type { ApiHashtagJSON } from './tags'; @@ -8,4 +9,5 @@ export interface ApiSearchResultsJSON { accounts: ApiAccountJSON[]; statuses: ApiStatusJSON[]; hashtags: ApiHashtagJSON[]; + collections: ApiCollectionJSON[]; } diff --git a/app/javascript/mastodon/features/compose/components/search.tsx b/app/javascript/mastodon/features/compose/components/search.tsx index 9c7baf50214..8fa2a5db478 100644 --- a/app/javascript/mastodon/features/compose/components/search.tsx +++ b/app/javascript/mastodon/features/compose/components/search.tsx @@ -19,6 +19,7 @@ import { useHistory } from 'react-router-dom'; import { isFulfilled } from '@reduxjs/toolkit'; +import { getCollectionPath } from '@/mastodon/features/collections/utils'; import CancelIcon from '@/material-icons/400-24px/cancel-fill.svg?react'; import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import SearchIcon from '@/material-icons/400-24px/search.svg?react'; @@ -337,6 +338,10 @@ export const Search: React.FC<{ history.push( `/@${result.payload.statuses[0].account.acct}/${result.payload.statuses[0].id}`, ); + } else if (result.payload.collections[0]) { + history.push( + getCollectionPath(result.payload.collections[0].id), + ); } } From f0726bf9afab8fb09a32f35d4f5f38b944e8184e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 27 May 2026 15:29:37 +0200 Subject: [PATCH 37/70] Update dependency @reduxjs/toolkit to v2.12.0 (#36700) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/yarn.lock b/yarn.lock index 48f731f1eb4..ea281af27ce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4077,12 +4077,12 @@ __metadata: linkType: hard "@reduxjs/toolkit@npm:^2.0.1": - version: 2.9.2 - resolution: "@reduxjs/toolkit@npm:2.9.2" + version: 2.12.0 + resolution: "@reduxjs/toolkit@npm:2.12.0" dependencies: "@standard-schema/spec": "npm:^1.0.0" "@standard-schema/utils": "npm:^0.3.0" - immer: "npm:^10.0.3" + immer: "npm:^11.0.0" redux: "npm:^5.0.1" redux-thunk: "npm:^3.1.0" reselect: "npm:^5.1.0" @@ -4094,7 +4094,7 @@ __metadata: optional: true react-redux: optional: true - checksum: 10c0/577416200c76ffd82bce6158aaeb63e836ed2c2a14e670253056dcaec505da77643e79b47208b4e493a0c120a4a2bc049efe60cd555a2699053af5b03f2f2953 + checksum: 10c0/2b85e31294a7139994fd78b08eb3ce706ce3b03b5081c13403b93ba4883a152d637171e4d9d969766238851f8915b1daa9f36b5a0a458aff0ff7600ee38795c9 languageName: node linkType: hard @@ -9425,10 +9425,10 @@ __metadata: languageName: node linkType: hard -"immer@npm:^10.0.3": - version: 10.0.3 - resolution: "immer@npm:10.0.3" - checksum: 10c0/282a4f8479a40f7d12b2b3243c095e3e892bf99058e2ffcdd6b8e9fd143e6a90f2717ab9b6c8b97c927ffb8054465c8f647056f41660dbfd672e240cf1063503 +"immer@npm:^11.0.0": + version: 11.1.8 + resolution: "immer@npm:11.1.8" + checksum: 10c0/df971d8a8f6a5312c6dca4a8437e20b3185d6c9cd6830ad526c18ffd50f4037ef8db4f332b0adbcb9f8c5ee2fbe117cf0623e8554e24777105b3cc9faf866d34 languageName: node linkType: hard From 965f01f52af250a3a264fb1e3450fbbd7ede5316 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 27 May 2026 11:36:05 -0400 Subject: [PATCH 38/70] Handle current bundler-audit CVEs (#39183) --- .bundler-audit.yml | 3 +++ Gemfile.lock | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 .bundler-audit.yml diff --git a/.bundler-audit.yml b/.bundler-audit.yml new file mode 100644 index 00000000000..4dae946991b --- /dev/null +++ b/.bundler-audit.yml @@ -0,0 +1,3 @@ +--- +ignore: + - CVE-2026-45363 diff --git a/Gemfile.lock b/Gemfile.lock index 4644688f468..333294b836b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -235,7 +235,7 @@ GEM fabrication (3.0.0) faker (3.8.0) i18n (>= 1.8.11, < 2) - faraday (2.14.1) + faraday (2.14.2) faraday-net_http (>= 2.0, < 3.5) json logger @@ -243,7 +243,7 @@ GEM faraday (>= 1, < 3) faraday-httpclient (2.0.2) httpclient (>= 2.2) - faraday-net_http (3.4.2) + faraday-net_http (3.4.3) net-http (~> 0.5) fast_blank (1.0.1) fastimage (2.4.1) From a5ea6452682bb1f1c76fbd15403158f8de8b9546 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 27 May 2026 17:39:20 +0200 Subject: [PATCH 39/70] Update github/codeql-action digest to 7211b7c (#39156) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/codeql.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 93bc87d7605..afb70669565 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -35,7 +35,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4 + uses: github/codeql-action/init@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -48,7 +48,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4 + uses: github/codeql-action/autobuild@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4 # ℹ️ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -61,6 +61,6 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4 + uses: github/codeql-action/analyze@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4 with: category: '/language:${{matrix.language}}' From ed23fafd1d6d1fc250d846ec1a4228be93258938 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 27 May 2026 17:39:38 +0200 Subject: [PATCH 40/70] Update codecov/codecov-action digest to e79a696 (#39155) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/test-ruby.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-ruby.yml b/.github/workflows/test-ruby.yml index 90c9dc89370..ac95c708ddf 100644 --- a/.github/workflows/test-ruby.yml +++ b/.github/workflows/test-ruby.yml @@ -167,7 +167,7 @@ jobs: - name: Upload coverage reports to Codecov if: matrix.ruby-version == '.ruby-version' - uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6 + uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6 with: files: coverage/lcov/*.lcov env: From ddd687b98e3cea8c172f3b0b0e4cf36f96582886 Mon Sep 17 00:00:00 2001 From: Itoh Shimon Date: Thu, 28 May 2026 01:23:52 +0900 Subject: [PATCH 41/70] Enable vertical text editing on Alt text editor (#38797) --- app/javascript/styles/mastodon/components.scss | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index a2771815abc..b5bc754dc43 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -1361,6 +1361,7 @@ body > [data-popper-placement] { // this element inherits a text direction that is opposite to its own, // the start of this element's text is cut off. + // Posts on the timeline .status:not(.status--is-quote) > .status__content > .status__content__text:lang(#{$lang}), @@ -1375,6 +1376,7 @@ body > [data-popper-placement] { overflow-x: hidden; // read more } + // Post editor .autosuggest-textarea > .autosuggest-textarea__textarea:lang(#{$lang}) { writing-mode: vertical-lr; min-height: 209px; // writable @@ -1383,6 +1385,18 @@ body > [data-popper-placement] { scrollbar-color: unset; } + // Alt text editor + .dialog-modal__content__form + > .input + > .label_input + > textarea#description:lang(#{$lang}) { + writing-mode: vertical-lr; + min-height: 150px; // writable + max-height: 150px; // suppress autosizing by react-textarea-autosize + overflow-x: auto; + } + + // Detailed posts .detailed-status > .status__content > .status__content__text:lang(#{$lang}) { writing-mode: vertical-lr; width: 100%; // detecting overflow From 9215e1ec53dcf3714080c84af7af070bcb8d9978 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 27 May 2026 16:25:00 +0000 Subject: [PATCH 42/70] Update Yarn to v4.15.0 (#39093) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- streaming/package.json | 2 +- yarn.lock | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 3edde49a714..76f4ee1c7a2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@mastodon/mastodon", "license": "AGPL-3.0-or-later", - "packageManager": "yarn@4.14.1", + "packageManager": "yarn@4.15.0", "engines": { "node": ">=22" }, diff --git a/streaming/package.json b/streaming/package.json index a8ebc63b78a..0581cd75ad0 100644 --- a/streaming/package.json +++ b/streaming/package.json @@ -1,7 +1,7 @@ { "name": "@mastodon/streaming", "license": "AGPL-3.0-or-later", - "packageManager": "yarn@4.14.1", + "packageManager": "yarn@4.15.0", "engines": { "node": ">=22" }, diff --git a/yarn.lock b/yarn.lock index ea281af27ce..0246f9ce399 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,7 +2,7 @@ # Manual changes might be lost - proceed with caution! __metadata: - version: 9 + version: 10 cacheKey: 10c0 "@aashutoshrathi/word-wrap@npm:^1.2.3": From 03b20bc0a4b12940602325a52fbcd50274b1118c Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 28 May 2026 03:19:52 -0400 Subject: [PATCH 43/70] Use `rescue_from` to handle missing status scenario in `NotificationMailer` (#38155) --- app/mailers/notification_mailer.rb | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/app/mailers/notification_mailer.rb b/app/mailers/notification_mailer.rb index ecb37509686..db9218619ad 100644 --- a/app/mailers/notification_mailer.rb +++ b/app/mailers/notification_mailer.rb @@ -19,17 +19,15 @@ class NotificationMailer < ApplicationMailer default to: -> { email_address_with_name(@user.email, @me.username) } + rescue_from(ActiveRecord::RecordNotFound) { false } + layout 'mailer' def mention - return if @status.blank? - mail subject: default_i18n_subject(name: @status.account.acct) end def quote - return if @status.blank? - mail subject: default_i18n_subject(name: @status.account.acct) end @@ -38,14 +36,10 @@ class NotificationMailer < ApplicationMailer end def favourite - return if @status.blank? - mail subject: default_i18n_subject(name: @account.acct) end def reblog - return if @status.blank? - mail subject: default_i18n_subject(name: @account.acct) end @@ -64,7 +58,7 @@ class NotificationMailer < ApplicationMailer end def set_status - @status = @notification.target_status + @status = @notification.target_status || raise(ActiveRecord::RecordNotFound) end def set_account From 4ba9421201a66be65d73efdc3df44dd42e1e1fd2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 12:30:01 +0200 Subject: [PATCH 44/70] Update dependency ws to v8.21.0 (#39151) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 0246f9ce399..abdf900a381 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16337,8 +16337,8 @@ __metadata: linkType: hard "ws@npm:^8.12.1, ws@npm:^8.18.0, ws@npm:^8.19.0, ws@npm:^8.20.0": - version: 8.20.1 - resolution: "ws@npm:8.20.1" + version: 8.21.0 + resolution: "ws@npm:8.21.0" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ">=5.0.2" @@ -16347,7 +16347,7 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 10c0/ce162433218399cdedeb76fd33363d4d86a7d910058d4e3c679dce08cea65d6da6b39f11baa4d7808d024cf46ed88f6a05c17611621aaad8fc5e62edacc30c5d + checksum: 10c0/ef4a243476283fc49bc7550966c4af4aa0eef56273837211e700de3b664e08604a760cdddcb5ba43c049140e74ccfec5b0ee0bb439e08c2adf9138902fdde5f9 languageName: node linkType: hard From 080894529d19e3dc8842ca7933be9474134303c8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 10:30:43 +0000 Subject: [PATCH 45/70] Update dependency ioredis to v5.11.0 (#39168) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 62 +++++++++++++++++++++---------------------------------- 1 file changed, 23 insertions(+), 39 deletions(-) diff --git a/yarn.lock b/yarn.lock index abdf900a381..3add265cd95 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2786,10 +2786,10 @@ __metadata: languageName: node linkType: hard -"@ioredis/commands@npm:1.5.1": - version: 1.5.1 - resolution: "@ioredis/commands@npm:1.5.1" - checksum: 10c0/cb8f6d13cff0753e3e7ef001fb895491985d9a623248192538f13bc2fd9bfdfde3c18cf2ba6f20ec8ceaa681b0771070d3a09b82eed044c798bcfef5e3ae54b3 +"@ioredis/commands@npm:1.10.0": + version: 1.10.0 + resolution: "@ioredis/commands@npm:1.10.0" + checksum: 10c0/baf91e62d0e64ef2b5f7ca4413dc2456fe250e87483beac4a1c8ef1fe5ad0d2fcdeb9b89d4556d8ef6c7455c64a964359d729601fdb06b2f4c76c35dd59afa99 languageName: node linkType: hard @@ -6900,10 +6900,10 @@ __metadata: languageName: node linkType: hard -"cluster-key-slot@npm:^1.1.0": - version: 1.1.2 - resolution: "cluster-key-slot@npm:1.1.2" - checksum: 10c0/d7d39ca28a8786e9e801eeb8c770e3c3236a566625d7299a47bb71113fb2298ce1039596acb82590e598c52dbc9b1f088c8f587803e697cb58e1867a95ff94d3 +"cluster-key-slot@npm:1.1.1": + version: 1.1.1 + resolution: "cluster-key-slot@npm:1.1.1" + checksum: 10c0/079b1ae86b20e2d53308a877b08de5e830722a45c07810569d0dab4955bed569da33ac9f79998289d014adf02cca7223a0647cb0ee6548a12ab3c4f9beac1377 languageName: node linkType: hard @@ -7319,7 +7319,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.3.6, debug@npm:^4.4.0, debug@npm:^4.4.1, debug@npm:^4.4.3": +"debug@npm:4, debug@npm:4.4.3, debug@npm:^4.1.0, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.3.6, debug@npm:^4.4.0, debug@npm:^4.4.1, debug@npm:^4.4.3": version: 4.4.3 resolution: "debug@npm:4.4.3" dependencies: @@ -7437,7 +7437,7 @@ __metadata: languageName: node linkType: hard -"denque@npm:^2.1.0": +"denque@npm:2.1.0": version: 2.1.0 resolution: "denque@npm:2.1.0" checksum: 10c0/f9ef81aa0af9c6c614a727cb3bd13c5d7db2af1abf9e6352045b86e85873e629690f6222f4edd49d10e4ccf8f078bbeec0794fafaf61b659c0589d0c511ec363 @@ -9546,19 +9546,17 @@ __metadata: linkType: hard "ioredis@npm:^5.3.2": - version: 5.10.1 - resolution: "ioredis@npm:5.10.1" + version: 5.11.0 + resolution: "ioredis@npm:5.11.0" dependencies: - "@ioredis/commands": "npm:1.5.1" - cluster-key-slot: "npm:^1.1.0" - debug: "npm:^4.3.4" - denque: "npm:^2.1.0" - lodash.defaults: "npm:^4.2.0" - lodash.isarguments: "npm:^3.1.0" - redis-errors: "npm:^1.2.0" - redis-parser: "npm:^3.0.0" - standard-as-callback: "npm:^2.1.0" - checksum: 10c0/d0507b52520d3bdd5dacaa33aed9dd3133794d8633b43a6b7fc3199a5e73f92cb77409f6904abe68e3221a95a630d97073b8c1c9e2c0c7613124db67e97c0eb0 + "@ioredis/commands": "npm:1.10.0" + cluster-key-slot: "npm:1.1.1" + debug: "npm:4.4.3" + denque: "npm:2.1.0" + redis-errors: "npm:1.2.0" + redis-parser: "npm:3.0.0" + standard-as-callback: "npm:2.1.0" + checksum: 10c0/6bba1eda256bafabf581089ec24c98bccc5af614b108f13fca6672ea707c36d67e7021c4f0965cbe0294e7a3964b6dbd897a95ed7f8fe82a175531219e91b84f languageName: node linkType: hard @@ -10552,20 +10550,6 @@ __metadata: languageName: node linkType: hard -"lodash.defaults@npm:^4.2.0": - version: 4.2.0 - resolution: "lodash.defaults@npm:4.2.0" - checksum: 10c0/d5b77aeb702caa69b17be1358faece33a84497bcca814897383c58b28a2f8dfc381b1d9edbec239f8b425126a3bbe4916223da2a576bb0411c2cefd67df80707 - languageName: node - linkType: hard - -"lodash.isarguments@npm:^3.1.0": - version: 3.1.0 - resolution: "lodash.isarguments@npm:3.1.0" - checksum: 10c0/5e8f95ba10975900a3920fb039a3f89a5a79359a1b5565e4e5b4310ed6ebe64011e31d402e34f577eca983a1fc01ff86c926e3cbe602e1ddfc858fdd353e62d8 - languageName: node - linkType: hard - "lodash.merge@npm:^4.6.2": version: 4.6.2 resolution: "lodash.merge@npm:4.6.2" @@ -13219,14 +13203,14 @@ __metadata: languageName: node linkType: hard -"redis-errors@npm:^1.0.0, redis-errors@npm:^1.2.0": +"redis-errors@npm:1.2.0, redis-errors@npm:^1.0.0": version: 1.2.0 resolution: "redis-errors@npm:1.2.0" checksum: 10c0/5b316736e9f532d91a35bff631335137a4f974927bb2fb42bf8c2f18879173a211787db8ac4c3fde8f75ed6233eb0888e55d52510b5620e30d69d7d719c8b8a7 languageName: node linkType: hard -"redis-parser@npm:^3.0.0": +"redis-parser@npm:3.0.0": version: 3.0.0 resolution: "redis-parser@npm:3.0.0" dependencies: @@ -14305,7 +14289,7 @@ __metadata: languageName: node linkType: hard -"standard-as-callback@npm:^2.1.0": +"standard-as-callback@npm:2.1.0": version: 2.1.0 resolution: "standard-as-callback@npm:2.1.0" checksum: 10c0/012677236e3d3fdc5689d29e64ea8a599331c4babe86956bf92fc5e127d53f85411c5536ee0079c52c43beb0026b5ce7aa1d834dd35dd026e82a15d1bcaead1f From 725b1964d2fff27244c3015824747dcce482994f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 10:32:34 +0000 Subject: [PATCH 46/70] Update dependency pg-connection-string to v2.13.0 (#39068) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 3add265cd95..3882158e70b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11921,9 +11921,9 @@ __metadata: linkType: hard "pg-connection-string@npm:^2.12.0, pg-connection-string@npm:^2.6.0": - version: 2.12.0 - resolution: "pg-connection-string@npm:2.12.0" - checksum: 10c0/3a26c62884a9f0464718f652bd5d6bce276ebda830c0fef4de4f88ae73c2507d70cae1d45c2f5b49bebd76187fb4c94f889d07c53fca6acd06b2eecbebcdc336 + version: 2.13.0 + resolution: "pg-connection-string@npm:2.13.0" + checksum: 10c0/870f83a8fca06d0340fc522653471d9c7081efbadf25c7f5801fcfb58104ef527138bb5d0546b21498ff4df75a742469622f657911a3b74034a1e94e59f34e31 languageName: node linkType: hard From ad821c8b74b041663aa5617bbcc70b03ff91ee90 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 10:36:32 +0000 Subject: [PATCH 47/70] Update dependency sidekiq to v8.1.6 (#39189) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 333294b836b..205dbed5670 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -816,7 +816,7 @@ GEM securerandom (0.4.1) shoulda-matchers (7.0.1) activesupport (>= 7.1) - sidekiq (8.1.5) + sidekiq (8.1.6) connection_pool (>= 3.0.0) json (>= 2.16.0) logger (>= 1.7.0) From dabf28a421d34c4c11009b40cbdad2b2a0c5f451 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 10:40:27 +0000 Subject: [PATCH 48/70] Update dependency sidekiq-unique-jobs to v8.1.0 (#38468) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 205dbed5670..c82a3f443da 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -827,7 +827,7 @@ GEM sidekiq-scheduler (6.0.2) rufus-scheduler (~> 3.2) sidekiq (>= 7.3, < 9) - sidekiq-unique-jobs (8.0.13) + sidekiq-unique-jobs (8.1.0) concurrent-ruby (~> 1.0, >= 1.0.5) sidekiq (>= 7.0.0, < 9.0.0) thor (>= 1.0, < 3.0) From 51fb5abeba976cc8fb6385df7358878184bdfcb6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 10:42:48 +0000 Subject: [PATCH 49/70] Update dependency net-http to '~> 0.9.0' (#36881) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile | 2 +- Gemfile.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index d4c1008a4fb..d345cb1f4a7 100644 --- a/Gemfile +++ b/Gemfile @@ -223,7 +223,7 @@ gem 'concurrent-ruby', require: false gem 'connection_pool', require: false gem 'xorcist', '~> 1.1' -gem 'net-http', '~> 0.6.0' +gem 'net-http', '~> 0.9.0' gem 'rubyzip', '~> 3.0' gem 'hcaptcha', '~> 7.1' diff --git a/Gemfile.lock b/Gemfile.lock index c82a3f443da..9c8e6f0abb4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -455,8 +455,8 @@ GEM msgpack (1.8.0) multi_json (1.20.1) mutex_m (0.3.0) - net-http (0.6.0) - uri + net-http (0.9.1) + uri (>= 0.11.1) net-imap (0.6.4) date net-protocol @@ -1012,7 +1012,7 @@ DEPENDENCIES memory_profiler mime-types (~> 3.7.0) mutex_m - net-http (~> 0.6.0) + net-http (~> 0.9.0) net-ldap (~> 0.18) nokogiri (~> 1.15) omniauth (~> 2.0) From 161cea90c77b68a57b6f70909841e27c0352dde2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 11:46:57 +0000 Subject: [PATCH 50/70] Update Node.js to 24.16 (#39130) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .nvmrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nvmrc b/.nvmrc index a2e33f6e2c0..78582455673 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -24.15 +24.16 From 554b6cf35ef83d32469e1e35e915f3baf06c1b56 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 28 May 2026 15:35:23 -0400 Subject: [PATCH 51/70] Update playwright to version 1.60.0 (#39199) --- Gemfile | 2 +- Gemfile.lock | 4 ++-- package.json | 2 +- yarn.lock | 20 ++++++++++---------- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Gemfile b/Gemfile index d345cb1f4a7..8576937d2df 100644 --- a/Gemfile +++ b/Gemfile @@ -135,7 +135,7 @@ group :test do # Browser integration testing gem 'capybara', '~> 3.39' gem 'capybara-playwright-driver' - gem 'playwright-ruby-client', '1.59.1', require: false # Pinning the exact version as it needs to be kept in sync with the installed npm package + gem 'playwright-ruby-client', '1.60.0', require: false # Pinning the exact version as it needs to be kept in sync with the installed npm package # Used to reset the database between system tests gem 'database_cleaner-active_record' diff --git a/Gemfile.lock b/Gemfile.lock index 9c8e6f0abb4..635d8555697 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -598,7 +598,7 @@ GEM pg (1.6.3) pghero (3.8.0) activerecord (>= 7.2) - playwright-ruby-client (1.59.1) + playwright-ruby-client (1.60.0) base64 concurrent-ruby (>= 1.1.6) mime-types (>= 3.0) @@ -1040,7 +1040,7 @@ DEPENDENCIES parslet pg (~> 1.5) pghero - playwright-ruby-client (= 1.59.1) + playwright-ruby-client (= 1.60.0) premailer-rails prometheus_exporter (~> 2.2) propshaft diff --git a/package.json b/package.json index 76f4ee1c7a2..6cebc2948a5 100644 --- a/package.json +++ b/package.json @@ -180,7 +180,7 @@ "msw": "^2.12.1", "msw-storybook-addon": "^2.0.6", "oxfmt": "^0.47.0", - "playwright": "^1.57.0", + "playwright": "^1.60.0", "react-test-renderer": "^18.2.0", "storybook": "^10.3.0", "stylelint": "^17.0.0", diff --git a/yarn.lock b/yarn.lock index 3882158e70b..eec215751e8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3007,7 +3007,7 @@ __metadata: msw-storybook-addon: "npm:^2.0.6" oxfmt: "npm:^0.47.0" path-complete-extname: "npm:^1.0.0" - playwright: "npm:^1.57.0" + playwright: "npm:^1.60.0" postcss-preset-env: "npm:^11.0.0" prop-types: "npm:^15.8.1" punycode: "npm:^2.3.0" @@ -12105,27 +12105,27 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.59.1": - version: 1.59.1 - resolution: "playwright-core@npm:1.59.1" +"playwright-core@npm:1.60.0": + version: 1.60.0 + resolution: "playwright-core@npm:1.60.0" bin: playwright-core: cli.js - checksum: 10c0/d41a74d9681ce3beb3d5239e9ed577710b4ad099a6ca2476219c6599d51e9cb4b80bd72ed82c528da6a5d929c18ae3b872cf02bb83f78fa1c2cb9199c501abee + checksum: 10c0/99ccd43923b6e9355e0723b7fe221e6326efd4687f8dafff951313662aea11db51f542a9c2122c704c445fb9baae1c9ec9fa6f895126bbddd9fe92313f6942c9 languageName: node linkType: hard -"playwright@npm:^1.57.0": - version: 1.59.1 - resolution: "playwright@npm:1.59.1" +"playwright@npm:^1.60.0": + version: 1.60.0 + resolution: "playwright@npm:1.60.0" dependencies: fsevents: "npm:2.3.2" - playwright-core: "npm:1.59.1" + playwright-core: "npm:1.60.0" dependenciesMeta: fsevents: optional: true bin: playwright: cli.js - checksum: 10c0/dfe38396e616e5c4f98825ce90037bb96e477c5a2bd9258a24854f8ce72a8a41427b19098863866f85aa0216e70287dd537c4438d761aca93995e31ae099c533 + checksum: 10c0/714ad76d85b4865d7e43c0012f9039800c1485373388973ed39d79339cee5ad467052d1e2f1eaeca107a1cb6e65342186a8578a4c3504853d84c3a691250d5db languageName: node linkType: hard From faa5944d4627f8d843ec63c7f95769b2fd1a2787 Mon Sep 17 00:00:00 2001 From: David Roetzel Date: Thu, 28 May 2026 21:52:49 +0200 Subject: [PATCH 52/70] Hydrate user-specific feature approval policy (#39194) --- app/lib/status_cache_hydrator.rb | 72 +++++++++++++++----------- spec/lib/status_cache_hydrator_spec.rb | 2 +- 2 files changed, 44 insertions(+), 30 deletions(-) diff --git a/app/lib/status_cache_hydrator.rb b/app/lib/status_cache_hydrator.rb index 1f1184d42fa..d5920530c60 100644 --- a/app/lib/status_cache_hydrator.rb +++ b/app/lib/status_cache_hydrator.rb @@ -5,42 +5,45 @@ class StatusCacheHydrator @status = status end - def hydrate(account_id, nested: false) + def hydrate(account_or_id, nested: false) + account = account_or_id.is_a?(Account) ? account_or_id : Account.find(account_or_id) + # The cache of the serialized hash is generated by the fan-out-on-write service payload = Rails.cache.fetch("fan-out/#{@status.id}") { InlineRenderer.render(@status, nil, :status) } # If we're delivering to the author who disabled the display of the application used to create the # status, we need to hydrate the application, since it was not rendered for the basic payload - payload[:application] = payload_application if payload[:application].nil? && @status.account_id == account_id + payload[:application] = payload_application if payload[:application].nil? && @status.account_id == account.id # We take advantage of the fact that some relationships can only occur with an original status, not # the reblog that wraps it, so we can assume that some values are always false if payload[:reblog] - hydrate_reblog_payload(payload, account_id, nested:) + hydrate_reblog_payload(payload, account, nested:) else - hydrate_non_reblog_payload(payload, account_id, nested:) + hydrate_non_reblog_payload(payload, account, nested:) end end private - def hydrate_non_reblog_payload(empty_payload, account_id, nested: false) + def hydrate_non_reblog_payload(empty_payload, account, nested: false) empty_payload.tap do |payload| - fill_status_payload(payload, @status, account_id, fresh: !nested, nested:) + fill_status_payload(payload, @status, account, fresh: !nested, nested:) end end - def hydrate_reblog_payload(empty_payload, account_id, nested: false) + def hydrate_reblog_payload(empty_payload, account, nested: false) empty_payload.tap do |payload| payload[:muted] = false payload[:bookmarked] = false - payload[:pinned] = false if @status.account_id == account_id + payload[:pinned] = false if @status.account_id == account.id # If the reblogged status is being delivered to the author who disabled the display of the application # used to create the status, we need to hydrate it here too - payload[:reblog][:application] = payload_reblog_application if payload[:reblog][:application].nil? && @status.reblog.account_id == account_id + payload[:reblog][:application] = payload_reblog_application if payload[:reblog][:application].nil? && @status.reblog.account_id == account.id - fill_status_payload(payload[:reblog], @status.reblog, account_id, fresh: false, nested:) + hydrate_account(payload[:account], account) + fill_status_payload(payload[:reblog], @status.reblog, account, fresh: false, nested:) payload[:filtered] = payload[:reblog][:filtered] payload[:favourited] = payload[:reblog][:favourited] @@ -49,36 +52,37 @@ class StatusCacheHydrator end end - def fill_status_payload(payload, status, account_id, nested: false, fresh: true) - payload[:favourited] = Favourite.exists?(account_id: account_id, status_id: status.id) - payload[:reblogged] = Status.exists?(account_id: account_id, reblog_of_id: status.id) - payload[:muted] = ConversationMute.exists?(account_id: account_id, conversation_id: status.conversation_id) - payload[:bookmarked] = Bookmark.exists?(account_id: account_id, status_id: status.id) - payload[:pinned] = StatusPin.exists?(account_id: account_id, status_id: status.id) if status.account_id == account_id - payload[:filtered] = mapped_applied_custom_filter(account_id, status) - # TODO: performance optimization by not loading `Account` twice - payload[:quote_approval][:current_user] = status.quote_policy_for_account(Account.find_by(id: account_id)) if payload[:quote_approval] - payload[:quote] = hydrate_quote_payload(payload[:quote], status.quote, account_id, nested:) if payload[:quote] + def fill_status_payload(payload, status, account, nested: false, fresh: true) + payload[:favourited] = Favourite.exists?(account_id: account.id, status_id: status.id) + payload[:reblogged] = Status.exists?(account_id: account.id, reblog_of_id: status.id) + payload[:muted] = ConversationMute.exists?(account_id: account.id, conversation_id: status.conversation_id) + payload[:bookmarked] = Bookmark.exists?(account_id: account.id, status_id: status.id) + payload[:pinned] = StatusPin.exists?(account_id: account.id, status_id: status.id) if status.account_id == account.id + payload[:filtered] = mapped_applied_custom_filter(account, status) + payload[:quote_approval][:current_user] = status.quote_policy_for_account(account) if payload[:quote_approval] + payload[:quote] = hydrate_quote_payload(payload[:quote], status.quote, account, nested:) if payload[:quote] if payload[:poll] if fresh # If the status is brand new, we don't need to look up votes in database - payload[:poll][:voted] = status.account_id == account_id + payload[:poll][:voted] = status.account_id == account.id payload[:poll][:own_votes] = [] - elsif status.account_id == account_id + elsif status.account_id == account.id payload[:poll][:voted] = true payload[:poll][:own_votes] = [] else - own_votes = PollVote.where(poll_id: status.poll_id, account_id: account_id).pluck(:choice) + own_votes = PollVote.where(poll_id: status.poll_id, account_id: account.id).pluck(:choice) payload[:poll][:voted] = !own_votes.empty? payload[:poll][:own_votes] = own_votes end end - payload[:card][:missing_attribution] = status.preview_card.unverified_author_account_id == account_id if payload[:card] + payload[:card][:missing_attribution] = status.preview_card.unverified_author_account_id == account.id if payload[:card] # Nested statuses are more likely to have a stale cache fill_status_stats(payload, status) if nested + + hydrate_account(payload[:account], account) end def fill_status_stats(payload, status) @@ -88,7 +92,7 @@ class StatusCacheHydrator payload[:quotes_count] = status.quotes_count end - def hydrate_quote_payload(empty_payload, quote, account_id, nested: false) + def hydrate_quote_payload(empty_payload, quote, account, nested: false) return unless quote&.acceptable? empty_payload.tap do |payload| @@ -100,14 +104,14 @@ class StatusCacheHydrator payload[nested ? :quoted_status_id : :quoted_status] = nil payload[:state] = 'deleted' else - filter_state = StatusFilter.new(quote.quoted_status, Account.find_by(id: account_id)).filter_state_for_quote + filter_state = StatusFilter.new(quote.quoted_status, account).filter_state_for_quote payload[:state] = filter_state || 'accepted' if filter_state == 'unauthorized' payload[nested ? :quoted_status_id : :quoted_status] = nil elsif nested payload[:quoted_status_id] = quote.quoted_status_id&.to_s else - payload[:quoted_status] = StatusCacheHydrator.new(quote.quoted_status).hydrate(account_id, nested: true) + payload[:quoted_status] = StatusCacheHydrator.new(quote.quoted_status).hydrate(account, nested: true) end end else @@ -116,9 +120,19 @@ class StatusCacheHydrator end end - def mapped_applied_custom_filter(account_id, status) + def hydrate_account(payload, account) + return unless Mastodon::Feature.collections_enabled? + return unless payload[:id] + + stale_account = Account.find_by(id: payload[:id]) + return if stale_account.nil? + + payload[:feature_approval][:current_user] = stale_account.feature_policy_for_account(account) + end + + def mapped_applied_custom_filter(account, status) CustomFilter - .apply_cached_filters(CustomFilter.cached_filters_for(account_id), status) + .apply_cached_filters(CustomFilter.cached_filters_for(account), status) .map { |filter| serialized_filter(filter) } end diff --git a/spec/lib/status_cache_hydrator_spec.rb b/spec/lib/status_cache_hydrator_spec.rb index 3eb781dfba0..03e453c046e 100644 --- a/spec/lib/status_cache_hydrator_spec.rb +++ b/spec/lib/status_cache_hydrator_spec.rb @@ -6,7 +6,7 @@ RSpec.describe StatusCacheHydrator do let(:status) { Fabricate(:status) } let(:account) { Fabricate(:account) } - describe '#hydrate' do + describe '#hydrate', feature: :collections do let(:compare_to_hash) { InlineRenderer.render(status, account, :status) } shared_examples 'shared behavior' do From 4101f567c5da9f388f48cfd59ea805646dd6159a Mon Sep 17 00:00:00 2001 From: Echo Date: Thu, 28 May 2026 22:13:56 +0200 Subject: [PATCH 53/70] Collection notification filtering (#39198) --- .../mastodon/actions/notification_groups.ts | 15 +- .../mastodon/actions/notifications.js | 3 + .../components/column_settings.jsx | 6 + .../components/column_settings_group.tsx | 162 ++++++++++++++++++ .../features/notifications_v2/filter_bar.tsx | 13 ++ app/javascript/mastodon/locales/en.json | 2 + app/javascript/mastodon/reducers/settings.js | 3 + .../mastodon/selectors/notifications.ts | 5 +- app/javascript/mastodon/selectors/settings.ts | 17 +- 9 files changed, 218 insertions(+), 8 deletions(-) create mode 100644 app/javascript/mastodon/features/notifications/components/column_settings_group.tsx diff --git a/app/javascript/mastodon/actions/notification_groups.ts b/app/javascript/mastodon/actions/notification_groups.ts index 2d03ef080f5..eddd6a93008 100644 --- a/app/javascript/mastodon/actions/notification_groups.ts +++ b/app/javascript/mastodon/actions/notification_groups.ts @@ -36,9 +36,18 @@ function notificationTypeForFilter(type: NotificationType) { } function notificationTypeForQuickFilter(type: NotificationType) { - if (type === 'quoted_update') return 'update'; - else if (type === 'quote') return 'mention'; - else return type; + switch (type) { + case 'quoted_update': + return 'update'; + case 'quote': + return 'mention'; + case 'collection_update': + return 'collection'; + case 'added_to_collection': + return 'collection'; + default: + return type; + } } function excludeAllTypesExcept(filter: string) { diff --git a/app/javascript/mastodon/actions/notifications.js b/app/javascript/mastodon/actions/notifications.js index da0c5f11025..cb4cd1251c4 100644 --- a/app/javascript/mastodon/actions/notifications.js +++ b/app/javascript/mastodon/actions/notifications.js @@ -86,6 +86,9 @@ export function setupBrowserNotifications() { }; } +/** + * @param {(NotificationPermission) => void} callback + */ export function requestBrowserPermission(callback = noOp) { return dispatch => { requestNotificationPermission((permission) => { diff --git a/app/javascript/mastodon/features/notifications/components/column_settings.jsx b/app/javascript/mastodon/features/notifications/components/column_settings.jsx index b1f4e598185..588af106b58 100644 --- a/app/javascript/mastodon/features/notifications/components/column_settings.jsx +++ b/app/javascript/mastodon/features/notifications/components/column_settings.jsx @@ -12,6 +12,7 @@ import ClearColumnButton from './clear_column_button'; import GrantPermissionButton from './grant_permission_button'; import { PolicyControls } from './policy_controls'; import SettingToggle from './setting_toggle'; +import { ColumnSettingsGroup } from './column_settings_group'; class ColumnSettings extends PureComponent { static propTypes = { @@ -187,6 +188,11 @@ class ColumnSettings extends PureComponent { + } + /> + {((this.props.identity.permissions & PERMISSION_MANAGE_USERS) === PERMISSION_MANAGE_USERS) && (

    diff --git a/app/javascript/mastodon/features/notifications/components/column_settings_group.tsx b/app/javascript/mastodon/features/notifications/components/column_settings_group.tsx new file mode 100644 index 00000000000..f888488be32 --- /dev/null +++ b/app/javascript/mastodon/features/notifications/components/column_settings_group.tsx @@ -0,0 +1,162 @@ +import { useCallback } from 'react'; +import type { FC, ReactNode } from 'react'; + +import { defineMessages, FormattedMessage } from 'react-intl'; + +import { showAlert } from '@/mastodon/actions/alerts'; +import { requestBrowserPermission } from '@/mastodon/actions/notifications'; +import { changeAlerts } from '@/mastodon/actions/push_notifications'; +import { changeSetting } from '@/mastodon/actions/settings'; +import { + createAppSelector, + useAppDispatch, + useAppSelector, +} from '@/mastodon/store'; + +import SettingToggle from './setting_toggle'; + +const selectNotificationSettings = createAppSelector( + [ + (state) => + (state.settings as Immutable.Map).get( + 'notifications', + ) as Immutable.Map | boolean>, + (state) => state.notifications.get('browserPermission') as string, + (state) => state.push_notifications, + ], + (settings, browserPermission, pushSettings) => ({ + settings, + browserPermission: browserPermission !== 'denied', + pushSettings, + showPushSettings: + pushSettings.get('supported') && pushSettings.get('enabled'), + }), +); + +const messages = defineMessages({ + permissionDenied: { + id: 'notifications.permission_denied_alert', + defaultMessage: + "Desktop notifications can't be enabled, as browser permission has been denied before", + }, +}); + +type SettingsType = 'alerts' | 'shows' | 'sounds'; + +export const ColumnSettingsGroup: FC<{ label: ReactNode; type: string }> = ({ + label, + type, +}) => { + const { settings, browserPermission, pushSettings, showPushSettings } = + useAppSelector(selectNotificationSettings); + + const dispatch = useAppDispatch(); + const handleChange = useCallback( + (path: [SettingsType, string], checked: boolean) => { + if ( + path[0] === 'alerts' && + checked && + typeof window.Notification !== 'undefined' && + Notification.permission !== 'granted' + ) { + dispatch( + requestBrowserPermission((permission) => { + if (permission === 'granted') { + dispatch(changeSetting(['notifications', ...path], checked)); + } else { + dispatch(showAlert({ message: messages.permissionDenied })); + } + }), + ); + } else { + dispatch(changeSetting(['notifications', ...path], checked)); + } + }, + [dispatch], + ); + const handlePushChange = useCallback( + (path: string[], checked: boolean) => { + if ( + checked && + typeof window.Notification !== 'undefined' && + Notification.permission !== 'granted' + ) { + dispatch( + requestBrowserPermission((permission: NotificationPermission) => { + if (permission === 'granted') { + dispatch(changeAlerts(path, checked)); + } else { + dispatch(showAlert({ message: messages.permissionDenied })); + } + }), + ); + } else { + dispatch(changeAlerts(path, checked)); + } + }, + [dispatch], + ); + + return ( +
    +

    {label}

    + +
    + + } + /> + + {showPushSettings && ( + + } + /> + )} + + + } + /> + + + } + /> +
    +
    + ); +}; diff --git a/app/javascript/mastodon/features/notifications_v2/filter_bar.tsx b/app/javascript/mastodon/features/notifications_v2/filter_bar.tsx index 56067afa932..f9552761829 100644 --- a/app/javascript/mastodon/features/notifications_v2/filter_bar.tsx +++ b/app/javascript/mastodon/features/notifications_v2/filter_bar.tsx @@ -3,6 +3,7 @@ import { useCallback } from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; +import CollectionsIcon from '@/material-icons/400-24px/category.svg?react'; import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react'; import InsertChartIcon from '@/material-icons/400-24px/insert_chart.svg?react'; import PersonAddIcon from '@/material-icons/400-24px/person_add.svg?react'; @@ -26,6 +27,10 @@ const tooltips = defineMessages({ boosts: { id: 'notifications.filter.boosts', defaultMessage: 'Boosts' }, polls: { id: 'notifications.filter.polls', defaultMessage: 'Poll results' }, follows: { id: 'notifications.filter.follows', defaultMessage: 'Follows' }, + collections: { + id: 'notifications.filter.collections', + defaultMessage: 'Collections', + }, statuses: { id: 'notifications.filter.statuses', defaultMessage: 'Updates from people you follow', @@ -124,6 +129,14 @@ export const FilterBar: React.FC = () => { > + + + ); else diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index b97260173b8..f111e436b82 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -1000,6 +1000,7 @@ "notifications.column_settings.admin.report": "New reports:", "notifications.column_settings.admin.sign_up": "New sign-ups:", "notifications.column_settings.alert": "Desktop notifications", + "notifications.column_settings.collections": "Collections:", "notifications.column_settings.favourite": "Favorites:", "notifications.column_settings.filter_bar.advanced": "Display all categories", "notifications.column_settings.filter_bar.category": "Quick filter bar", @@ -1019,6 +1020,7 @@ "notifications.column_settings.update": "Edits:", "notifications.filter.all": "All", "notifications.filter.boosts": "Boosts", + "notifications.filter.collections": "Collections", "notifications.filter.favourites": "Favorites", "notifications.filter.follows": "Follows", "notifications.filter.mentions": "Mentions", diff --git a/app/javascript/mastodon/reducers/settings.js b/app/javascript/mastodon/reducers/settings.js index 775996a48c1..c10d3506002 100644 --- a/app/javascript/mastodon/reducers/settings.js +++ b/app/javascript/mastodon/reducers/settings.js @@ -41,6 +41,7 @@ const initialState = ImmutableMap({ poll: false, status: false, update: false, + collections: false, 'admin.sign_up': false, 'admin.report': false, }), @@ -65,6 +66,7 @@ const initialState = ImmutableMap({ poll: true, status: true, update: true, + collections: true, 'admin.sign_up': true, 'admin.report': true, }), @@ -79,6 +81,7 @@ const initialState = ImmutableMap({ poll: true, status: true, update: true, + collections: true, 'admin.sign_up': true, 'admin.report': true, }), diff --git a/app/javascript/mastodon/selectors/notifications.ts b/app/javascript/mastodon/selectors/notifications.ts index 8c808a2dffe..14111176ac6 100644 --- a/app/javascript/mastodon/selectors/notifications.ts +++ b/app/javascript/mastodon/selectors/notifications.ts @@ -29,7 +29,10 @@ const filterNotificationsByAllowedTypes = ( (item) => item.type === 'gap' || allowedType === item.type || - (allowedType === 'mention' && item.type === 'quote'), + (allowedType === 'mention' && item.type === 'quote') || + (allowedType === 'collection' && + (item.type === 'collection_update' || + item.type === 'added_to_collection')), ); }; diff --git a/app/javascript/mastodon/selectors/settings.ts b/app/javascript/mastodon/selectors/settings.ts index ca343741674..49e0df0c404 100644 --- a/app/javascript/mastodon/selectors/settings.ts +++ b/app/javascript/mastodon/selectors/settings.ts @@ -17,10 +17,19 @@ export const selectSettingsNotificationsShows = createSelector( export const selectSettingsNotificationsExcludedTypes = createSelector( [selectSettingsNotificationsShows], - (shows) => - Object.entries(shows) - .filter(([_type, enabled]) => !enabled) - .map(([type, _enabled]) => type), + (shows) => { + const excludedTypes: string[] = []; + for (const key in shows) { + if (!shows[key]) { + if (key === 'collections') { + excludedTypes.push('collection_update', 'added_to_collection'); + } else { + excludedTypes.push(key); + } + } + } + return excludedTypes; + }, ); export const selectSettingsNotificationsQuickFilterShow = (state: RootState) => From 89a32c36654ab6a05a67b976f526d601885230f6 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 28 May 2026 16:14:12 -0400 Subject: [PATCH 54/70] Update jwt to version 2.10.3 (#39187) --- .bundler-audit.yml | 3 --- Gemfile.lock | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) delete mode 100644 .bundler-audit.yml diff --git a/.bundler-audit.yml b/.bundler-audit.yml deleted file mode 100644 index 4dae946991b..00000000000 --- a/.bundler-audit.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -ignore: - - CVE-2026-45363 diff --git a/Gemfile.lock b/Gemfile.lock index 635d8555697..e7c077a975e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -378,7 +378,7 @@ GEM addressable (~> 2.8) bigdecimal (>= 3.1, < 5) jsonapi-renderer (0.2.2) - jwt (2.10.2) + jwt (2.10.3) base64 kaminari (1.2.2) activesupport (>= 4.1.0) From 8a9ea06dee2d3a7f94e4f4c7094ec3594c83442a Mon Sep 17 00:00:00 2001 From: "Pia B." Date: Thu, 28 May 2026 22:14:31 +0200 Subject: [PATCH 55/70] fixes bug Admin Mailer trends mail not displayed correctly (#39122) --- app/mailers/admin_mailer.rb | 10 ++++-- config/sidekiq.yml | 2 +- spec/mailers/admin_mailer_spec.rb | 55 +++++++++++++++++++++++++++---- 3 files changed, 56 insertions(+), 11 deletions(-) diff --git a/app/mailers/admin_mailer.rb b/app/mailers/admin_mailer.rb index fe2325b6f37..dcf0ef5c7f2 100644 --- a/app/mailers/admin_mailer.rb +++ b/app/mailers/admin_mailer.rb @@ -34,9 +34,13 @@ class AdminMailer < ApplicationMailer end def new_trends(links, tags, statuses) - @links = links - @tags = tags - @statuses = statuses + ActiveRecord::Associations::Preloader.new(records: [*links, *tags, *statuses], associations: [:trend]).call + + @links = links.filter { |link| link.trend.present? } + @tags = tags.filter { |tag| tag.trend.present? } + @statuses = statuses.filter { |status| status.trend.present? } + + return unless @links.any? || @tags.any? || @statuses.any? mail subject: default_i18n_subject(instance: @instance) end diff --git a/config/sidekiq.yml b/config/sidekiq.yml index 5beb95a3f8b..ae30a5c0111 100644 --- a/config/sidekiq.yml +++ b/config/sidekiq.yml @@ -17,7 +17,7 @@ class: Scheduler::ScheduledStatusesScheduler queue: scheduler trends_refresh_scheduler: - every: '5m' + every: ['5m', first_in: '4m'] class: Scheduler::Trends::RefreshScheduler queue: scheduler trends_review_notifications_scheduler: diff --git a/spec/mailers/admin_mailer_spec.rb b/spec/mailers/admin_mailer_spec.rb index e71a8308bfe..34ed2d4dfa5 100644 --- a/spec/mailers/admin_mailer_spec.rb +++ b/spec/mailers/admin_mailer_spec.rb @@ -71,16 +71,22 @@ RSpec.describe AdminMailer do describe '.new_trends' do let(:recipient) { Fabricate(:account, username: 'Snurf') } - let(:link) { Fabricate(:preview_card, trendable: true, language: 'en') } - let(:status) { Fabricate(:status) } - let(:tag) { Fabricate(:tag) } - let(:mail) { described_class.with(recipient: recipient).new_trends([link], [tag], [status]) } + let!(:link) { Fabricate(:preview_card, trendable: true, language: 'en') } + let!(:status) { Fabricate(:status) } + let!(:tag) { Fabricate(:tag, display_name: 'Test Tag') } + let!(:other_tag) { Fabricate(:tag, display_name: 'Test Tag') } + let!(:another_tag) { Fabricate(:tag, display_name: 'Test Tag') } + let(:mail) { described_class.with(recipient: recipient).new_trends([link], [tag, other_tag, another_tag], [status]) } + let(:status_trend) { Fabricate(:status_trend, status: status, account: Fabricate(:account)) } + let(:tag_trend) { Fabricate(:tag_trend, tag: tag) } + let(:other_tag_trend) { Fabricate(:tag_trend, tag: other_tag) } + let(:preview_card_trend) { Fabricate(:preview_card_trend, preview_card: link) } before do - PreviewCardTrend.create!(preview_card: link) - StatusTrend.create!(status: status, account: Fabricate(:account)) - TagTrend.create!(tag: tag) recipient.user.update(locale: :en) + status_trend + tag_trend + preview_card_trend end it 'renders the email' do @@ -96,6 +102,41 @@ RSpec.describe AdminMailer do .and match(link.title) .and match(tag.display_name) end + + context 'when between queueing and sending trends gets deleted' do + let(:queue_mail) { described_class.with(recipient: recipient).new_trends([link], [tag, other_tag], [status]).deliver_later! } + + before do + recipient.user.update(locale: :en) + end + + it 'sends the email when all but one trends were deleted without the respective tag or status or link' do + other_tag_trend + expect(queue_mail.successfully_enqueued?).to be(true) + + TagTrend.delete_all + StatusTrend.delete_all + expect { queue_mail.perform_now }.to send_email( + to: recipient.user_email, + from: 'notifications@localhost', + subject: I18n.t('admin_mailer.new_trends.subject', instance: Rails.configuration.x.local_domain) + ) + expect(mail.body).to have_text(/The following items need a review before they can be displayed publicly/) + .and match(link.title) + expect(mail.body).to_not match(ActivityPub::TagManager.instance.url_for(status)) + expect(mail.body).to_not match(tag.display_name) + end + + it 'returns nil when no trends are present' do + expect(queue_mail.successfully_enqueued?).to be(true) + + TagTrend.delete_all + StatusTrend.delete_all + PreviewCardTrend.delete_all + + expect { queue_mail.perform_now }.to_not send_email + end + end end describe '.new_software_updates' do From 3d84865edb17884fb313db9337b4dc3500e8884d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 20:14:36 +0000 Subject: [PATCH 56/70] Update dependency vite to v8.0.14 (#39121) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 175 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 91 insertions(+), 84 deletions(-) diff --git a/yarn.lock b/yarn.lock index eec215751e8..251cc538c21 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3684,10 +3684,10 @@ __metadata: languageName: node linkType: hard -"@oxc-project/types@npm:=0.130.0, @oxc-project/types@npm:^0.130.0": - version: 0.130.0 - resolution: "@oxc-project/types@npm:0.130.0" - checksum: 10c0/7ec8c03407b0bcb235b930c62859e6efcb3fe5cbaa5db98770d760df5c3e6b3e28a0ad22c2e35d1addede8065b40000c3822c5235dde2959af226639eb870000 +"@oxc-project/types@npm:=0.132.0": + version: 0.132.0 + resolution: "@oxc-project/types@npm:0.132.0" + checksum: 10c0/d0ca5e98be0b873d69e4f0f743eb35026833603dac11db9d55f2b5438251b381b886dc556fe3175a17b673f8e2073c49bde88d7e6e702aa09298c22b8b5504e1 languageName: node linkType: hard @@ -3705,6 +3705,13 @@ __metadata: languageName: node linkType: hard +"@oxc-project/types@npm:^0.130.0": + version: 0.130.0 + resolution: "@oxc-project/types@npm:0.130.0" + checksum: 10c0/7ec8c03407b0bcb235b930c62859e6efcb3fe5cbaa5db98770d760df5c3e6b3e28a0ad22c2e35d1addede8065b40000c3822c5235dde2959af226639eb870000 + languageName: node + linkType: hard + "@oxfmt/binding-android-arm-eabi@npm:0.47.0": version: 0.47.0 resolution: "@oxfmt/binding-android-arm-eabi@npm:0.47.0" @@ -4109,93 +4116,93 @@ __metadata: languageName: node linkType: hard -"@rolldown/binding-android-arm64@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-android-arm64@npm:1.0.1" +"@rolldown/binding-android-arm64@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-android-arm64@npm:1.0.2" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@rolldown/binding-darwin-arm64@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-darwin-arm64@npm:1.0.1" +"@rolldown/binding-darwin-arm64@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-darwin-arm64@npm:1.0.2" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@rolldown/binding-darwin-x64@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-darwin-x64@npm:1.0.1" +"@rolldown/binding-darwin-x64@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-darwin-x64@npm:1.0.2" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@rolldown/binding-freebsd-x64@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-freebsd-x64@npm:1.0.1" +"@rolldown/binding-freebsd-x64@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-freebsd-x64@npm:1.0.2" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@rolldown/binding-linux-arm-gnueabihf@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-linux-arm-gnueabihf@npm:1.0.1" +"@rolldown/binding-linux-arm-gnueabihf@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-linux-arm-gnueabihf@npm:1.0.2" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@rolldown/binding-linux-arm64-gnu@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-linux-arm64-gnu@npm:1.0.1" +"@rolldown/binding-linux-arm64-gnu@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-linux-arm64-gnu@npm:1.0.2" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@rolldown/binding-linux-arm64-musl@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-linux-arm64-musl@npm:1.0.1" +"@rolldown/binding-linux-arm64-musl@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-linux-arm64-musl@npm:1.0.2" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@rolldown/binding-linux-ppc64-gnu@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-linux-ppc64-gnu@npm:1.0.1" +"@rolldown/binding-linux-ppc64-gnu@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-linux-ppc64-gnu@npm:1.0.2" conditions: os=linux & cpu=ppc64 & libc=glibc languageName: node linkType: hard -"@rolldown/binding-linux-s390x-gnu@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-linux-s390x-gnu@npm:1.0.1" +"@rolldown/binding-linux-s390x-gnu@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-linux-s390x-gnu@npm:1.0.2" conditions: os=linux & cpu=s390x & libc=glibc languageName: node linkType: hard -"@rolldown/binding-linux-x64-gnu@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-linux-x64-gnu@npm:1.0.1" +"@rolldown/binding-linux-x64-gnu@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-linux-x64-gnu@npm:1.0.2" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@rolldown/binding-linux-x64-musl@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-linux-x64-musl@npm:1.0.1" +"@rolldown/binding-linux-x64-musl@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-linux-x64-musl@npm:1.0.2" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@rolldown/binding-openharmony-arm64@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-openharmony-arm64@npm:1.0.1" +"@rolldown/binding-openharmony-arm64@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-openharmony-arm64@npm:1.0.2" conditions: os=openharmony & cpu=arm64 languageName: node linkType: hard -"@rolldown/binding-wasm32-wasi@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-wasm32-wasi@npm:1.0.1" +"@rolldown/binding-wasm32-wasi@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-wasm32-wasi@npm:1.0.2" dependencies: "@emnapi/core": "npm:1.10.0" "@emnapi/runtime": "npm:1.10.0" @@ -4204,16 +4211,16 @@ __metadata: languageName: node linkType: hard -"@rolldown/binding-win32-arm64-msvc@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-win32-arm64-msvc@npm:1.0.1" +"@rolldown/binding-win32-arm64-msvc@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-win32-arm64-msvc@npm:1.0.2" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@rolldown/binding-win32-x64-msvc@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-win32-x64-msvc@npm:1.0.1" +"@rolldown/binding-win32-x64-msvc@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-win32-x64-msvc@npm:1.0.2" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -11074,12 +11081,12 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.3.11": - version: 3.3.11 - resolution: "nanoid@npm:3.3.11" +"nanoid@npm:^3.3.12": + version: 3.3.12 + resolution: "nanoid@npm:3.3.12" bin: nanoid: bin/nanoid.cjs - checksum: 10c0/40e7f70b3d15f725ca072dfc4f74e81fcf1fbb02e491cf58ac0c79093adc9b0a73b152bcde57df4b79cd097e13023d7504acb38404a4da7bc1cd8e887b82fe0b + checksum: 10c0/ba142b7b39e11e80c16dd74b0365d407880c87c1cf7e1480956981ae940ee36060fa5b6f092cd1e315184dd19244c657bd017d03327bd3c62247d691c5e8edfb languageName: node linkType: hard @@ -12618,14 +12625,14 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.0.0, postcss@npm:^8.4.35, postcss@npm:^8.5.13, postcss@npm:^8.5.14": - version: 8.5.14 - resolution: "postcss@npm:8.5.14" +"postcss@npm:^8.0.0, postcss@npm:^8.4.35, postcss@npm:^8.5.13, postcss@npm:^8.5.15": + version: 8.5.15 + resolution: "postcss@npm:8.5.15" dependencies: - nanoid: "npm:^3.3.11" + nanoid: "npm:^3.3.12" picocolors: "npm:^1.1.1" source-map-js: "npm:^1.2.1" - checksum: 10c0/48138207cf5ef5581be1bfe2cb65ccfe0ac75e43888ba045afc8ed6043d7b56aeb3b9a9fe5b353ff554be943cd0cc15d826ccb991525159175971e5ee8ab0237 + checksum: 10c0/7f2e63ae22fbe43aace1bf652bd99da4e90737c64194d49e51ddc9cd0f9e51ff2861a7d734379b494deffa03a880a5c65eec70bc29ee9ebaa7136dde3eee8f31 languageName: node linkType: hard @@ -13507,26 +13514,26 @@ __metadata: languageName: node linkType: hard -"rolldown@npm:1.0.1": - version: 1.0.1 - resolution: "rolldown@npm:1.0.1" +"rolldown@npm:1.0.2": + version: 1.0.2 + resolution: "rolldown@npm:1.0.2" dependencies: - "@oxc-project/types": "npm:=0.130.0" - "@rolldown/binding-android-arm64": "npm:1.0.1" - "@rolldown/binding-darwin-arm64": "npm:1.0.1" - "@rolldown/binding-darwin-x64": "npm:1.0.1" - "@rolldown/binding-freebsd-x64": "npm:1.0.1" - "@rolldown/binding-linux-arm-gnueabihf": "npm:1.0.1" - "@rolldown/binding-linux-arm64-gnu": "npm:1.0.1" - "@rolldown/binding-linux-arm64-musl": "npm:1.0.1" - "@rolldown/binding-linux-ppc64-gnu": "npm:1.0.1" - "@rolldown/binding-linux-s390x-gnu": "npm:1.0.1" - "@rolldown/binding-linux-x64-gnu": "npm:1.0.1" - "@rolldown/binding-linux-x64-musl": "npm:1.0.1" - "@rolldown/binding-openharmony-arm64": "npm:1.0.1" - "@rolldown/binding-wasm32-wasi": "npm:1.0.1" - "@rolldown/binding-win32-arm64-msvc": "npm:1.0.1" - "@rolldown/binding-win32-x64-msvc": "npm:1.0.1" + "@oxc-project/types": "npm:=0.132.0" + "@rolldown/binding-android-arm64": "npm:1.0.2" + "@rolldown/binding-darwin-arm64": "npm:1.0.2" + "@rolldown/binding-darwin-x64": "npm:1.0.2" + "@rolldown/binding-freebsd-x64": "npm:1.0.2" + "@rolldown/binding-linux-arm-gnueabihf": "npm:1.0.2" + "@rolldown/binding-linux-arm64-gnu": "npm:1.0.2" + "@rolldown/binding-linux-arm64-musl": "npm:1.0.2" + "@rolldown/binding-linux-ppc64-gnu": "npm:1.0.2" + "@rolldown/binding-linux-s390x-gnu": "npm:1.0.2" + "@rolldown/binding-linux-x64-gnu": "npm:1.0.2" + "@rolldown/binding-linux-x64-musl": "npm:1.0.2" + "@rolldown/binding-openharmony-arm64": "npm:1.0.2" + "@rolldown/binding-wasm32-wasi": "npm:1.0.2" + "@rolldown/binding-win32-arm64-msvc": "npm:1.0.2" + "@rolldown/binding-win32-x64-msvc": "npm:1.0.2" "@rolldown/pluginutils": "npm:^1.0.0" dependenciesMeta: "@rolldown/binding-android-arm64": @@ -13560,8 +13567,8 @@ __metadata: "@rolldown/binding-win32-x64-msvc": optional: true bin: - rolldown: bin/cli.mjs - checksum: 10c0/0631c071874e1471c33923905061fa514fce2bd43c2e741adcddcaa4d9beaa2ba7a5d14af130d53753d838823e15b59f5acef7d24fb83ffb7aef15933b78e7d3 + rolldown: ./bin/cli.mjs + checksum: 10c0/628327a6e3122c0b62880f1c87d54095394e5138a6af2e6e7b2f67ef4c4b11f1421db68c9a5bb4e1be161465a863ab4f68f15076ce895cd4bb3d0ba18a3b20b1 languageName: node linkType: hard @@ -15730,14 +15737,14 @@ __metadata: linkType: hard "vite@npm:^6.0.0 || ^7.0.0 || ^8.0.0, vite@npm:^8.0.0": - version: 8.0.13 - resolution: "vite@npm:8.0.13" + version: 8.0.14 + resolution: "vite@npm:8.0.14" dependencies: fsevents: "npm:~2.3.3" lightningcss: "npm:^1.32.0" picomatch: "npm:^4.0.4" - postcss: "npm:^8.5.14" - rolldown: "npm:1.0.1" + postcss: "npm:^8.5.15" + rolldown: "npm:1.0.2" tinyglobby: "npm:^0.2.16" peerDependencies: "@types/node": ^20.19.0 || >=22.12.0 @@ -15782,7 +15789,7 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: 10c0/8f4d6fd30c3be710f76dba8ee7cd156902200e649884911cfa8e6e5f7ad4dd5b6933bdd4f0c46c0169c49ddce9ce1bfab6d395df9d176c0d959e3ba0e5ee54e4 + checksum: 10c0/1ff99b4daadc64aed5f9e40387ecf39fd3bca45c1a5c4fa4aa82197de901930f0507af8d75c54715e2744c99575913947efb625653a78ef6df3997c5613970bd languageName: node linkType: hard From cf6bf8eae5245cf5f657942c1e6fde7b14790019 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 20:37:32 +0000 Subject: [PATCH 57/70] Update dependency opentelemetry-instrumentation-rack to v0.31.1 (#39139) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index e7c077a975e..693228a4d26 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -539,7 +539,7 @@ GEM opentelemetry-instrumentation-active_support (~> 0.10) opentelemetry-instrumentation-active_support (0.12.0) opentelemetry-instrumentation-base (~> 0.25) - opentelemetry-instrumentation-base (0.26.0) + opentelemetry-instrumentation-base (0.26.1) opentelemetry-api (~> 1.7) opentelemetry-common (~> 0.21) opentelemetry-registry (~> 0.1) @@ -559,7 +559,7 @@ GEM opentelemetry-helpers-sql opentelemetry-helpers-sql-processor opentelemetry-instrumentation-base (~> 0.25) - opentelemetry-instrumentation-rack (0.31.0) + opentelemetry-instrumentation-rack (0.31.1) opentelemetry-instrumentation-base (~> 0.25) opentelemetry-instrumentation-rails (0.42.0) opentelemetry-instrumentation-action_mailer (~> 0.7) From 2dde0179c5cb58b6910797c1083bce1a823b8dee Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 20:37:42 +0000 Subject: [PATCH 58/70] Update dependency sass to v1.100.0 (#39141) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/yarn.lock b/yarn.lock index 251cc538c21..ea4ef7f6eb0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6812,12 +6812,12 @@ __metadata: languageName: node linkType: hard -"chokidar@npm:^4.0.0": - version: 4.0.0 - resolution: "chokidar@npm:4.0.0" +"chokidar@npm:^5.0.0": + version: 5.0.0 + resolution: "chokidar@npm:5.0.0" dependencies: - readdirp: "npm:^4.0.1" - checksum: 10c0/42d03c53b0ad200689e4fae7763133561480561cab8ba5304e8f2298ff45ff84bf0f6065c3f02b9e557b74b156813734439a1a2ff19a1ea6b35692395cd92738 + readdirp: "npm:^5.0.0" + checksum: 10c0/42fc907cb2a7ff5c9e220f84dae75380a77997f851c2a5e7865a2cf9ae45dd407a23557208cdcdbf3ac8c93341135a1748e4c48c31855f3bfa095e5159b6bdec languageName: node linkType: hard @@ -13173,10 +13173,10 @@ __metadata: languageName: node linkType: hard -"readdirp@npm:^4.0.1": - version: 4.0.1 - resolution: "readdirp@npm:4.0.1" - checksum: 10c0/e5a0b547015f68ecc918f115b62b75b2b840611480a9240cb3317090a0ddac01bb9b40315a8fa08acdf52a43eea17b808c89b645263cba3ab64dc557d7f801f1 +"readdirp@npm:^5.0.0": + version: 5.0.0 + resolution: "readdirp@npm:5.0.0" + checksum: 10c0/faf1ec57cff2020f473128da3f8d2a57813cc3a08a36c38cae1c9af32c1579906cc50ba75578043b35bade77e945c098233665797cf9730ba3613a62d6e79219 languageName: node linkType: hard @@ -13781,11 +13781,11 @@ __metadata: linkType: hard "sass@npm:^1.62.1, sass@npm:^1.70.0": - version: 1.99.0 - resolution: "sass@npm:1.99.0" + version: 1.100.0 + resolution: "sass@npm:1.100.0" dependencies: "@parcel/watcher": "npm:^2.4.1" - chokidar: "npm:^4.0.0" + chokidar: "npm:^5.0.0" immutable: "npm:^5.1.5" source-map-js: "npm:>=0.6.2 <2.0.0" dependenciesMeta: @@ -13793,7 +13793,7 @@ __metadata: optional: true bin: sass: sass.js - checksum: 10c0/83c54a8c6decb79fff50dd9500d7932cf1cb7c5d9be4bc42bd3d537402c37bbee062aea6efdbdf9fb0b8697b18177d60c72bf101872336b93b1c27a2dc3621e1 + checksum: 10c0/e2aab47c87b69d2d4f8e48fa665138548069f56a7fd0fc4e15c9bde888b715798e49d33436e873918a8849ca3cc6c141a68618f58e2f3b2e6ec179cc309ca622 languageName: node linkType: hard From fd92d33d712b73721e8bc198e4e47d6286e120de Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 22:38:03 +0200 Subject: [PATCH 59/70] Update dependency react-redux to v9.3.0 (#39045) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index ea4ef7f6eb0..a7c35f775a9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13018,8 +13018,8 @@ __metadata: linkType: hard "react-redux@npm:^9.0.4": - version: 9.2.0 - resolution: "react-redux@npm:9.2.0" + version: 9.3.0 + resolution: "react-redux@npm:9.3.0" dependencies: "@types/use-sync-external-store": "npm:^0.0.6" use-sync-external-store: "npm:^1.4.0" @@ -13032,7 +13032,7 @@ __metadata: optional: true redux: optional: true - checksum: 10c0/00d485f9d9219ca1507b4d30dde5f6ff8fb68ba642458f742e0ec83af052f89e65cd668249b99299e1053cc6ad3d2d8ac6cb89e2f70d2ac5585ae0d7fa0ef259 + checksum: 10c0/b9f4efcfbfbc90cac9d1709ab3affb1e18a9dc9bd3cceda43bd2e1d9d2394ee0c29df36ec2202d52b566db774888b594c8c5aa86b64f27ef34fca607c687c9e3 languageName: node linkType: hard From f436be941034206ad68dd6e58389c4fcf328a629 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 29 May 2026 07:30:42 +0000 Subject: [PATCH 60/70] New Crowdin Translations (automated) (#39193) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/be.json | 2 + app/javascript/mastodon/locales/da.json | 2 + app/javascript/mastodon/locales/de.json | 2 + app/javascript/mastodon/locales/el.json | 2 + app/javascript/mastodon/locales/es-AR.json | 2 + app/javascript/mastodon/locales/es-MX.json | 6 +++ app/javascript/mastodon/locales/es.json | 6 +++ app/javascript/mastodon/locales/et.json | 26 +++++++---- app/javascript/mastodon/locales/ga.json | 6 +++ app/javascript/mastodon/locales/gl.json | 2 + app/javascript/mastodon/locales/it.json | 2 + app/javascript/mastodon/locales/nl.json | 2 + app/javascript/mastodon/locales/pt-BR.json | 54 +++++++++++----------- app/javascript/mastodon/locales/vi.json | 2 + app/javascript/mastodon/locales/zh-CN.json | 10 +++- app/javascript/mastodon/locales/zh-TW.json | 2 + config/locales/de.yml | 7 +++ config/locales/es-MX.yml | 11 +++++ config/locales/es.yml | 11 +++++ config/locales/et.yml | 17 +++++-- config/locales/ga.yml | 11 +++++ config/locales/lt.yml | 3 ++ config/locales/simple_form.lt.yml | 3 ++ config/locales/tr.yml | 7 +++ config/locales/zh-CN.yml | 11 +++++ 25 files changed, 170 insertions(+), 39 deletions(-) diff --git a/app/javascript/mastodon/locales/be.json b/app/javascript/mastodon/locales/be.json index 1fff2a1fc7a..dc2733bde7c 100644 --- a/app/javascript/mastodon/locales/be.json +++ b/app/javascript/mastodon/locales/be.json @@ -1000,6 +1000,7 @@ "notifications.column_settings.admin.report": "Новыя скаргі:", "notifications.column_settings.admin.sign_up": "Новыя рэгістрацыі:", "notifications.column_settings.alert": "Апавяшчэнні на працоўным стале", + "notifications.column_settings.collections": "Калекцыі:", "notifications.column_settings.favourite": "Упадабанае:", "notifications.column_settings.filter_bar.advanced": "Паказаць усе катэгорыі", "notifications.column_settings.filter_bar.category": "Панэль хуткай фільтрацыі", @@ -1019,6 +1020,7 @@ "notifications.column_settings.update": "Праўкі:", "notifications.filter.all": "Усе", "notifications.filter.boosts": "Пашырэнні", + "notifications.filter.collections": "Калекцыі", "notifications.filter.favourites": "Упадабанае", "notifications.filter.follows": "Падпісаны на", "notifications.filter.mentions": "Згадванні", diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json index c9e86a3ae36..0b3604ef684 100644 --- a/app/javascript/mastodon/locales/da.json +++ b/app/javascript/mastodon/locales/da.json @@ -1000,6 +1000,7 @@ "notifications.column_settings.admin.report": "Nye rapporteringer:", "notifications.column_settings.admin.sign_up": "Nye tilmeldinger:", "notifications.column_settings.alert": "Computernotifikationer", + "notifications.column_settings.collections": "Samlinger:", "notifications.column_settings.favourite": "Favoritter:", "notifications.column_settings.filter_bar.advanced": "Vis alle kategorier", "notifications.column_settings.filter_bar.category": "Hurtigfiltreringsbjælke", @@ -1019,6 +1020,7 @@ "notifications.column_settings.update": "Redigeringer:", "notifications.filter.all": "Alle", "notifications.filter.boosts": "Fremhævelser", + "notifications.filter.collections": "Samlinger", "notifications.filter.favourites": "Favoritter", "notifications.filter.follows": "Følger", "notifications.filter.mentions": "Omtaler", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index 76767a271ed..1637ae9df3c 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -1000,6 +1000,7 @@ "notifications.column_settings.admin.report": "Neue Meldungen:", "notifications.column_settings.admin.sign_up": "Neue Registrierungen:", "notifications.column_settings.alert": "Desktop-Benachrichtigungen", + "notifications.column_settings.collections": "Sammlungen:", "notifications.column_settings.favourite": "Favoriten:", "notifications.column_settings.filter_bar.advanced": "Alle Filterkategorien anzeigen", "notifications.column_settings.filter_bar.category": "Filterleiste", @@ -1019,6 +1020,7 @@ "notifications.column_settings.update": "Überarbeitete Beiträge:", "notifications.filter.all": "Alles", "notifications.filter.boosts": "Geteilte Beiträge", + "notifications.filter.collections": "Sammlungen", "notifications.filter.favourites": "Favoriten", "notifications.filter.follows": "Neue Follower", "notifications.filter.mentions": "Erwähnungen", diff --git a/app/javascript/mastodon/locales/el.json b/app/javascript/mastodon/locales/el.json index 745e23c335a..aac2f5b6d03 100644 --- a/app/javascript/mastodon/locales/el.json +++ b/app/javascript/mastodon/locales/el.json @@ -1000,6 +1000,7 @@ "notifications.column_settings.admin.report": "Νέες αναφορές:", "notifications.column_settings.admin.sign_up": "Νέες εγγραφές:", "notifications.column_settings.alert": "Ειδοποιήσεις για υπολογιστή", + "notifications.column_settings.collections": "Συλλογές:", "notifications.column_settings.favourite": "Αγαπημένα:", "notifications.column_settings.filter_bar.advanced": "Εμφάνιση όλων των κατηγοριών", "notifications.column_settings.filter_bar.category": "Μπάρα γρήγορου φίλτρου", @@ -1019,6 +1020,7 @@ "notifications.column_settings.update": "Επεξεργασίες:", "notifications.filter.all": "Όλες", "notifications.filter.boosts": "Προωθήσεις", + "notifications.filter.collections": "Συλλογές", "notifications.filter.favourites": "Αγαπημένα", "notifications.filter.follows": "Ακολουθείς", "notifications.filter.mentions": "Επισημάνσεις", diff --git a/app/javascript/mastodon/locales/es-AR.json b/app/javascript/mastodon/locales/es-AR.json index 4cf1086871e..a3de4c997bb 100644 --- a/app/javascript/mastodon/locales/es-AR.json +++ b/app/javascript/mastodon/locales/es-AR.json @@ -1000,6 +1000,7 @@ "notifications.column_settings.admin.report": "Nuevas denuncias:", "notifications.column_settings.admin.sign_up": "Nuevos registros:", "notifications.column_settings.alert": "Notificaciones de escritorio", + "notifications.column_settings.collections": "Colecciones:", "notifications.column_settings.favourite": "Favoritos:", "notifications.column_settings.filter_bar.advanced": "Mostrar todas las categorías", "notifications.column_settings.filter_bar.category": "Barra de filtrado rápido", @@ -1019,6 +1020,7 @@ "notifications.column_settings.update": "Ediciones:", "notifications.filter.all": "Todas", "notifications.filter.boosts": "Adhesiones", + "notifications.filter.collections": "Colecciones", "notifications.filter.favourites": "Favoritos", "notifications.filter.follows": "Seguidores", "notifications.filter.mentions": "Menciones", diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json index 2d9d8493d60..e8b8e2deec4 100644 --- a/app/javascript/mastodon/locales/es-MX.json +++ b/app/javascript/mastodon/locales/es-MX.json @@ -584,6 +584,12 @@ "copy_icon_button.copy_this_text": "Copiar enlace al portapapeles", "copypaste.copied": "Copiado", "copypaste.copy_to_clipboard": "Copiar al portapapeles", + "custom_homepage.about": "Acerca de", + "custom_homepage.about_this_server": "Acerca de este servidor", + "custom_homepage.administered_by": "Administrado por", + "custom_homepage.contact": "Contacto:", + "custom_homepage.latest_activity": "Actividad más reciente", + "custom_homepage.these_are_the_latest_posts": "Estas son las últimas 40 publicaciones de las cuentas de este servidor.", "directory.federated": "Desde el fediverso conocido", "directory.local": "Sólo de {domain}", "directory.new_arrivals": "Recién llegados", diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json index e685ccf1c81..50142cb2fde 100644 --- a/app/javascript/mastodon/locales/es.json +++ b/app/javascript/mastodon/locales/es.json @@ -584,6 +584,12 @@ "copy_icon_button.copy_this_text": "Copiar enlace al portapapeles", "copypaste.copied": "Copiado", "copypaste.copy_to_clipboard": "Copiar al portapapeles", + "custom_homepage.about": "Acerca de", + "custom_homepage.about_this_server": "Acerca de este servidor", + "custom_homepage.administered_by": "Administrado por", + "custom_homepage.contact": "Contacto:", + "custom_homepage.latest_activity": "Actividad más reciente", + "custom_homepage.these_are_the_latest_posts": "Estas son las últimas 40 publicaciones de las cuentas de este servidor.", "directory.federated": "Desde el fediverso conocido", "directory.local": "Solo desde {domain}", "directory.new_arrivals": "Recién llegados", diff --git a/app/javascript/mastodon/locales/et.json b/app/javascript/mastodon/locales/et.json index 959cdcba599..c545e3a2b59 100644 --- a/app/javascript/mastodon/locales/et.json +++ b/app/javascript/mastodon/locales/et.json @@ -584,6 +584,12 @@ "copy_icon_button.copy_this_text": "Kopeeri link lõikelauale", "copypaste.copied": "Kopeeritud", "copypaste.copy_to_clipboard": "Kopeeri vahemällu", + "custom_homepage.about": "Teave", + "custom_homepage.about_this_server": "Teave koduserveri kohta", + "custom_homepage.administered_by": "Seda haldab", + "custom_homepage.contact": "Kontakt:", + "custom_homepage.latest_activity": "Viimane tegevus", + "custom_homepage.these_are_the_latest_posts": "Need on selle serveri kasutajate viimased 40 postitust.", "directory.federated": "Tuntud födiversumist", "directory.local": "Ainult domeenilt {domain}", "directory.new_arrivals": "Uustulijad", @@ -775,17 +781,17 @@ "home.pending_critical_update.link": "Vaata uuendusi", "home.pending_critical_update.title": "Saadaval kriitiline turvauuendus!", "home.show_announcements": "Kuva teadaandeid", - "ignore_notifications_modal.disclaimer": "Mastodon ei saa teavitada kasutajaid, et ignoreerisid nende teavitusi. Teavituste ignoreerimine ei peata sõnumite endi saatmist.", + "ignore_notifications_modal.disclaimer": "Mastodon ei saa teavitada kasutajaid, et eirasid nende teavitusi. Teavituste eiramine ei peata sõnumite endi saatmist.", "ignore_notifications_modal.filter_instead": "Selle asemel filtreeri", "ignore_notifications_modal.filter_to_act_users": "Saad endiselt kasutajaid vastu võtta, tagasi lükata või neist teatada", "ignore_notifications_modal.filter_to_avoid_confusion": "Filtreerimine aitab vältida võimalikke segaminiajamisi", "ignore_notifications_modal.filter_to_review_separately": "Saad filtreeritud teateid eraldi vaadata", "ignore_notifications_modal.ignore": "Ignoreeri teavitusi", - "ignore_notifications_modal.limited_accounts_title": "Ignoreeri modereeritud kontode teavitusi?", - "ignore_notifications_modal.new_accounts_title": "Ignoreeri uute kontode teavitusi?", - "ignore_notifications_modal.not_followers_title": "Ignoreeri inimeste teavitusi, kes sind ei jälgi?", - "ignore_notifications_modal.not_following_title": "Ignoreeri inimeste teavitusi, keda sa ei jälgi?", - "ignore_notifications_modal.private_mentions_title": "Ignoreeri soovimatute eraviisiliste mainimiste teateid?", + "ignore_notifications_modal.limited_accounts_title": "Kas eirad modereeritud kontode teavitusi?", + "ignore_notifications_modal.new_accounts_title": "Kas eirad uute kontode teavitusi?", + "ignore_notifications_modal.not_followers_title": "Kas eirad teavitusi kasutajatelt, kes sind ei jälgi?", + "ignore_notifications_modal.not_following_title": "Kas eirad teavitusi kasutajatelt, keda sa ei jälgi?", + "ignore_notifications_modal.private_mentions_title": "Kas eirad soovimatute eraviisiliste mainimiste teavitusi?", "info_button.label": "Abi", "info_button.what_is_alt_text": "

    Mis on alt-tekst?

    Alt-tekst pakub pildi kirjeldust nägemispuudega inimeste jaoks või neile, kel on aeglane internet või neile, kes otsivad lisaselgitust

    Saad parandada ligipääsetavust ja mõistmist kõigi jaoks, kirjutades selge, lühida ja objektiivse alt-teksti.

    • Lisa tähtsad elemendid
    • Tee pildil olevast tekstist kokkuvõte
    • Kasuta reeglipärast lausestruktuuri
    • Väldi ebaolulist infot
    • Keskendu keerukate vaadete puhul (näiteks diagrammid ja kaardid) puhul trendidele ja põhiseostele
    ", "interaction_modal.action": "Suhestumaks kasutaja {name} postitusega palun logi sisse oma Mastodoni kasutajakontoga sõltumata serverist, mida kasutad.", @@ -879,7 +885,7 @@ "loading_indicator.label": "Laadimine…", "media_gallery.hide": "Peida", "moved_to_account_banner.text": "Kontot {disabledAccount} ei ole praegu võimalik kasutada, sest kolisid kontole {movedToAccount}.", - "mute_modal.hide_from_notifications": "Peida teavituste hulgast", + "mute_modal.hide_from_notifications": "Peida teavituste seast", "mute_modal.hide_options": "Peida valikud", "mute_modal.indefinite": "Kuni eemaldan neilt summutamise", "mute_modal.show_options": "Kuva valikud", @@ -908,6 +914,7 @@ "navigation_bar.live_feed_local": "Ajajoon reaalajas (sinu server)", "navigation_bar.live_feed_public": "Ajajoon reaalajas (Födiversum)", "navigation_bar.logout": "Logi välja", + "navigation_bar.main": "Esileht", "navigation_bar.moderation": "Modereerimine", "navigation_bar.more": "Lisavalikud", "navigation_bar.mutes": "Summutatud kasutajad", @@ -980,8 +987,8 @@ "notification_requests.dismiss_multiple": "{count, plural, one {Loobuda # taotlusest…} other {Loobuda # taotlusest…}}", "notification_requests.edit_selection": "Muuda", "notification_requests.exit_selection": "Valmis", - "notification_requests.explainer_for_limited_account": "Sellelt kontolt tulevad teavitused on filtreeritud, sest moderaator on seda kontot piiranud.", - "notification_requests.explainer_for_limited_remote_account": "Sellelt kontolt tulevad teavitused on filtreeritud, sest moderaator on seda kontot või serverit piiranud.", + "notification_requests.explainer_for_limited_account": "Selle kasutajakontoga seotud teavitused on filtreeritud, sest moderaator on selle konto tegevust piiranud.", + "notification_requests.explainer_for_limited_remote_account": "Selle kasutajakontoga seotud teavitused on filtreeritud, sest moderaator on selle konto tegevust või suhtlust andtu koduserveriga piiranud.", "notification_requests.maximize": "Maksimeeri", "notification_requests.minimize_banner": "Minimeeri filtreeritud teavituste bänner", "notification_requests.notifications_from": "Teavitus kasutajalt {name}", @@ -1305,6 +1312,7 @@ "tabs_bar.menu": "Menüü", "tabs_bar.notifications": "Teated", "tabs_bar.publish": "Uus postitus", + "tabs_bar.quick_links": "Kiirlingid", "tabs_bar.search": "Otsing", "tag.remove": "Eemalda", "terms_of_service.effective_as_of": "Kehtib alates {date}", diff --git a/app/javascript/mastodon/locales/ga.json b/app/javascript/mastodon/locales/ga.json index ae4ec98b68b..a4f3b08f3cc 100644 --- a/app/javascript/mastodon/locales/ga.json +++ b/app/javascript/mastodon/locales/ga.json @@ -584,6 +584,12 @@ "copy_icon_button.copy_this_text": "Cóipeáil nasc chuig an ghearrthaisce", "copypaste.copied": "Cóipeáilte", "copypaste.copy_to_clipboard": "Cóipeáil chuig an ngearrthaisce", + "custom_homepage.about": "Maidir", + "custom_homepage.about_this_server": "Maidir leis an bhfreastalaí seo", + "custom_homepage.administered_by": "Arna riar ag", + "custom_homepage.contact": "Déan teagmháil le:", + "custom_homepage.latest_activity": "An ghníomhaíocht is déanaí", + "custom_homepage.these_are_the_latest_posts": "Seo iad na 40 postáil is déanaí ó chuntais ar an bhfreastalaí seo.", "directory.federated": "Ó chomhchruinne aitheanta", "directory.local": "Ó {domain} amháin", "directory.new_arrivals": "Daoine atá tar éis teacht", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 9cbf31fe1f1..ec102c2b68c 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -1000,6 +1000,7 @@ "notifications.column_settings.admin.report": "Novas denuncias:", "notifications.column_settings.admin.sign_up": "Novas usuarias:", "notifications.column_settings.alert": "Notificacións de escritorio", + "notifications.column_settings.collections": "Coleccións:", "notifications.column_settings.favourite": "Favoritas:", "notifications.column_settings.filter_bar.advanced": "Mostrar todas as categorías", "notifications.column_settings.filter_bar.category": "Barra de filtrado rápido", @@ -1019,6 +1020,7 @@ "notifications.column_settings.update": "Edicións:", "notifications.filter.all": "Todo", "notifications.filter.boosts": "Compartidos", + "notifications.filter.collections": "Coleccións", "notifications.filter.favourites": "Favoritas", "notifications.filter.follows": "Seguimentos", "notifications.filter.mentions": "Mencións", diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json index 080e25da4e8..e723f68c122 100644 --- a/app/javascript/mastodon/locales/it.json +++ b/app/javascript/mastodon/locales/it.json @@ -1000,6 +1000,7 @@ "notifications.column_settings.admin.report": "Nuove segnalazioni:", "notifications.column_settings.admin.sign_up": "Nuove iscrizioni:", "notifications.column_settings.alert": "Notifiche desktop", + "notifications.column_settings.collections": "Collezioni:", "notifications.column_settings.favourite": "Preferiti:", "notifications.column_settings.filter_bar.advanced": "Mostra tutte le categorie", "notifications.column_settings.filter_bar.category": "Barra del filtro veloce", @@ -1019,6 +1020,7 @@ "notifications.column_settings.update": "Modifiche:", "notifications.filter.all": "Tutti", "notifications.filter.boosts": "Condivisioni", + "notifications.filter.collections": "Collezioni", "notifications.filter.favourites": "Preferiti", "notifications.filter.follows": "Seguaci", "notifications.filter.mentions": "Menzioni", diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index e298d758424..696b927044f 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -1000,6 +1000,7 @@ "notifications.column_settings.admin.report": "Nieuwe rapportages:", "notifications.column_settings.admin.sign_up": "Nieuwe registraties:", "notifications.column_settings.alert": "Desktopmeldingen", + "notifications.column_settings.collections": "Verzamelingen:", "notifications.column_settings.favourite": "Favorieten:", "notifications.column_settings.filter_bar.advanced": "Alle categorieën tonen", "notifications.column_settings.filter_bar.category": "Snelle filterbalk", @@ -1019,6 +1020,7 @@ "notifications.column_settings.update": "Bewerkingen:", "notifications.filter.all": "Alles", "notifications.filter.boosts": "Boosts", + "notifications.filter.collections": "Verzamelingen", "notifications.filter.favourites": "Favorieten", "notifications.filter.follows": "Nieuwe volgers", "notifications.filter.mentions": "Vermeldingen", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index 778740e2749..51dc45c3406 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -715,22 +715,22 @@ "follow_suggestions.curated_suggestion": "Escolha da equipe", "follow_suggestions.dismiss": "Não mostrar novamente", "follow_suggestions.featured_longer": "Escolhido à mão pela equipe de {domain}", - "follow_suggestions.friends_of_friends_longer": "Popular entre as pessoas que você segue", - "follow_suggestions.hints.featured": "Este perfil foi escolhido a dedo pela equipe {domain}.", - "follow_suggestions.hints.friends_of_friends": "Este perfil é popular entre as pessoas que você segue.", + "follow_suggestions.friends_of_friends_longer": "Em alta entre as pessoas que você segue", + "follow_suggestions.hints.featured": "Este perfil foi escolhido à mão pela equipe de {domain}.", + "follow_suggestions.hints.friends_of_friends": "Este perfil está em alta entre as pessoas que você segue.", "follow_suggestions.hints.most_followed": "Este perfil é um dos mais seguidos em {domain}.", - "follow_suggestions.hints.most_interactions": "Este perfil tem recebido recentemente muita atenção em {domain}.", + "follow_suggestions.hints.most_interactions": "Este perfil recentemente ganhou bastante atenção em {domain}.", "follow_suggestions.hints.similar_to_recently_followed": "Este perfil é semelhante aos perfis que você seguiu recentemente.", "follow_suggestions.personalized_suggestion": "Sugestão personalizada", - "follow_suggestions.popular_suggestion": "Sugestão popular", - "follow_suggestions.popular_suggestion_longer": "Popular em {domain}", - "follow_suggestions.similar_to_recently_followed_longer": "Similar a perfis que você seguiu recentemente", - "follow_suggestions.view_all": "Visualizar tudo", + "follow_suggestions.popular_suggestion": "Sugestão em alta", + "follow_suggestions.popular_suggestion_longer": "Em alta em {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "Semelhante aos perfis que você seguiu recentemente", + "follow_suggestions.view_all": "Ver tudo", "follow_suggestions.who_to_follow": "Quem seguir", "followed_tags": "Hashtags seguidas", - "followers.hide_other_followers": "Este usuário escolheu não deixar visíveis seus seguidores", - "followers.title": "Seguinte {name}", - "following.hide_other_following": "Este usuário escolheu não deixar visíveis aqueles a quem segue", + "followers.hide_other_followers": "O usuário decidiu não deixar seus seguidores visíveis", + "followers.title": "Seguindo {name}", + "following.hide_other_following": "O usuário decidiu não deixar quem eles seguem visível", "following.title": "Seguido por {name}", "footer.about": "Sobre", "footer.about_mastodon": "Sobre o Mastodon", @@ -740,13 +740,13 @@ "footer.get_app": "Baixe o app", "footer.keyboard_shortcuts": "Atalhos de teclado", "footer.privacy_policy": "Política de privacidade", - "footer.source_code": "Exibir código-fonte", + "footer.source_code": "Ver código-fonte", "footer.status": "Status", "footer.terms_of_service": "Termos de serviço", - "form_error.blank": "O espaço não pode estar em branco.", + "form_error.blank": "O campo não pode estar vazio.", "form_field.optional": "(opcional)", "getting_started.heading": "Primeiros passos", - "hashtag.admin_moderation": "Abrir interface de moderação para #{name}", + "hashtag.admin_moderation": "Abrir menu de moderação para #{name}", "hashtag.browse": "Buscar publicações em #{hashtag}", "hashtag.browse_from_account": "Buscar publicações de @{name} em #{hashtag}", "hashtag.column_header.tag_mode.all": "e {additional}", @@ -764,27 +764,27 @@ "hashtag.feature": "Destacar no perfil", "hashtag.follow": "Seguir hashtag", "hashtag.mute": "Silenciar #{hashtag}", - "hashtag.unfeature": "Não destacar no perfil", + "hashtag.unfeature": "Remover destaque", "hashtag.unfollow": "Parar de seguir hashtag", - "hashtags.and_other": "…e {count, plural, one {}other {outros #}}", - "hints.profiles.followers_may_be_missing": "Pode haver seguidores deste perfil faltando.", - "hints.profiles.follows_may_be_missing": "Pode haver seguidos por este perfil faltando.", - "hints.profiles.posts_may_be_missing": "É possível que algumas publicações deste perfil estejam faltando.", - "hints.profiles.see_more_followers": "Ver mais seguidores no {domain}", - "hints.profiles.see_more_follows": "Ver mais seguidos no {domain}", + "hashtags.and_other": "…e {count, plural, other {mais #}}", + "hints.profiles.followers_may_be_missing": "Alguns seguidores deste perfil podem estar faltando.", + "hints.profiles.follows_may_be_missing": "Alguns seguidos deste perfil podem estar faltando.", + "hints.profiles.posts_may_be_missing": "Algumas publicações deste perfil podem estar faltando.", + "hints.profiles.see_more_followers": "Ver mais seguidores em {domain}", + "hints.profiles.see_more_follows": "Ver mais perfis seguidos em {domain}", "hints.profiles.see_more_posts": "Ver mais publicações em {domain}", - "home.column_settings.show_quotes": "Mostrar citações", + "home.column_settings.show_quotes": "Exibir citações", "home.column_settings.show_reblogs": "Mostrar impulsos", "home.column_settings.show_replies": "Mostrar respostas", "home.hide_announcements": "Ocultar anúncios", - "home.pending_critical_update.body": "Por favor, atualize o seu servidor Mastodon o mais rápido possível!", + "home.pending_critical_update.body": "Por favor, atualize o servidor do Mastodon o mais rápido possível!", "home.pending_critical_update.link": "Ver atualizações", "home.pending_critical_update.title": "Atualização de segurança crítica disponível!", "home.show_announcements": "Mostrar anúncios", - "ignore_notifications_modal.disclaimer": "O Mastodon não pode informar aos usuários que você ignorou suas notificações. Ignorar notificações não impedirá que as próprias mensagens sejam enviadas.", + "ignore_notifications_modal.disclaimer": "O Mastodon não informa os usuários se você ignorar as notificações deles. Ignorar notificações não impedirá as mensagens de serem enviadas.", "ignore_notifications_modal.filter_instead": "Filtrar em vez disso", - "ignore_notifications_modal.filter_to_act_users": "Você ainda conseguirá aceitar, rejeitar ou denunciar usuários", - "ignore_notifications_modal.filter_to_avoid_confusion": "A filtragem ajuda a evitar confusão potencial", + "ignore_notifications_modal.filter_to_act_users": "Você ainda poderá aceitar, rejeitar ou denunciar", + "ignore_notifications_modal.filter_to_avoid_confusion": "Os filtros ajudam a evitar potenciais confusões", "ignore_notifications_modal.filter_to_review_separately": "Você pode rever notificações filtradas separadamente", "ignore_notifications_modal.ignore": "Ignorar notificações", "ignore_notifications_modal.limited_accounts_title": "Ignorar notificações de contas moderadas?", @@ -1000,6 +1000,7 @@ "notifications.column_settings.admin.report": "Novas denúncias:", "notifications.column_settings.admin.sign_up": "Novas inscrições:", "notifications.column_settings.alert": "Notificações no computador", + "notifications.column_settings.collections": "Coleções:", "notifications.column_settings.favourite": "Favoritos:", "notifications.column_settings.filter_bar.advanced": "Exibir todas as categorias", "notifications.column_settings.filter_bar.category": "Barra de filtro rápido", @@ -1019,6 +1020,7 @@ "notifications.column_settings.update": "Editar:", "notifications.filter.all": "Tudo", "notifications.filter.boosts": "Impulsos", + "notifications.filter.collections": "Coleções", "notifications.filter.favourites": "Favoritos", "notifications.filter.follows": "Seguidores", "notifications.filter.mentions": "Menções", diff --git a/app/javascript/mastodon/locales/vi.json b/app/javascript/mastodon/locales/vi.json index 547ebd7a5f3..ffc2c6edfff 100644 --- a/app/javascript/mastodon/locales/vi.json +++ b/app/javascript/mastodon/locales/vi.json @@ -999,6 +999,7 @@ "notifications.column_settings.admin.report": "Báo cáo mới:", "notifications.column_settings.admin.sign_up": "Người mới tham gia:", "notifications.column_settings.alert": "Báo trên máy tính", + "notifications.column_settings.collections": "Gói khởi đầu:", "notifications.column_settings.favourite": "Lượt thích:", "notifications.column_settings.filter_bar.advanced": "Xếp theo từng loại thông báo", "notifications.column_settings.filter_bar.category": "Phân loại thông báo", @@ -1018,6 +1019,7 @@ "notifications.column_settings.update": "Sửa tút:", "notifications.filter.all": "Tất cả", "notifications.filter.boosts": "Đăng lại", + "notifications.filter.collections": "Gói khởi đầu", "notifications.filter.favourites": "Lượt thích", "notifications.filter.follows": "Người theo dõi mới", "notifications.filter.mentions": "Lượt nhắc đến", diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json index 96f8ffbe95d..7a45db88149 100644 --- a/app/javascript/mastodon/locales/zh-CN.json +++ b/app/javascript/mastodon/locales/zh-CN.json @@ -584,6 +584,12 @@ "copy_icon_button.copy_this_text": "复制链接到剪贴板", "copypaste.copied": "已复制", "copypaste.copy_to_clipboard": "复制到剪贴板", + "custom_homepage.about": "关于", + "custom_homepage.about_this_server": "关于此服务器", + "custom_homepage.administered_by": "管理者为", + "custom_homepage.contact": "联系方式:", + "custom_homepage.latest_activity": "最新动态", + "custom_homepage.these_are_the_latest_posts": "以下是来自此服务器账号的最新 40 条嘟文。", "directory.federated": "来自已知联邦宇宙", "directory.local": "仅来自 {domain}", "directory.new_arrivals": "新来者", @@ -908,7 +914,7 @@ "navigation_bar.live_feed_local": "实时动态(本站)", "navigation_bar.live_feed_public": "实时动态(公开)", "navigation_bar.logout": "退出登录", - "navigation_bar.main": "首页", + "navigation_bar.main": "主要", "navigation_bar.moderation": "审核", "navigation_bar.more": "更多", "navigation_bar.mutes": "已隐藏的用户", @@ -994,6 +1000,7 @@ "notifications.column_settings.admin.report": "新举报:", "notifications.column_settings.admin.sign_up": "新注册:", "notifications.column_settings.alert": "桌面通知", + "notifications.column_settings.collections": "收藏列表:", "notifications.column_settings.favourite": "喜欢:", "notifications.column_settings.filter_bar.advanced": "显示全部类别", "notifications.column_settings.filter_bar.category": "快速筛选栏", @@ -1013,6 +1020,7 @@ "notifications.column_settings.update": "编辑:", "notifications.filter.all": "全部", "notifications.filter.boosts": "转嘟", + "notifications.filter.collections": "收藏列表", "notifications.filter.favourites": "喜欢", "notifications.filter.follows": "关注", "notifications.filter.mentions": "提及", diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index 0793407f650..eecf0c51a61 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -1000,6 +1000,7 @@ "notifications.column_settings.admin.report": "新檢舉報告:", "notifications.column_settings.admin.sign_up": "新註冊帳號:", "notifications.column_settings.alert": "桌面通知", + "notifications.column_settings.collections": "收藏名單:", "notifications.column_settings.favourite": "最愛:", "notifications.column_settings.filter_bar.advanced": "顯示所有分類", "notifications.column_settings.filter_bar.category": "快速過濾器", @@ -1019,6 +1020,7 @@ "notifications.column_settings.update": "編輯:", "notifications.filter.all": "全部", "notifications.filter.boosts": "轉嘟", + "notifications.filter.collections": "收藏名單", "notifications.filter.favourites": "最愛", "notifications.filter.follows": "跟隨的使用者", "notifications.filter.mentions": "提及", diff --git a/config/locales/de.yml b/config/locales/de.yml index 129a42708ec..6ba465395d4 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -956,7 +956,14 @@ de: disabled: Bestimmte Rolle erforderlich public: Alle landing_page: + hints: + about_html: Eine Seite mit der Beschreibung, den Kontaktinformationen, den Regeln und weiteren Informationen zu diesem Server. + local_feed_html: Ein Live-Feed mit den neuesten Beiträgen der Nutzer auf diesem Server. + overview_html: Eine Seite, die die Beschreibung deines Servers zusammen mit den neuesten lokalen Beiträgen der Nutzer zeigt. + trends_html: Eine Seite mit dem, was auf diesem Server gerade im Trend liegt. values: + about: Über-Seite + local_feed: Lokaler Live-Feed overview: Übersicht trends: Trendet registrations: diff --git a/config/locales/es-MX.yml b/config/locales/es-MX.yml index d5b34b78147..358e0e32911 100644 --- a/config/locales/es-MX.yml +++ b/config/locales/es-MX.yml @@ -955,6 +955,17 @@ es-MX: authenticated: Solo usuarios registrados disabled: Requerir un rol de usuario específico public: Todos + landing_page: + hints: + about_html: Una página con la descripción, la información de contacto, las normas y otros datos sobre este servidor. + local_feed_html: Una cronología en tiempo real con las publicaciones más recientes de los usuarios de este servidor. + overview_html: Una página que muestra la descripción de tu servidor junto con las publicaciones locales más recientes de los usuarios de este servidor. + trends_html: Una página que muestra lo que es popular en este servidor en este momento. + values: + about: Página sobre el servidor + local_feed: Cronología local + overview: Resumen + trends: En tendencia registrations: moderation_recommandation: "¡Por favor, asegúrate de contar con un equipo de moderación adecuado y activo antes de abrir el registro al público!" preamble: Controla quién puede crear una cuenta en tu servidor. diff --git a/config/locales/es.yml b/config/locales/es.yml index 44b7d0517ac..2d96e9ce36d 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -955,6 +955,17 @@ es: authenticated: Solo usuarios autenticados disabled: Requerir un rol de usuario específico public: Todos + landing_page: + hints: + about_html: Una página con la descripción, información de contacto, reglas y otra información relevante de este servidor. + local_feed_html: Una cronología con los mensajes más recientes de los usuarios en este servidor. + overview_html: Una página que muestra la descripción de tu servidor junto a las publicaciones locales más recientes de los usuarios en este servidor. + trends_html: Una página destacando lo que es popular en este servidor en este momento. + values: + about: Página sobre el servidor + local_feed: Cronología local + overview: Resumen + trends: En tendencia registrations: moderation_recommandation: Por favor, ¡asegúrate de tener un equipo de moderación adecuado y reactivo antes de abrir los registros a todo el mundo! preamble: Controla quién puede crear una cuenta en tu servidor. diff --git a/config/locales/et.yml b/config/locales/et.yml index 34227ceb483..1120d4db2e1 100644 --- a/config/locales/et.yml +++ b/config/locales/et.yml @@ -279,8 +279,8 @@ et: destroy_unavailable_domain_html: "%{name} taastas edastamise domeeni %{target}" destroy_user_role_html: "%{name} kustutas %{target} rolli" destroy_username_block_html: "%{name} eemaldas kasutajanime reegli, milles sisaldub %{target}" - disable_2fa_user_html: "%{name} eemaldas kasutaja %{target} kahe etapise nõude" - disable_custom_emoji_html: "%{name} keelas emotikooni %{target}" + disable_2fa_user_html: "%{name} eemaldas kasutajalt %{target} kahefaktorilise autentimise nõude" + disable_custom_emoji_html: "%{name} keelas emoji %{target}" disable_relay_html: "%{name} eemaldas sõnumivahendusserveri kasutuselt: %{target}" disable_sign_in_token_auth_user_html: "%{name} keelas e-posti võtme abil autentimise %{target} jaoks" disable_user_html: "%{name} keelas %{target} sisenemise" @@ -295,7 +295,7 @@ et: reject_user_html: "%{name} lükkas %{target} liitumissoovi tagasi" remove_avatar_user_html: "%{name} eemaldas %{target} avatari" reopen_report_html: "%{name} taasavas raporti %{target}" - resend_user_html: "%{name} lähtestas %{target} kinnituskirja e-posti" + resend_user_html: "%{name} saatis kasutajale %{target} e-postiga uue kinnituskirja" reset_password_user_html: "%{name} lähtestas %{target} kasutaja salasõna" resolve_report_html: "%{name} lahendas raporti %{target}" sensitive_account_html: "%{name} märkis %{target} meedia kui tundlik sisu" @@ -955,6 +955,17 @@ et: authenticated: Vaid autenditud kasutajad disabled: Eelda konkreetse kasutajarolli olemasolu public: Kõik + landing_page: + hints: + about_html: Leht kirjeldusega, kontaktiteabega, reeglitega muu olulisega selle koduserveri kohta. + local_feed_html: Sisuvoog viimaste selle serveri kasutajate postitustega. + overview_html: Leht, kus näidatakse selle serveri kirjeldust koos serveri kasutate viimaste postitustega. + trends_html: Leht, mis näitab selles serveris hetkel populaarseid teemasid. + values: + about: Serveri teabe leht + local_feed: Kohalik postituste voog + overview: Ülevaade + trends: Populaarsust koguv registrations: moderation_recommandation: Enne kõigi jaoks registreerimise avamist veendu, et oleks olemas adekvaatne ja reageerimisvalmis modereerijaskond! preamble: Kes saab serveril konto luua. diff --git a/config/locales/ga.yml b/config/locales/ga.yml index e0accf79cf3..ceb92571086 100644 --- a/config/locales/ga.yml +++ b/config/locales/ga.yml @@ -1003,6 +1003,17 @@ ga: authenticated: Úsáideoirí fíordheimhnithe amháin disabled: Éiligh ról úsáideora sonrach public: Gach duine + landing_page: + hints: + about_html: Leathanach leis an gcur síos, eolas teagmhála, rialacha agus faisnéis eile maidir leis an bhfreastalaí seo. + local_feed_html: Fotha beo ina bhfuil na postálacha is déanaí ó úsáideoirí ar an bhfreastalaí seo. + overview_html: Leathanach a thaispeánann cur síos ar do fhreastalaí in éineacht leis na postálacha áitiúla is déanaí ó úsáideoirí ar an bhfreastalaí seo. + trends_html: Leathanach ar a bhfuil an-tóir ar an bhfreastalaí seo faoi láthair. + values: + about: Maidir le leathanach + local_feed: Beatha beo áitiúil + overview: Forbhreathnú + trends: Treocht registrations: moderation_recommandation: Cinntigh le do thoil go bhfuil foireann mhodhnóireachta imoibríoch leordhóthanach agat sula n-osclaíonn tú clárúcháin do gach duine! preamble: Rialú cé atá in ann cuntas a chruthú ar do fhreastalaí. diff --git a/config/locales/lt.yml b/config/locales/lt.yml index 0f08842c908..ea6ccfbd5cb 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -961,6 +961,9 @@ lt: your_appeal_rejected: Tavo apeliacija buvo atmesta edit_profile: other: Kita + email_subscription_mailer: + confirmation: + action: Patvirtinkite el. pašto adresą emoji_styles: auto: Automatinis native: Vietiniai diff --git a/config/locales/simple_form.lt.yml b/config/locales/simple_form.lt.yml index a027191c3f9..4d5b72c7b02 100644 --- a/config/locales/simple_form.lt.yml +++ b/config/locales/simple_form.lt.yml @@ -148,6 +148,7 @@ lt: avatar: Profilio nuotrauka bot: Tai automatinė paskyra chosen_languages: Filtruoti kalbas + confirm_password: Patvirtink slaptažodį display_name: Rodomas vardas email: El. pašto adresas expires_in: Nustoja galioti po @@ -261,7 +262,9 @@ lt: jurisdiction: Teisinis teismingumas min_age: Mažiausias amžius user: + date_of_birth_1i: Metai date_of_birth_2i: Mėnuo + date_of_birth_3i: Diena role: Vaidmuo time_zone: Laiko juosta user_role: diff --git a/config/locales/tr.yml b/config/locales/tr.yml index 7ec25d873e8..81837e5b6ca 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -956,9 +956,16 @@ tr: disabled: Belirli kullanıcı rolü gerekir public: Herkes landing_page: + hints: + about_html: Bu sunucuya ilişkin açıklama, iletişim bilgileri, kurallar ve diğer bilgilerin yer aldığı bir sayfa. + local_feed_html: Bu sunucudaki kullanıcıların en son paylaşımlarını içeren bir canlı akış. + overview_html: Sunucunuzun açıklamasını ve bu sunucudaki kullanıcıların en son yerel gönderilerini gösteren bir sayfa. + trends_html: Bu sunucuda şu anda popüler olanları gösteren bir sayfa. values: about: Hakkında sayfası + local_feed: Yerel canlı akış overview: Genel Bakış + trends: Öne çıkanlar registrations: moderation_recommandation: Lütfen kayıtları herkese açmadan önce yeterli ve duyarlı bir denetleyici ekibine sahip olduğunuzdan emin olun! preamble: Sunucunuzda kimin hesap oluşturabileceğini denetleyin. diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index 8ecfbdc16f3..e768ff4d9b5 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -939,6 +939,17 @@ zh-CN: authenticated: 仅已登录用户 disabled: 需要特定的用户角色 public: 每个人 + landing_page: + hints: + about_html: 关于此服务器的描述、联系信息、规则及其他信息的页面。 + local_feed_html: 展示此服务器用户最新嘟文的实时动态。 + overview_html: 展示你的服务器描述及本站用户最新嘟文的页面。 + trends_html: 展示此服务器当前热门内容的页面。 + values: + about: 关于本站 + local_feed: 本站实时动态 + overview: 概览 + trends: 当前热门 registrations: moderation_recommandation: 在向每个人开放注册之前,请确保你拥有一个人手足够且反应迅速的管理团队! preamble: 控制谁可以在你的服务器上创建账号。 From f89ba969c2b585ca1f9c978b5c338f865f4d95d9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 29 May 2026 10:23:48 +0200 Subject: [PATCH 61/70] Update dependency aws-sdk-core to v3.250.0 (#39204) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 693228a4d26..2a659eb3c21 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -99,8 +99,8 @@ GEM ast (2.4.3) attr_required (1.0.2) aws-eventstream (1.4.0) - aws-partitions (1.1253.0) - aws-sdk-core (3.249.0) + aws-partitions (1.1254.0) + aws-sdk-core (3.250.0) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.992.0) aws-sigv4 (~> 1.9) From 6d3182a6eb2de6998a832669f5a81c31512455ed Mon Sep 17 00:00:00 2001 From: David Roetzel Date: Fri, 29 May 2026 10:39:51 +0200 Subject: [PATCH 62/70] Move Collections API to `v1` namespace (#39210) --- .../collection_items_controller.rb | 2 +- .../collections_controller.rb | 6 ++-- .../in_collections_controller.rb | 6 ++-- config/routes/api.rb | 18 ++++++++++-- lib/mastodon/version.rb | 2 +- .../{v1_alpha => v1}/collection_items_spec.rb | 0 .../api/{v1_alpha => v1}/collections_spec.rb | 28 +++++++++---------- .../{v1_alpha => v1}/in_collections_spec.rb | 12 ++++---- 8 files changed, 44 insertions(+), 30 deletions(-) rename app/controllers/api/{v1_alpha => v1}/collection_items_controller.rb (95%) rename app/controllers/api/{v1_alpha => v1}/collections_controller.rb (90%) rename app/controllers/api/{v1_alpha => v1}/in_collections_controller.rb (79%) rename spec/requests/api/{v1_alpha => v1}/collection_items_spec.rb (100%) rename spec/requests/api/{v1_alpha => v1}/collections_spec.rb (87%) rename spec/requests/api/{v1_alpha => v1}/in_collections_spec.rb (75%) diff --git a/app/controllers/api/v1_alpha/collection_items_controller.rb b/app/controllers/api/v1/collection_items_controller.rb similarity index 95% rename from app/controllers/api/v1_alpha/collection_items_controller.rb rename to app/controllers/api/v1/collection_items_controller.rb index 2c46cc4f9fc..eaa46a44300 100644 --- a/app/controllers/api/v1_alpha/collection_items_controller.rb +++ b/app/controllers/api/v1/collection_items_controller.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class Api::V1Alpha::CollectionItemsController < Api::BaseController +class Api::V1::CollectionItemsController < Api::BaseController include Authorization before_action :check_feature_enabled diff --git a/app/controllers/api/v1_alpha/collections_controller.rb b/app/controllers/api/v1/collections_controller.rb similarity index 90% rename from app/controllers/api/v1_alpha/collections_controller.rb rename to app/controllers/api/v1/collections_controller.rb index 1ca1cd6923f..3c1841237d1 100644 --- a/app/controllers/api/v1_alpha/collections_controller.rb +++ b/app/controllers/api/v1/collections_controller.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class Api::V1Alpha::CollectionsController < Api::BaseController +class Api::V1::CollectionsController < Api::BaseController include Authorization DEFAULT_COLLECTIONS_LIMIT = 40 @@ -98,13 +98,13 @@ class Api::V1Alpha::CollectionsController < Api::BaseController def next_path return unless records_continue? - api_v1_alpha_account_collections_url(@account, pagination_params(offset: offset_param + limit_param(DEFAULT_COLLECTIONS_LIMIT))) + api_v1_account_collections_url(@account, pagination_params(offset: offset_param + limit_param(DEFAULT_COLLECTIONS_LIMIT))) end def prev_path return if offset_param.zero? - api_v1_alpha_account_collections_url(@account, pagination_params(offset: offset_param - limit_param(DEFAULT_COLLECTIONS_LIMIT))) + api_v1_account_collections_url(@account, pagination_params(offset: offset_param - limit_param(DEFAULT_COLLECTIONS_LIMIT))) end def records_continue? diff --git a/app/controllers/api/v1_alpha/in_collections_controller.rb b/app/controllers/api/v1/in_collections_controller.rb similarity index 79% rename from app/controllers/api/v1_alpha/in_collections_controller.rb rename to app/controllers/api/v1/in_collections_controller.rb index 087464989ef..54a1334e3c8 100644 --- a/app/controllers/api/v1_alpha/in_collections_controller.rb +++ b/app/controllers/api/v1/in_collections_controller.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class Api::V1Alpha::InCollectionsController < Api::BaseController +class Api::V1::InCollectionsController < Api::BaseController include Authorization DEFAULT_COLLECTIONS_LIMIT = 40 @@ -44,13 +44,13 @@ class Api::V1Alpha::InCollectionsController < Api::BaseController def next_path return unless records_continue? - api_v1_alpha_account_in_collections_url(@account, pagination_params(offset: offset_param + limit_param(DEFAULT_COLLECTIONS_LIMIT))) + api_v1_account_in_collections_url(@account, pagination_params(offset: offset_param + limit_param(DEFAULT_COLLECTIONS_LIMIT))) end def prev_path return if offset_param.zero? - api_v1_alpha_account_in_collections_url(@account, pagination_params(offset: offset_param - limit_param(DEFAULT_COLLECTIONS_LIMIT))) + api_v1_account_in_collections_url(@account, pagination_params(offset: offset_param - limit_param(DEFAULT_COLLECTIONS_LIMIT))) end def records_continue? diff --git a/config/routes/api.rb b/config/routes/api.rb index 2546b5517a4..a212685eb08 100644 --- a/config/routes/api.rb +++ b/config/routes/api.rb @@ -6,13 +6,16 @@ namespace :api, format: false do # Experimental JSON / REST API namespace :v1_alpha do + resources :async_refreshes, only: :show + end + + # TODO: Remove once apps switch over to v1 + scope :v1_alpha, as: :v1_alpha, module: :v1 do resources :accounts, only: [] do resources :collections, only: [:index] resources :in_collections, only: [:index] end - resources :async_refreshes, only: :show - resources :collections, only: [:show, :create, :update, :destroy] do resources :items, only: [:create, :destroy], controller: 'collection_items' do member do @@ -221,6 +224,9 @@ namespace :api, format: false do resources :email_subscriptions, only: :create end + resources :collections, only: [:index] + resources :in_collections, only: [:index] + member do post :follow post :unfollow @@ -327,6 +333,14 @@ namespace :api, format: false do resources :tags, only: [:index, :show, :update] end + + resources :collections, only: [:show, :create, :update, :destroy] do + resources :items, only: [:create, :destroy], controller: 'collection_items' do + member do + post :revoke + end + end + end end namespace :v2 do diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb index 750c83b718e..6d5353eefc9 100644 --- a/lib/mastodon/version.rb +++ b/lib/mastodon/version.rb @@ -45,7 +45,7 @@ module Mastodon def api_versions { - mastodon: 9, + mastodon: 10, } end diff --git a/spec/requests/api/v1_alpha/collection_items_spec.rb b/spec/requests/api/v1/collection_items_spec.rb similarity index 100% rename from spec/requests/api/v1_alpha/collection_items_spec.rb rename to spec/requests/api/v1/collection_items_spec.rb diff --git a/spec/requests/api/v1_alpha/collections_spec.rb b/spec/requests/api/v1/collections_spec.rb similarity index 87% rename from spec/requests/api/v1_alpha/collections_spec.rb rename to spec/requests/api/v1/collections_spec.rb index f448659bf59..4bf296f2936 100644 --- a/spec/requests/api/v1_alpha/collections_spec.rb +++ b/spec/requests/api/v1/collections_spec.rb @@ -2,12 +2,12 @@ require 'rails_helper' -RSpec.describe 'Api::V1Alpha::Collections', feature: :collections do +RSpec.describe 'Api::V1::Collections', feature: :collections do include_context 'with API authentication', oauth_scopes: 'read:collections write:collections' - describe 'GET /api/v1_alpha/accounts/:account_id/collections' do + describe 'GET /api/v1/accounts/:account_id/collections' do subject do - get "/api/v1_alpha/accounts/#{account.id}/collections", headers: headers, params: params + get "/api/v1/accounts/#{account.id}/collections", headers: headers, params: params end let(:params) { {} } @@ -34,7 +34,7 @@ RSpec.describe 'Api::V1Alpha::Collections', feature: :collections do expect(response) .to include_pagination_headers( - next: api_v1_alpha_account_collections_url(account, limit: 1, offset: 1) + next: api_v1_account_collections_url(account, limit: 1, offset: 1) ) end end @@ -50,8 +50,8 @@ RSpec.describe 'Api::V1Alpha::Collections', feature: :collections do expect(response) .to include_pagination_headers( - prev: api_v1_alpha_account_collections_url(account, limit: 1, offset: 0), - next: api_v1_alpha_account_collections_url(account, limit: 1, offset: 2) + prev: api_v1_account_collections_url(account, limit: 1, offset: 0), + next: api_v1_account_collections_url(account, limit: 1, offset: 2) ) end end @@ -96,9 +96,9 @@ RSpec.describe 'Api::V1Alpha::Collections', feature: :collections do end end - describe 'GET /api/v1_alpha/collections/:id' do + describe 'GET /api/v1/collections/:id' do subject do - get "/api/v1_alpha/collections/#{collection.id}", headers: headers + get "/api/v1/collections/#{collection.id}", headers: headers end let(:collection) { Fabricate(:collection) } @@ -140,9 +140,9 @@ RSpec.describe 'Api::V1Alpha::Collections', feature: :collections do end end - describe 'POST /api/v1_alpha/collections' do + describe 'POST /api/v1/collections' do subject do - post '/api/v1_alpha/collections', headers: headers, params: params + post '/api/v1/collections', headers: headers, params: params end let(:params) { {} } @@ -187,9 +187,9 @@ RSpec.describe 'Api::V1Alpha::Collections', feature: :collections do end end - describe 'PATCH /api/v1_alpha/collections/:id' do + describe 'PATCH /api/v1/collections/:id' do subject do - patch "/api/v1_alpha/collections/#{collection.id}", headers: headers, params: params + patch "/api/v1/collections/#{collection.id}", headers: headers, params: params end let(:collection) { Fabricate(:collection) } @@ -256,9 +256,9 @@ RSpec.describe 'Api::V1Alpha::Collections', feature: :collections do end end - describe 'DELETE /api/v1_alpha/collections/:id' do + describe 'DELETE /api/v1/collections/:id' do subject do - delete "/api/v1_alpha/collections/#{collection.id}", headers: headers + delete "/api/v1/collections/#{collection.id}", headers: headers end let(:collection) { Fabricate(:collection) } diff --git a/spec/requests/api/v1_alpha/in_collections_spec.rb b/spec/requests/api/v1/in_collections_spec.rb similarity index 75% rename from spec/requests/api/v1_alpha/in_collections_spec.rb rename to spec/requests/api/v1/in_collections_spec.rb index a4bd3110bed..3c41feb2e75 100644 --- a/spec/requests/api/v1_alpha/in_collections_spec.rb +++ b/spec/requests/api/v1/in_collections_spec.rb @@ -2,12 +2,12 @@ require 'rails_helper' -RSpec.describe 'Api::V1Alpha::InCollections', feature: :collections do +RSpec.describe 'Api::V1::InCollections', feature: :collections do include_context 'with API authentication', oauth_scopes: 'read:collections write:collections' - describe 'GET /api/v1_alpha/in_collections' do + describe 'GET /api/v1/in_collections' do subject do - get "/api/v1_alpha/accounts/#{account.id}/in_collections", headers: headers, params: params + get "/api/v1/accounts/#{account.id}/in_collections", headers: headers, params: params end let(:params) { {} } @@ -33,7 +33,7 @@ RSpec.describe 'Api::V1Alpha::InCollections', feature: :collections do expect(response) .to include_pagination_headers( - next: api_v1_alpha_account_in_collections_url(account, limit: 1, offset: 1) + next: api_v1_account_in_collections_url(account, limit: 1, offset: 1) ) end end @@ -49,8 +49,8 @@ RSpec.describe 'Api::V1Alpha::InCollections', feature: :collections do expect(response) .to include_pagination_headers( - prev: api_v1_alpha_account_in_collections_url(account, limit: 1, offset: 0), - next: api_v1_alpha_account_in_collections_url(account, limit: 1, offset: 2) + prev: api_v1_account_in_collections_url(account, limit: 1, offset: 0), + next: api_v1_account_in_collections_url(account, limit: 1, offset: 2) ) end end From e2754b0bc2872a17f4cca57c25f0c34b4e60fe33 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Fri, 29 May 2026 05:16:19 -0400 Subject: [PATCH 63/70] Unify `queue_mail` and `mail` in admin mailer new trends spec (#39207) --- spec/mailers/admin_mailer_spec.rb | 43 +++++++++++++++---------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/spec/mailers/admin_mailer_spec.rb b/spec/mailers/admin_mailer_spec.rb index 34ed2d4dfa5..75efe3a4622 100644 --- a/spec/mailers/admin_mailer_spec.rb +++ b/spec/mailers/admin_mailer_spec.rb @@ -74,19 +74,15 @@ RSpec.describe AdminMailer do let!(:link) { Fabricate(:preview_card, trendable: true, language: 'en') } let!(:status) { Fabricate(:status) } let!(:tag) { Fabricate(:tag, display_name: 'Test Tag') } - let!(:other_tag) { Fabricate(:tag, display_name: 'Test Tag') } - let!(:another_tag) { Fabricate(:tag, display_name: 'Test Tag') } - let(:mail) { described_class.with(recipient: recipient).new_trends([link], [tag, other_tag, another_tag], [status]) } - let(:status_trend) { Fabricate(:status_trend, status: status, account: Fabricate(:account)) } - let(:tag_trend) { Fabricate(:tag_trend, tag: tag) } + let!(:other_tag) { Fabricate(:tag, display_name: 'Other Test Tag') } + let(:mail) { described_class.with(recipient: recipient).new_trends([link], [tag, other_tag], [status]) } let(:other_tag_trend) { Fabricate(:tag_trend, tag: other_tag) } - let(:preview_card_trend) { Fabricate(:preview_card_trend, preview_card: link) } before do recipient.user.update(locale: :en) - status_trend - tag_trend - preview_card_trend + Fabricate(:status_trend, status: status, account: Fabricate(:account)) + Fabricate(:tag_trend, tag: tag) + Fabricate(:preview_card_trend, preview_card: link) end it 'renders the email' do @@ -104,37 +100,40 @@ RSpec.describe AdminMailer do end context 'when between queueing and sending trends gets deleted' do - let(:queue_mail) { described_class.with(recipient: recipient).new_trends([link], [tag, other_tag], [status]).deliver_later! } - before do recipient.user.update(locale: :en) end it 'sends the email when all but one trends were deleted without the respective tag or status or link' do other_tag_trend - expect(queue_mail.successfully_enqueued?).to be(true) + expect(mail.deliver_later!) + .to be_successfully_enqueued TagTrend.delete_all StatusTrend.delete_all - expect { queue_mail.perform_now }.to send_email( - to: recipient.user_email, - from: 'notifications@localhost', - subject: I18n.t('admin_mailer.new_trends.subject', instance: Rails.configuration.x.local_domain) - ) - expect(mail.body).to have_text(/The following items need a review before they can be displayed publicly/) + expect { mail.deliver } + .to send_email( + to: recipient.user_email, + from: 'notifications@localhost', + subject: I18n.t('admin_mailer.new_trends.subject', instance: Rails.configuration.x.local_domain) + ) + expect(mail.body) + .to have_text(/The following items need a review before they can be displayed publicly/) .and match(link.title) - expect(mail.body).to_not match(ActivityPub::TagManager.instance.url_for(status)) - expect(mail.body).to_not match(tag.display_name) + .and not_include(ActivityPub::TagManager.instance.url_for(status)) + .and not_include(tag.display_name) end it 'returns nil when no trends are present' do - expect(queue_mail.successfully_enqueued?).to be(true) + expect(mail.deliver_later!) + .to be_successfully_enqueued TagTrend.delete_all StatusTrend.delete_all PreviewCardTrend.delete_all - expect { queue_mail.perform_now }.to_not send_email + expect { mail.deliver } + .to_not send_email end end end From 572612fde9f764297cc6e47c22372c7b1dcba65b Mon Sep 17 00:00:00 2001 From: David Roetzel Date: Fri, 29 May 2026 11:37:42 +0200 Subject: [PATCH 64/70] Remove `collections` feature flag (#39211) --- .../featured_collections_controller.rb | 5 - .../admin/report_notes_controller.rb | 2 + .../api/v1/collection_items_controller.rb | 6 - .../api/v1/collections_controller.rb | 6 - .../api/v1/in_collections_controller.rb | 6 - app/controllers/api/v1/reports_controller.rb | 6 +- app/controllers/api/v1/statuses_controller.rb | 2 +- .../collection_items_controller.rb | 5 - app/controllers/collections_controller.rb | 5 - app/lib/activitypub/activity/accept.rb | 2 +- app/lib/activitypub/activity/add.rb | 4 +- app/lib/activitypub/activity/delete.rb | 2 +- .../activitypub/activity/feature_request.rb | 1 - app/lib/activitypub/activity/update.rb | 2 +- app/lib/status_cache_hydrator.rb | 1 - .../activitypub/actor_serializer.rb | 6 +- app/serializers/rest/account_serializer.rb | 2 +- app/serializers/rest/role_serializer.rb | 2 +- .../activitypub/process_account_service.rb | 4 +- app/services/resolve_url_service.rb | 2 +- app/views/admin/reports/index.html.haml | 7 +- app/views/admin/reports/show.html.haml | 39 +++--- app/views/admin/roles/_form.html.haml | 10 +- spec/lib/activitypub/activity/accept_spec.rb | 2 +- spec/lib/activitypub/activity/add_spec.rb | 4 +- spec/lib/activitypub/activity/delete_spec.rb | 2 +- .../activity/feature_request_spec.rb | 2 +- spec/lib/activitypub/activity/update_spec.rb | 2 +- spec/lib/status_cache_hydrator_spec.rb | 2 +- spec/models/admin/moderation_action_spec.rb | 6 +- .../activitypub/featured_collections_spec.rb | 2 +- spec/requests/admin/reports_spec.rb | 4 +- spec/requests/api/v1/collection_items_spec.rb | 2 +- spec/requests/api/v1/collections_spec.rb | 2 +- spec/requests/api/v1/in_collections_spec.rb | 2 +- spec/requests/api/v1/reports_spec.rb | 2 +- spec/requests/collection_items_spec.rb | 2 +- spec/requests/collections_spec.rb | 4 +- .../activitypub/actor_serializer_spec.rb | 63 ++++----- .../activitypub/flag_serializer_spec.rb | 2 +- .../rest/account_serializer_spec.rb | 121 ++++++++---------- .../rest/account_warning_serializer_spec.rb | 3 +- .../rest/admin/account_serializer_spec.rb | 4 +- .../rest/admin/report_serializer_spec.rb | 2 +- .../rest/report_serializer_spec.rb | 8 +- spec/serializers/rest/role_serializer_spec.rb | 2 +- .../rest/suggestion_serializer_spec.rb | 3 +- .../process_account_service_spec.rb | 13 +- spec/services/resolve_url_service_spec.rb | 4 +- 49 files changed, 166 insertions(+), 226 deletions(-) diff --git a/app/controllers/activitypub/featured_collections_controller.rb b/app/controllers/activitypub/featured_collections_controller.rb index 09de5583cc9..12c0648fae4 100644 --- a/app/controllers/activitypub/featured_collections_controller.rb +++ b/app/controllers/activitypub/featured_collections_controller.rb @@ -9,7 +9,6 @@ class ActivityPub::FeaturedCollectionsController < ApplicationController vary_by -> { public_fetch_mode? ? 'Accept, Accept-Language, Cookie' : 'Accept, Accept-Language, Cookie, Signature' } - before_action :check_feature_enabled before_action :require_account_signature!, if: -> { authorized_fetch_mode? } before_action :set_collections @@ -72,8 +71,4 @@ class ActivityPub::FeaturedCollectionsController < ApplicationController ) end end - - def check_feature_enabled - raise ActionController::RoutingError unless Mastodon::Feature.collections_enabled? - end end diff --git a/app/controllers/admin/report_notes_controller.rb b/app/controllers/admin/report_notes_controller.rb index 10dbe846e4c..03234b0bde4 100644 --- a/app/controllers/admin/report_notes_controller.rb +++ b/app/controllers/admin/report_notes_controller.rb @@ -25,6 +25,8 @@ module Admin @action_logs = @report.history.includes(:target) @form = Admin::StatusBatchAction.new @statuses = @report.statuses.with_includes + @collections = @report.collections + @collection_form = Admin::CollectionBatchAction.new render 'admin/reports/show' end diff --git a/app/controllers/api/v1/collection_items_controller.rb b/app/controllers/api/v1/collection_items_controller.rb index eaa46a44300..3ec5e18ed95 100644 --- a/app/controllers/api/v1/collection_items_controller.rb +++ b/app/controllers/api/v1/collection_items_controller.rb @@ -3,8 +3,6 @@ class Api::V1::CollectionItemsController < Api::BaseController include Authorization - before_action :check_feature_enabled - before_action -> { doorkeeper_authorize! :write, :'write:collections' } before_action :require_user! @@ -55,8 +53,4 @@ class Api::V1::CollectionItemsController < Api::BaseController def set_collection_item @collection_item = @collection.collection_items.find(params[:id]) end - - def check_feature_enabled - raise ActionController::RoutingError unless Mastodon::Feature.collections_enabled? - end end diff --git a/app/controllers/api/v1/collections_controller.rb b/app/controllers/api/v1/collections_controller.rb index 3c1841237d1..9acd535f465 100644 --- a/app/controllers/api/v1/collections_controller.rb +++ b/app/controllers/api/v1/collections_controller.rb @@ -9,8 +9,6 @@ class Api::V1::CollectionsController < Api::BaseController render json: { error: ValidationErrorFormatter.new(e).as_json }, status: 422 end - before_action :check_feature_enabled - before_action -> { authorize_if_got_token! :read, :'read:collections' }, only: [:index, :show] before_action -> { doorkeeper_authorize! :write, :'write:collections' }, only: [:create, :update, :destroy] @@ -91,10 +89,6 @@ class Api::V1::CollectionsController < Api::BaseController params.permit(:name, :description, :language, :sensitive, :discoverable, :tag_name) end - def check_feature_enabled - raise ActionController::RoutingError unless Mastodon::Feature.collections_enabled? - end - def next_path return unless records_continue? diff --git a/app/controllers/api/v1/in_collections_controller.rb b/app/controllers/api/v1/in_collections_controller.rb index 54a1334e3c8..c34845e463e 100644 --- a/app/controllers/api/v1/in_collections_controller.rb +++ b/app/controllers/api/v1/in_collections_controller.rb @@ -5,8 +5,6 @@ class Api::V1::InCollectionsController < Api::BaseController DEFAULT_COLLECTIONS_LIMIT = 40 - before_action :check_feature_enabled - before_action -> { authorize_if_got_token! :read, :'read:collections' }, only: [:index] before_action :require_user! @@ -37,10 +35,6 @@ class Api::V1::InCollectionsController < Api::BaseController .limit(limit_param(DEFAULT_COLLECTIONS_LIMIT)) end - def check_feature_enabled - raise ActionController::RoutingError unless Mastodon::Feature.collections_enabled? - end - def next_path return unless records_continue? diff --git a/app/controllers/api/v1/reports_controller.rb b/app/controllers/api/v1/reports_controller.rb index 8e341aa48e6..a8653631c27 100644 --- a/app/controllers/api/v1/reports_controller.rb +++ b/app/controllers/api/v1/reports_controller.rb @@ -23,10 +23,6 @@ class Api::V1::ReportsController < Api::BaseController end def report_params - if Mastodon::Feature.collections_enabled? - params.permit(:account_id, :comment, :category, :forward, forward_to_domains: [], status_ids: [], collection_ids: [], rule_ids: []) - else - params.permit(:account_id, :comment, :category, :forward, forward_to_domains: [], status_ids: [], rule_ids: []) - end + params.permit(:account_id, :comment, :category, :forward, forward_to_domains: [], status_ids: [], collection_ids: [], rule_ids: []) end end diff --git a/app/controllers/api/v1/statuses_controller.rb b/app/controllers/api/v1/statuses_controller.rb index 78b237357c9..d3f742d62a1 100644 --- a/app/controllers/api/v1/statuses_controller.rb +++ b/app/controllers/api/v1/statuses_controller.rb @@ -170,6 +170,6 @@ class Api::V1::StatusesController < Api::BaseController end def serialized_accounts(accounts) - ActiveModel::Serializer::CollectionSerializer.new(accounts, serializer: REST::AccountSerializer) + ActiveModel::Serializer::CollectionSerializer.new(accounts, serializer: REST::AccountSerializer, scope_name: :current_user, scope: current_user) end end diff --git a/app/controllers/collection_items_controller.rb b/app/controllers/collection_items_controller.rb index 09c1e0e192a..51044b59654 100644 --- a/app/controllers/collection_items_controller.rb +++ b/app/controllers/collection_items_controller.rb @@ -7,7 +7,6 @@ class CollectionItemsController < ApplicationController vary_by -> { public_fetch_mode? ? 'Accept, Accept-Language, Cookie' : 'Accept, Accept-Language, Cookie, Signature' } - before_action :check_feature_enabled before_action :require_account_signature!, if: -> { authorized_fetch_mode? } before_action :set_collection_item @@ -35,8 +34,4 @@ class CollectionItemsController < ApplicationController rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError not_found end - - def check_feature_enabled - raise ActionController::RoutingError unless Mastodon::Feature.collections_enabled? - end end diff --git a/app/controllers/collections_controller.rb b/app/controllers/collections_controller.rb index 70541433f00..628418557c7 100644 --- a/app/controllers/collections_controller.rb +++ b/app/controllers/collections_controller.rb @@ -8,7 +8,6 @@ class CollectionsController < ApplicationController vary_by -> { public_fetch_mode? ? 'Accept, Accept-Language, Cookie' : 'Accept, Accept-Language, Cookie, Signature' } - before_action :check_feature_enabled before_action :require_account_signature!, only: :show, if: -> { request.format == :json && authorized_fetch_mode? } before_action :set_collection @@ -51,8 +50,4 @@ class CollectionsController < ApplicationController recently_updated = @collection.updated_at > 15.minutes.ago recently_updated ? 30.seconds : 5.minutes end - - def check_feature_enabled - raise ActionController::RoutingError unless Mastodon::Feature.collections_enabled? - end end diff --git a/app/lib/activitypub/activity/accept.rb b/app/lib/activitypub/activity/accept.rb index 4dc6977b8ef..a76b79a6d87 100644 --- a/app/lib/activitypub/activity/accept.rb +++ b/app/lib/activitypub/activity/accept.rb @@ -5,7 +5,7 @@ class ActivityPub::Activity::Accept < ActivityPub::Activity return accept_follow_for_relay if relay_follow? return accept_follow!(follow_request_from_object) unless follow_request_from_object.nil? return accept_quote!(quote_request_from_object) unless quote_request_from_object.nil? - return accept_feature_request! if Mastodon::Feature.collections_enabled? && feature_request_from_object.present? + return accept_feature_request! if feature_request_from_object.present? case @object['type'] when 'Follow' diff --git a/app/lib/activitypub/activity/add.rb b/app/lib/activitypub/activity/add.rb index 0d22910a9a5..957471a5c69 100644 --- a/app/lib/activitypub/activity/add.rb +++ b/app/lib/activitypub/activity/add.rb @@ -13,12 +13,10 @@ class ActivityPub::Activity::Add < ActivityPub::Activity add_featured end when @account.collections_url - return unless Mastodon::Feature.collections_enabled? - add_collection else @collection = @account.collections.find_by(uri: value_or_id(@json['target'])) - add_collection_item if @collection && Mastodon::Feature.collections_enabled? + add_collection_item if @collection end end diff --git a/app/lib/activitypub/activity/delete.rb b/app/lib/activitypub/activity/delete.rb index 1239462a11f..1e3cd1a647d 100644 --- a/app/lib/activitypub/activity/delete.rb +++ b/app/lib/activitypub/activity/delete.rb @@ -3,7 +3,7 @@ class ActivityPub::Activity::Delete < ActivityPub::Activity def perform return delete_person if @account.uri == object_uri - return delete_feature_authorization! unless !Mastodon::Feature.collections_enabled? || feature_authorization_from_object.nil? + return delete_feature_authorization! unless feature_authorization_from_object.nil? delete_object end diff --git a/app/lib/activitypub/activity/feature_request.rb b/app/lib/activitypub/activity/feature_request.rb index 16a3860a0ee..27386187678 100644 --- a/app/lib/activitypub/activity/feature_request.rb +++ b/app/lib/activitypub/activity/feature_request.rb @@ -4,7 +4,6 @@ class ActivityPub::Activity::FeatureRequest < ActivityPub::Activity include Payloadable def perform - return unless Mastodon::Feature.collections_enabled? return if non_matching_uri_hosts?(@account.uri, @json['id']) @collection = find_or_fetch_collection diff --git a/app/lib/activitypub/activity/update.rb b/app/lib/activitypub/activity/update.rb index 8eb2427a84f..87d5a5fad56 100644 --- a/app/lib/activitypub/activity/update.rb +++ b/app/lib/activitypub/activity/update.rb @@ -13,7 +13,7 @@ class ActivityPub::Activity::Update < ActivityPub::Activity update_account elsif supported_object_type? || converted_object_type? update_status - elsif equals_or_includes_any?(@object['type'], ['FeaturedCollection']) && Mastodon::Feature.collections_enabled? + elsif equals_or_includes_any?(@object['type'], ['FeaturedCollection']) update_collection end end diff --git a/app/lib/status_cache_hydrator.rb b/app/lib/status_cache_hydrator.rb index d5920530c60..ece88c04c1b 100644 --- a/app/lib/status_cache_hydrator.rb +++ b/app/lib/status_cache_hydrator.rb @@ -121,7 +121,6 @@ class StatusCacheHydrator end def hydrate_account(payload, account) - return unless Mastodon::Feature.collections_enabled? return unless payload[:id] stale_account = Account.find_by(id: payload[:id]) diff --git a/app/serializers/activitypub/actor_serializer.rb b/app/serializers/activitypub/actor_serializer.rb index 8212b607f63..38b0878b1a4 100644 --- a/app/serializers/activitypub/actor_serializer.rb +++ b/app/serializers/activitypub/actor_serializer.rb @@ -10,7 +10,7 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer :moved_to, :property_value, :discoverable, :suspended, :memorial, :indexable, :attribution_domains, :profile_settings - context_extensions :interaction_policies if Mastodon::Feature.collections_enabled? + context_extensions :interaction_policies attributes :id, :webfinger, :type, :following, :followers, :inbox, :outbox, :featured, :featured_tags, @@ -21,8 +21,8 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer attribute :show_media_replies, key: :show_replies_in_media - attribute :interaction_policy, if: -> { Mastodon::Feature.collections_enabled? } - attribute :featured_collections, if: -> { Mastodon::Feature.collections_enabled? } + attribute :interaction_policy + attribute :featured_collections has_one :public_key, serializer: ActivityPub::PublicKeySerializer diff --git a/app/serializers/rest/account_serializer.rb b/app/serializers/rest/account_serializer.rb index 8afe3f3b679..e24cdfab856 100644 --- a/app/serializers/rest/account_serializer.rb +++ b/app/serializers/rest/account_serializer.rb @@ -21,7 +21,7 @@ class REST::AccountSerializer < ActiveModel::Serializer attribute :memorial, if: :memorial? - attribute :feature_approval, if: -> { Mastodon::Feature.collections_enabled? } + attribute :feature_approval attribute :email_subscriptions, if: -> { Rails.application.config.x.email_subscriptions && Setting.email_subscriptions } class AccountDecorator < SimpleDelegator diff --git a/app/serializers/rest/role_serializer.rb b/app/serializers/rest/role_serializer.rb index a3d8af64b21..424b3401daf 100644 --- a/app/serializers/rest/role_serializer.rb +++ b/app/serializers/rest/role_serializer.rb @@ -3,7 +3,7 @@ class REST::RoleSerializer < ActiveModel::Serializer attributes :id, :name, :permissions, :color, :highlighted - attribute :collection_limit, if: -> { Mastodon::Feature.collections_enabled? } + attribute :collection_limit def id object.id.to_s diff --git a/app/services/activitypub/process_account_service.rb b/app/services/activitypub/process_account_service.rb index 62545393270..e616400c934 100644 --- a/app/services/activitypub/process_account_service.rb +++ b/app/services/activitypub/process_account_service.rb @@ -72,7 +72,7 @@ class ActivityPub::ProcessAccountService < BaseService unless @options[:only_key] || @account.suspended? check_featured_collection! if @json['featured'].present? check_featured_tags_collection! if @json['featuredTags'].present? - check_featured_collections_collection! if @json['featuredCollections'].present? && Mastodon::Feature.collections_enabled? + check_featured_collections_collection! if @json['featuredCollections'].present? check_links! if @account.fields.any?(&:requires_verification?) end @@ -121,7 +121,7 @@ class ActivityPub::ProcessAccountService < BaseService @account.uri = @uri @account.actor_type = actor_type @account.created_at = @json['published'] if @json['published'].present? - @account.feature_approval_policy = feature_approval_policy if Mastodon::Feature.collections_enabled? + @account.feature_approval_policy = feature_approval_policy end def valid_collection_uri(uri) diff --git a/app/services/resolve_url_service.rb b/app/services/resolve_url_service.rb index 9a136439b08..5c27121acd3 100644 --- a/app/services/resolve_url_service.rb +++ b/app/services/resolve_url_service.rb @@ -28,7 +28,7 @@ class ResolveURLService < BaseService status = FetchRemoteStatusService.new.call(resource_url, prefetched_body: body) authorize_with @on_behalf_of, status, :show? unless status.nil? status - elsif type == 'FeaturedCollection' && Mastodon::Feature.collections_enabled? + elsif type == 'FeaturedCollection' collection = ActivityPub::FetchRemoteFeaturedCollectionService.new.call(resource_url, prefetched_body: body) authorize_with @on_behalf_of, collection, :show? unless collection.nil? collection diff --git a/app/views/admin/reports/index.html.haml b/app/views/admin/reports/index.html.haml index 070d8c8518c..b6b25c190ef 100644 --- a/app/views/admin/reports/index.html.haml +++ b/app/views/admin/reports/index.html.haml @@ -67,10 +67,9 @@ = material_symbol('photo_camera') = report.media_attachments_count - - if Mastodon::Feature.collections_enabled? - %span.report-card__summary__item__content__icon{ title: t('admin.accounts.collections') } - = material_symbol('category') - = report.collections.size + %span.report-card__summary__item__content__icon{ title: t('admin.accounts.collections') } + = material_symbol('category') + = report.collections.size - if report.forwarded? · diff --git a/app/views/admin/reports/show.html.haml b/app/views/admin/reports/show.html.haml index bae69cca045..d23edee3c49 100644 --- a/app/views/admin/reports/show.html.haml +++ b/app/views/admin/reports/show.html.haml @@ -62,27 +62,26 @@ - else = render partial: 'admin/shared/status_batch_row', collection: @statuses, as: :status, locals: { f: f } -- if Mastodon::Feature.collections_enabled? - %details{ open: @collections.any? } - %summary - = t 'admin.reports.collections', count: @collections.size +%details{ open: @collections.any? } + %summary + = t 'admin.reports.collections', count: @collections.size - = form_with model: @collection_form, url: batch_admin_account_collections_path(@report.target_account_id, report_id: @report.id) do |f| - .batch-table - .batch-table__toolbar - %label.batch-table__toolbar__select.batch-checkbox-all - = check_box_tag :batch_checkbox_all, nil, false - .batch-table__toolbar__actions - = link_to safe_join([material_symbol('add'), t('admin.reports.add_to_report')]), - admin_account_collections_path(@report.target_account_id, report_id: @report.id), - class: 'table-action-link' - - if !@collections.empty? && @report.unresolved? - = f.button safe_join([material_symbol('close'), t('admin.collections.batch.remove_from_report')]), name: :remove_from_report, class: 'table-action-link', type: :submit - .batch-table__body - - if @collections.empty? - = nothing_here 'nothing-here--under-tabs' - - else - = render partial: 'admin/shared/collection_batch_row', collection: @collections, as: :collection, locals: { f: f } + = form_with model: @collection_form, url: batch_admin_account_collections_path(@report.target_account_id, report_id: @report.id) do |f| + .batch-table + .batch-table__toolbar + %label.batch-table__toolbar__select.batch-checkbox-all + = check_box_tag :batch_checkbox_all, nil, false + .batch-table__toolbar__actions + = link_to safe_join([material_symbol('add'), t('admin.reports.add_to_report')]), + admin_account_collections_path(@report.target_account_id, report_id: @report.id), + class: 'table-action-link' + - if !@collections.empty? && @report.unresolved? + = f.button safe_join([material_symbol('close'), t('admin.collections.batch.remove_from_report')]), name: :remove_from_report, class: 'table-action-link', type: :submit + .batch-table__body + - if @collections.empty? + = nothing_here 'nothing-here--under-tabs' + - else + = render partial: 'admin/shared/collection_batch_row', collection: @collections, as: :collection, locals: { f: f } - if @report.unresolved? %hr.spacer/ diff --git a/app/views/admin/roles/_form.html.haml b/app/views/admin/roles/_form.html.haml index 51114beac15..7246357e670 100644 --- a/app/views/admin/roles/_form.html.haml +++ b/app/views/admin/roles/_form.html.haml @@ -32,13 +32,11 @@ %hr.spacer/ -- if Mastodon::Feature.collections_enabled? +.fields-group + = form.input :collection_limit, + wrapper: :with_label - .fields-group - = form.input :collection_limit, - wrapper: :with_label - - %hr.spacer/ +%hr.spacer/ - unless current_user.role == form.object diff --git a/spec/lib/activitypub/activity/accept_spec.rb b/spec/lib/activitypub/activity/accept_spec.rb index 732f01cc6db..7775143e88f 100644 --- a/spec/lib/activitypub/activity/accept_spec.rb +++ b/spec/lib/activitypub/activity/accept_spec.rb @@ -172,7 +172,7 @@ RSpec.describe ActivityPub::Activity::Accept do end end - context 'with a FeatureRequest', feature: :collections do + context 'with a FeatureRequest' do let(:collection) { Fabricate(:collection, account: recipient) } let(:collection_item) { Fabricate(:collection_item, collection:, account: sender, state: :pending) } let(:object) { collection_item.activity_uri } diff --git a/spec/lib/activitypub/activity/add_spec.rb b/spec/lib/activitypub/activity/add_spec.rb index b444f38a3d0..201953087f1 100644 --- a/spec/lib/activitypub/activity/add_spec.rb +++ b/spec/lib/activitypub/activity/add_spec.rb @@ -80,7 +80,7 @@ RSpec.describe ActivityPub::Activity::Add do end end - context 'when the target is the `featuredCollections` collection', feature: :collections do + context 'when the target is the `featuredCollections` collection' do subject { described_class.new(activity_json, account) } let(:account) { Fabricate(:remote_account, collections_url: 'https://example.com/actor/1/featured_collections') } @@ -122,7 +122,7 @@ RSpec.describe ActivityPub::Activity::Add do end end - context 'when the target is a collection', feature: :collections do + context 'when the target is a collection' do subject { described_class.new(activity_json, collection.account) } let(:collection) { Fabricate(:remote_collection) } diff --git a/spec/lib/activitypub/activity/delete_spec.rb b/spec/lib/activitypub/activity/delete_spec.rb index c6d74b4b5b9..7e5d5f85746 100644 --- a/spec/lib/activitypub/activity/delete_spec.rb +++ b/spec/lib/activitypub/activity/delete_spec.rb @@ -120,7 +120,7 @@ RSpec.describe ActivityPub::Activity::Delete do end end - context 'with a FeatureAuthorization', feature: :collections do + context 'with a FeatureAuthorization' do let(:recipient) { Fabricate(:account) } let(:approval_uri) { 'https://example.com/authorizations/1' } let(:collection) { Fabricate(:collection, account: recipient) } diff --git a/spec/lib/activitypub/activity/feature_request_spec.rb b/spec/lib/activitypub/activity/feature_request_spec.rb index 5d134b6cebb..3efdf33b356 100644 --- a/spec/lib/activitypub/activity/feature_request_spec.rb +++ b/spec/lib/activitypub/activity/feature_request_spec.rb @@ -20,7 +20,7 @@ RSpec.describe ActivityPub::Activity::FeatureRequest do } end - describe '#perform', feature: :collections do + describe '#perform' do subject { described_class.new(json, sender) } context 'when recipient is discoverable' do diff --git a/spec/lib/activitypub/activity/update_spec.rb b/spec/lib/activitypub/activity/update_spec.rb index 701a2ff1f55..c281d03a94a 100644 --- a/spec/lib/activitypub/activity/update_spec.rb +++ b/spec/lib/activitypub/activity/update_spec.rb @@ -257,7 +257,7 @@ RSpec.describe ActivityPub::Activity::Update do end end - context 'with a `FeaturedCollection` object', feature: :collections do + context 'with a `FeaturedCollection` object' do let(:collection) { Fabricate(:remote_collection, account: sender, name: 'old name', discoverable: false) } let(:account) { Fabricate(:account) } let!(:collection_item) { Fabricate(:collection_item, account:, collection:, uri: 'https://example.com/featured_stamps/1') } diff --git a/spec/lib/status_cache_hydrator_spec.rb b/spec/lib/status_cache_hydrator_spec.rb index 03e453c046e..3eb781dfba0 100644 --- a/spec/lib/status_cache_hydrator_spec.rb +++ b/spec/lib/status_cache_hydrator_spec.rb @@ -6,7 +6,7 @@ RSpec.describe StatusCacheHydrator do let(:status) { Fabricate(:status) } let(:account) { Fabricate(:account) } - describe '#hydrate', feature: :collections do + describe '#hydrate' do let(:compare_to_hash) { InlineRenderer.render(status, account, :status) } shared_examples 'shared behavior' do diff --git a/spec/models/admin/moderation_action_spec.rb b/spec/models/admin/moderation_action_spec.rb index fd2e7a4c4cb..c49e7c9a307 100644 --- a/spec/models/admin/moderation_action_spec.rb +++ b/spec/models/admin/moderation_action_spec.rb @@ -33,7 +33,7 @@ RSpec.describe Admin::ModerationAction do expect(report.reload).to be_action_taken end - context 'with attached collections', feature: :collections do + context 'with attached collections' do let(:status_ids) { [] } let(:collections) { Fabricate.times(2, :collection, account: target_account) } @@ -47,7 +47,7 @@ RSpec.describe Admin::ModerationAction do end end - context 'with a remote collection', feature: :collections do + context 'with a remote collection' do let(:status_ids) { [] } let(:collection) { Fabricate(:remote_collection) } let(:target_account) { collection.account } @@ -83,7 +83,7 @@ RSpec.describe Admin::ModerationAction do expect(report.reload).to be_action_taken end - context 'with attached collections', feature: :collections do + context 'with attached collections' do let(:status_ids) { [] } let(:collections) { Fabricate.times(2, :collection, account: target_account) } diff --git a/spec/requests/activitypub/featured_collections_spec.rb b/spec/requests/activitypub/featured_collections_spec.rb index 09a17c53bea..c4601df69b3 100644 --- a/spec/requests/activitypub/featured_collections_spec.rb +++ b/spec/requests/activitypub/featured_collections_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' RSpec.describe 'Collections' do - describe 'GET /ap/users/@:account_id/featured_collections', feature: :collections do + describe 'GET /ap/users/@:account_id/featured_collections' do subject { get ap_account_featured_collections_path(account.id, format: :json) } let(:collection) { Fabricate(:collection) } diff --git a/spec/requests/admin/reports_spec.rb b/spec/requests/admin/reports_spec.rb index d44db637953..2e361e43dfd 100644 --- a/spec/requests/admin/reports_spec.rb +++ b/spec/requests/admin/reports_spec.rb @@ -47,7 +47,7 @@ RSpec.describe 'Admin Reports' do it_behaves_like 'successful return' end - context 'with a reported collection', feature: :collections do + context 'with a reported collection' do before do report.collections << Fabricate(:collection, account: report.target_account) end @@ -55,7 +55,7 @@ RSpec.describe 'Admin Reports' do it_behaves_like 'successful return' end - context 'with both status and collection', feature: :collections do + context 'with both status and collection' do before do status = Fabricate(:status, account: report.target_account) report.update(status_ids: [status.id]) diff --git a/spec/requests/api/v1/collection_items_spec.rb b/spec/requests/api/v1/collection_items_spec.rb index e7ee854e67a..93d4f70ad52 100644 --- a/spec/requests/api/v1/collection_items_spec.rb +++ b/spec/requests/api/v1/collection_items_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'Api::V1Alpha::CollectionItems', feature: :collections do +RSpec.describe 'Api::V1Alpha::CollectionItems' do include_context 'with API authentication', oauth_scopes: 'read:collections write:collections' describe 'POST /api/v1_alpha/collections/:collection_id/items' do diff --git a/spec/requests/api/v1/collections_spec.rb b/spec/requests/api/v1/collections_spec.rb index 4bf296f2936..b6bb17319db 100644 --- a/spec/requests/api/v1/collections_spec.rb +++ b/spec/requests/api/v1/collections_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'Api::V1::Collections', feature: :collections do +RSpec.describe 'Api::V1::Collections' do include_context 'with API authentication', oauth_scopes: 'read:collections write:collections' describe 'GET /api/v1/accounts/:account_id/collections' do diff --git a/spec/requests/api/v1/in_collections_spec.rb b/spec/requests/api/v1/in_collections_spec.rb index 3c41feb2e75..74902fe09ef 100644 --- a/spec/requests/api/v1/in_collections_spec.rb +++ b/spec/requests/api/v1/in_collections_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'Api::V1::InCollections', feature: :collections do +RSpec.describe 'Api::V1::InCollections' do include_context 'with API authentication', oauth_scopes: 'read:collections write:collections' describe 'GET /api/v1/in_collections' do diff --git a/spec/requests/api/v1/reports_spec.rb b/spec/requests/api/v1/reports_spec.rb index 247ff979c5a..6b344eaac8e 100644 --- a/spec/requests/api/v1/reports_spec.rb +++ b/spec/requests/api/v1/reports_spec.rb @@ -113,7 +113,7 @@ RSpec.describe 'Reports' do end end - context 'with attached collection', feature: :collections do + context 'with attached collection' do let(:collection) { Fabricate(:collection, account: target_account) } let(:collection_ids) { [collection.id] } diff --git a/spec/requests/collection_items_spec.rb b/spec/requests/collection_items_spec.rb index f0802fc3f36..703e6bdba32 100644 --- a/spec/requests/collection_items_spec.rb +++ b/spec/requests/collection_items_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' RSpec.describe 'CollectionItems' do - describe 'GET /ap/users/@:account_id/collection_items/:id', feature: :collections do + describe 'GET /ap/users/@:account_id/collection_items/:id' do subject { get ap_account_collection_item_path(account.id, collection_item, format: :json) } let(:collection_item) { Fabricate(:collection_item) } diff --git a/spec/requests/collections_spec.rb b/spec/requests/collections_spec.rb index bdebb03f605..dbdf1c16a28 100644 --- a/spec/requests/collections_spec.rb +++ b/spec/requests/collections_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' RSpec.describe 'Collections' do - describe 'GET /collections/:id', feature: :collections do + describe 'GET /collections/:id' do subject { get collection_path(collection) } let(:collection) { Fabricate(:collection) } @@ -15,7 +15,7 @@ RSpec.describe 'Collections' do end end - describe 'GET /ap/:account_id/collections/:id', feature: :collections do + describe 'GET /ap/:account_id/collections/:id' do subject { get ap_account_collection_path(account.id, collection, format: :json) } let(:collection) { Fabricate(:collection) } diff --git a/spec/serializers/activitypub/actor_serializer_spec.rb b/spec/serializers/activitypub/actor_serializer_spec.rb index 73702c979c1..661890f33b6 100644 --- a/spec/serializers/activitypub/actor_serializer_spec.rb +++ b/spec/serializers/activitypub/actor_serializer_spec.rb @@ -40,46 +40,37 @@ RSpec.describe ActivityPub::ActorSerializer do describe '#interactionPolicy' do let(:record) { Fabricate(:account) } - # TODO: Remove when feature flag is removed - context 'when collections feature is disabled?' do - it 'is not present' do - expect(subject).to_not have_key('interactionPolicy') + context 'when actor is discoverable' do + it 'includes an automatic policy allowing everyone' do + expect(subject).to include('interactionPolicy' => { + 'canFeature' => { + 'automaticApproval' => ['https://www.w3.org/ns/activitystreams#Public'], + }, + }) + end + + context 'when actor is locked' do + let(:record) { Fabricate(:account, locked: true) } + + it 'includes an automatic policy allowing followers' do + expect(subject).to include('interactionPolicy' => { + 'canFeature' => { + 'automaticApproval' => [ActivityPub::TagManager.instance.followers_uri_for(record)], + }, + }) + end end end - context 'when collections feature is enabled', feature: :collections do - context 'when actor is discoverable' do - it 'includes an automatic policy allowing everyone' do - expect(subject).to include('interactionPolicy' => { - 'canFeature' => { - 'automaticApproval' => ['https://www.w3.org/ns/activitystreams#Public'], - }, - }) - end + context 'when actor is not discoverable' do + let(:record) { Fabricate(:account, discoverable: false) } - context 'when actor is locked' do - let(:record) { Fabricate(:account, locked: true) } - - it 'includes an automatic policy allowing followers' do - expect(subject).to include('interactionPolicy' => { - 'canFeature' => { - 'automaticApproval' => [ActivityPub::TagManager.instance.followers_uri_for(record)], - }, - }) - end - end - end - - context 'when actor is not discoverable' do - let(:record) { Fabricate(:account, discoverable: false) } - - it 'includes an automatic policy limited to the actor itself' do - expect(subject).to include('interactionPolicy' => { - 'canFeature' => { - 'automaticApproval' => [ActivityPub::TagManager.instance.uri_for(record)], - }, - }) - end + it 'includes an automatic policy limited to the actor itself' do + expect(subject).to include('interactionPolicy' => { + 'canFeature' => { + 'automaticApproval' => [ActivityPub::TagManager.instance.uri_for(record)], + }, + }) end end end diff --git a/spec/serializers/activitypub/flag_serializer_spec.rb b/spec/serializers/activitypub/flag_serializer_spec.rb index a66a49bc876..cebf0d2ea70 100644 --- a/spec/serializers/activitypub/flag_serializer_spec.rb +++ b/spec/serializers/activitypub/flag_serializer_spec.rb @@ -38,7 +38,7 @@ RSpec.describe ActivityPub::FlagSerializer do end end - context 'with collection', feature: :collections do + context 'with collection' do let(:target_account) { Fabricate(:account) } let(:collection) { Fabricate(:collection, account: target_account) } let(:report) { Fabricate(:report, target_account:, collections: [collection]) } diff --git a/spec/serializers/rest/account_serializer_spec.rb b/spec/serializers/rest/account_serializer_spec.rb index e8e437cbd30..68e62f7e070 100644 --- a/spec/serializers/rest/account_serializer_spec.rb +++ b/spec/serializers/rest/account_serializer_spec.rb @@ -76,75 +76,66 @@ RSpec.describe REST::AccountSerializer do end describe '#feature_approval' do - # TODO: Remove when feature flag is removed - context 'when collections feature is disabled' do - it 'does not include the approval policy' do - expect(subject).to_not have_key('feature_approval') - end - end - - context 'when collections feature is enabled', feature: :collections do - context 'when account is local' do - context 'when account is discoverable' do - it 'includes a policy that allows featuring' do - expect(subject['feature_approval']).to include({ - 'automatic' => ['public'], - 'manual' => [], - 'current_user' => 'automatic', - }) - end - - context 'when account is locked' do - let(:account) { Fabricate(:account, locked: true) } - - context 'when the current account does not follow the user' do - it 'includes a policy that allows featuring for followers and has "denied" for the current user' do - expect(subject['feature_approval']).to include({ - 'automatic' => ['followers'], - 'manual' => [], - 'current_user' => 'denied', - }) - end - end - - context 'when the current account follows the user' do - before { current_user.account.follow!(account) } - - it 'includes a policy that allows featuring for followers and has "automatic" for the current user' do - expect(subject['feature_approval']).to include({ - 'automatic' => ['followers'], - 'manual' => [], - 'current_user' => 'automatic', - }) - end - end - end - end - - context 'when account is not discoverable' do - let(:account) { Fabricate(:account, discoverable: false) } - - it 'includes a policy that disallows featuring' do - expect(subject['feature_approval']).to include({ - 'automatic' => [], - 'manual' => [], - 'current_user' => 'denied', - }) - end - end - end - - context 'when account is remote' do - let(:account) { Fabricate(:account, domain: 'example.com', feature_approval_policy: 0b11000000000000000010) } - - it 'includes the matching policy' do + context 'when account is local' do + context 'when account is discoverable' do + it 'includes a policy that allows featuring' do expect(subject['feature_approval']).to include({ - 'automatic' => ['followers', 'following'], - 'manual' => ['public'], - 'current_user' => 'manual', + 'automatic' => ['public'], + 'manual' => [], + 'current_user' => 'automatic', + }) + end + + context 'when account is locked' do + let(:account) { Fabricate(:account, locked: true) } + + context 'when the current account does not follow the user' do + it 'includes a policy that allows featuring for followers and has "denied" for the current user' do + expect(subject['feature_approval']).to include({ + 'automatic' => ['followers'], + 'manual' => [], + 'current_user' => 'denied', + }) + end + end + + context 'when the current account follows the user' do + before { current_user.account.follow!(account) } + + it 'includes a policy that allows featuring for followers and has "automatic" for the current user' do + expect(subject['feature_approval']).to include({ + 'automatic' => ['followers'], + 'manual' => [], + 'current_user' => 'automatic', + }) + end + end + end + end + + context 'when account is not discoverable' do + let(:account) { Fabricate(:account, discoverable: false) } + + it 'includes a policy that disallows featuring' do + expect(subject['feature_approval']).to include({ + 'automatic' => [], + 'manual' => [], + 'current_user' => 'denied', }) end end end + + context 'when account is remote' do + let(:account) { Fabricate(:account, domain: 'example.com', feature_approval_policy: 0b11000000000000000010) } + + it 'includes the matching policy' do + expect(subject['feature_approval']).to include({ + 'automatic' => ['followers', 'following'], + 'manual' => ['public'], + 'current_user' => 'manual', + }) + end + end end end diff --git a/spec/serializers/rest/account_warning_serializer_spec.rb b/spec/serializers/rest/account_warning_serializer_spec.rb index a7a9dc5f630..ebbfebe76ae 100644 --- a/spec/serializers/rest/account_warning_serializer_spec.rb +++ b/spec/serializers/rest/account_warning_serializer_spec.rb @@ -3,8 +3,9 @@ require 'rails_helper' RSpec.describe REST::AccountWarningSerializer do - subject { serialized_record_json(record, described_class) } + subject { serialized_record_json(record, described_class, options: { scope: current_user, scope_name: :current_user }) } + let(:current_user) { Fabricate(:moderator_user) } let(:record) { Fabricate :account_warning, id: 123, status_ids: [456, 789] } describe 'serialization' do diff --git a/spec/serializers/rest/admin/account_serializer_spec.rb b/spec/serializers/rest/admin/account_serializer_spec.rb index 5f617207a76..d16b23f112d 100644 --- a/spec/serializers/rest/admin/account_serializer_spec.rb +++ b/spec/serializers/rest/admin/account_serializer_spec.rb @@ -3,7 +3,9 @@ require 'rails_helper' RSpec.describe REST::Admin::AccountSerializer do - subject { serialized_record_json(record, described_class) } + subject { serialized_record_json(record, described_class, options: { scope: current_user, scope_name: :current_user }) } + + let(:current_user) { Fabricate(:admin_user) } context 'when created_at is populated' do let(:record) { Fabricate :account, user: Fabricate(:user) } diff --git a/spec/serializers/rest/admin/report_serializer_spec.rb b/spec/serializers/rest/admin/report_serializer_spec.rb index 78d7d4f10a9..8be7c9410b1 100644 --- a/spec/serializers/rest/admin/report_serializer_spec.rb +++ b/spec/serializers/rest/admin/report_serializer_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' RSpec.describe REST::Admin::ReportSerializer do - subject { serialized_record_json(report, described_class) } + subject { serialized_record_json(report, described_class, options: { scope_name: :current_user, scope: nil }) } context 'with timestamps' do let(:report) { Fabricate(:report, action_taken_at: 3.days.ago) } diff --git a/spec/serializers/rest/report_serializer_spec.rb b/spec/serializers/rest/report_serializer_spec.rb index 180cdbdb68d..5ffff832208 100644 --- a/spec/serializers/rest/report_serializer_spec.rb +++ b/spec/serializers/rest/report_serializer_spec.rb @@ -6,10 +6,16 @@ RSpec.describe REST::ReportSerializer do subject do serialized_record_json( report, - described_class + described_class, + options: { + scope: current_user, + scope_name: :current_user, + } ) end + let(:current_user) { Fabricate(:moderator_user) } + context 'with timestamps' do let(:report) { Fabricate(:report, action_taken_at: 3.days.ago) } diff --git a/spec/serializers/rest/role_serializer_spec.rb b/spec/serializers/rest/role_serializer_spec.rb index 5b380475872..cb8fd14fc6b 100644 --- a/spec/serializers/rest/role_serializer_spec.rb +++ b/spec/serializers/rest/role_serializer_spec.rb @@ -27,7 +27,7 @@ RSpec.describe REST::RoleSerializer do }) end - context 'when collections are enabled', feature: :collections do + context 'when collections are enabled' do it 'includes the relevant attributes' do expect(subject) .to include({ diff --git a/spec/serializers/rest/suggestion_serializer_spec.rb b/spec/serializers/rest/suggestion_serializer_spec.rb index 288d1daa230..a30076ed48f 100644 --- a/spec/serializers/rest/suggestion_serializer_spec.rb +++ b/spec/serializers/rest/suggestion_serializer_spec.rb @@ -3,7 +3,8 @@ require 'rails_helper' RSpec.describe REST::SuggestionSerializer do - let(:serialization) { serialized_record_json(record, described_class) } + let(:serialization) { serialized_record_json(record, described_class, options: { scope: current_user, scope_name: :current_user }) } + let(:current_user) { Fabricate(:user) } let(:record) do AccountSuggestions::Suggestion.new( account: account, diff --git a/spec/services/activitypub/process_account_service_spec.rb b/spec/services/activitypub/process_account_service_spec.rb index 96923a816e9..56f117ca824 100644 --- a/spec/services/activitypub/process_account_service_spec.rb +++ b/spec/services/activitypub/process_account_service_spec.rb @@ -63,7 +63,7 @@ RSpec.describe ActivityPub::ProcessAccountService do end end - context 'with collection URIs', feature: :collections do + context 'with collection URIs' do let(:payload) do { 'id' => 'https://foo.test', @@ -562,16 +562,7 @@ RSpec.describe ActivityPub::ProcessAccountService do .to_return(status: 200, body: '', headers: {}) end - # TODO: Remove when feature flag is removed - context 'when collections feature is disabled' do - it 'does not set the interaction policy' do - account = subject.call('user1', 'foo.test', payload) - - expect(account.feature_approval_policy).to be_zero - end - end - - context 'when collections feature is enabled', feature: :collections do + context 'when collections feature is enabled' do it 'sets the interaction policy to the correct value' do account = subject.call('user1', 'foo.test', payload) diff --git a/spec/services/resolve_url_service_spec.rb b/spec/services/resolve_url_service_spec.rb index 6174d8cac9b..d5ac5b55b50 100644 --- a/spec/services/resolve_url_service_spec.rb +++ b/spec/services/resolve_url_service_spec.rb @@ -30,7 +30,7 @@ RSpec.describe ResolveURLService do expect(subject.call(url)).to eq known_account end - context 'when searching for a remote collection', feature: :collections do + context 'when searching for a remote collection' do let(:account) { Fabricate(:account) } let(:collection_account) { Fabricate(:account, domain: 'example.com', protocol: :activitypub) } @@ -63,7 +63,7 @@ RSpec.describe ResolveURLService do end end - context 'when searching for a local collection', feature: :collections do + context 'when searching for a local collection' do let(:account) { Fabricate(:account) } let(:collection) { Fabricate(:collection) } From 796f77136229cfb400e0ea403ef6ed9ed3e06f07 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 29 May 2026 09:48:52 +0000 Subject: [PATCH 65/70] Update dependency pg to v8.21.0 (#39067) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/yarn.lock b/yarn.lock index a7c35f775a9..cac35d1e98b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11920,14 +11920,14 @@ __metadata: languageName: node linkType: hard -"pg-cloudflare@npm:^1.3.0": - version: 1.3.0 - resolution: "pg-cloudflare@npm:1.3.0" - checksum: 10c0/b0866c88af8e54c7b3ed510719d92df37714b3af5e3a3a10d9f761fcec99483e222f5b78a1f2de590368127648087c45c01aaf66fadbe46edb25673eedc4f8fc +"pg-cloudflare@npm:^1.4.0": + version: 1.4.0 + resolution: "pg-cloudflare@npm:1.4.0" + checksum: 10c0/553764d00055052648393cda53c1feb065991d6f9fbfdeb56cf8396c5b33377ab2897aaf5dc9cd3933d09023a1f01e8b1ca755431dcf5fd71c92ea277e2888f1 languageName: node linkType: hard -"pg-connection-string@npm:^2.12.0, pg-connection-string@npm:^2.6.0": +"pg-connection-string@npm:^2.13.0, pg-connection-string@npm:^2.6.0": version: 2.13.0 resolution: "pg-connection-string@npm:2.13.0" checksum: 10c0/870f83a8fca06d0340fc522653471d9c7081efbadf25c7f5801fcfb58104ef527138bb5d0546b21498ff4df75a742469622f657911a3b74034a1e94e59f34e31 @@ -11941,19 +11941,19 @@ __metadata: languageName: node linkType: hard -"pg-pool@npm:^3.13.0": - version: 3.13.0 - resolution: "pg-pool@npm:3.13.0" +"pg-pool@npm:^3.14.0": + version: 3.14.0 + resolution: "pg-pool@npm:3.14.0" peerDependencies: pg: ">=8.0" - checksum: 10c0/2756f79cda14e3834356f2ca035deab806bca2172a38a488b62ada54bd3e65d33f583661bbe96da0c0e75e6bc59807ada733c37efca6e24ae2893429936a1549 + checksum: 10c0/3dd706e67e3b317e29409d9eb3bd44e960eabd86db2a9711a9391bbd43881f8ce7a5f7054a341509558ee05e9bf0a3cc7aef037039da0790ce1e16762ade3ba6 languageName: node linkType: hard -"pg-protocol@npm:*, pg-protocol@npm:^1.13.0": - version: 1.13.0 - resolution: "pg-protocol@npm:1.13.0" - checksum: 10c0/a4e851e6bb8ff404ca19d561cf49b6b0caf45163bd3f289889edaf6c4e9fb25b08fb57f50d37a8cc86007efcf2cbb3dd2372c97a353a546f45eb49ddebc84fa9 +"pg-protocol@npm:*, pg-protocol@npm:^1.14.0": + version: 1.14.0 + resolution: "pg-protocol@npm:1.14.0" + checksum: 10c0/dccb29b30f5cee8f2ca7dfd17da9eb957174f7a1a25e987e0bfc9fe7640f53dc9fd05c7f3635e7db0c5eefcd41716fffe625f3c1ea9789634d438851b9ce90ae languageName: node linkType: hard @@ -11971,13 +11971,13 @@ __metadata: linkType: hard "pg@npm:^8.5.0": - version: 8.20.0 - resolution: "pg@npm:8.20.0" + version: 8.21.0 + resolution: "pg@npm:8.21.0" dependencies: - pg-cloudflare: "npm:^1.3.0" - pg-connection-string: "npm:^2.12.0" - pg-pool: "npm:^3.13.0" - pg-protocol: "npm:^1.13.0" + pg-cloudflare: "npm:^1.4.0" + pg-connection-string: "npm:^2.13.0" + pg-pool: "npm:^3.14.0" + pg-protocol: "npm:^1.14.0" pg-types: "npm:2.2.0" pgpass: "npm:1.0.5" peerDependencies: @@ -11988,7 +11988,7 @@ __metadata: peerDependenciesMeta: pg-native: optional: true - checksum: 10c0/e21d44b9fb3ec188e67778d7abd32d945a546f2da5128b6c8c16da8ae1e42fdc953c0d6f0a2ee65d11f31808c1dffaf908cb9c880cd2e8f0ae05525e4b8bc832 + checksum: 10c0/6b46ae867a3838bf3bb720ef5a3d877bd85de19d90c6f3422e772f56443fc04a4f5b1fa44c9e8544a0f44454971e653d98f4040096e92c378a5aa5a7b07fa0f1 languageName: node linkType: hard From fa1e16ed9fe5633d9e86468d57b2040608677c37 Mon Sep 17 00:00:00 2001 From: Echo Date: Fri, 29 May 2026 13:53:03 +0200 Subject: [PATCH 66/70] Collections: Add default recommendations (#39202) --- .../components/form_fields/combobox_field.tsx | 17 +++ .../features/collections/editor/accounts.tsx | 2 + .../mastodon/features/collections/utils.ts | 6 +- .../mastodon/hooks/useSearchAccounts.ts | 117 ++++++++++++++---- 4 files changed, 112 insertions(+), 30 deletions(-) diff --git a/app/javascript/mastodon/components/form_fields/combobox_field.tsx b/app/javascript/mastodon/components/form_fields/combobox_field.tsx index f3e7b454765..a0e0a36f790 100644 --- a/app/javascript/mastodon/components/form_fields/combobox_field.tsx +++ b/app/javascript/mastodon/components/form_fields/combobox_field.tsx @@ -100,6 +100,10 @@ interface ComboboxProps< * Icon to be displayed in the text input */ icon?: TextInputProps['icon'] | null; + /** + * Set to true to open as soon as there is focus + */ + openOnFocus?: boolean; /** * Set to false to keep the menu open when an item is selected */ @@ -217,8 +221,10 @@ const ComboboxWithRef = ( renderGroupTitle, renderItem, onSelectItem, + onFocus, onChange, onKeyDown, + openOnFocus = false, closeOnSelect = true, suppressMenu = false, icon = SearchIcon, @@ -288,6 +294,16 @@ const ComboboxWithRef = ( } }, []); + const handleFocus: React.FocusEventHandler = useCallback( + (e) => { + if (openOnFocus) { + setShouldMenuOpen(true); + } + onFocus?.(e); + }, + [onFocus, openOnFocus], + ); + const handleInputChange = useCallback( (e: React.ChangeEvent) => { onChange(e); @@ -487,6 +503,7 @@ const ComboboxWithRef = ( autoComplete='off' spellCheck='false' value={value} + onFocus={handleFocus} onChange={handleInputChange} onKeyDown={handleInputKeyDown} icon={icon ?? undefined} diff --git a/app/javascript/mastodon/features/collections/editor/accounts.tsx b/app/javascript/mastodon/features/collections/editor/accounts.tsx index c9423217f56..c5d23bdf3ee 100644 --- a/app/javascript/mastodon/features/collections/editor/accounts.tsx +++ b/app/javascript/mastodon/features/collections/editor/accounts.tsx @@ -215,6 +215,7 @@ export const CollectionAccounts: React.FC<{ resetAccounts, } = useSearchAccounts({ withRelationships: true, + withDefaultFollows: searchValue === '', // Don't suggest accounts that were already added filterResults: (account) => !editorItems.find((item) => item.account_id === account.id), @@ -363,6 +364,7 @@ export const CollectionAccounts: React.FC<{ )} {hasPendingItems && } `/collections/${id}`; -export const canAccountBeAdded = (account: ApiMutedAccountJSON | Account) => +export const canAccountBeAdded = (account: ApiAccountJSON | Account) => ['automatic', 'manual'].includes(account.feature_approval.current_user); export const canAccountBeAddedByFollowers = ( - account: ApiMutedAccountJSON | Account, + account: ApiAccountJSON | Account, ) => account.feature_approval.automatic.includes('followers') || account.feature_approval.manual.includes('followers'); diff --git a/app/javascript/mastodon/hooks/useSearchAccounts.ts b/app/javascript/mastodon/hooks/useSearchAccounts.ts index c19f08e734f..b7e6ab9f52a 100644 --- a/app/javascript/mastodon/hooks/useSearchAccounts.ts +++ b/app/javascript/mastodon/hooks/useSearchAccounts.ts @@ -1,4 +1,4 @@ -import { useCallback, useRef, useState } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import { useDebouncedCallback } from 'use-debounce'; @@ -8,16 +8,20 @@ import { apiRequest } from 'mastodon/api'; import type { ApiAccountJSON } from 'mastodon/api_types/accounts'; import { useAppDispatch } from 'mastodon/store'; +import { useCurrentAccountId } from './useAccountId'; + export function useSearchAccounts({ onSettled, filterResults, resetOnInputClear = true, withRelationships = false, + withDefaultFollows = false, }: { onSettled?: (value: string) => void; filterResults?: (account: ApiAccountJSON) => boolean; resetOnInputClear?: boolean; withRelationships?: boolean; + withDefaultFollows?: boolean; } = {}) { const dispatch = useAppDispatch(); @@ -29,7 +33,7 @@ export function useSearchAccounts({ const searchRequestRef = useRef(null); const searchAccounts = useDebouncedCallback( - (value: string) => { + async (value: string) => { if (searchRequestRef.current) { searchRequestRef.current.abort(); } @@ -46,41 +50,100 @@ export function useSearchAccounts({ searchRequestRef.current = new AbortController(); - void apiRequest('GET', 'v1/accounts/search', { - signal: searchRequestRef.current.signal, - params: { - q: value, - resolve: true, - }, - }) - .then((data) => { - const accounts = filterResults ? data.filter(filterResults) : data; - const accountIds = accounts.map((a) => a.id); - dispatch(importFetchedAccounts(accounts)); - if (withRelationships) { - dispatch(fetchRelationships(accountIds)); - } - setAccounts(accounts); - setLoadingState('idle'); - onSettled?.(value); - }) - .catch(() => { - setLoadingState('error'); - onSettled?.(value); - }); + try { + const data = await apiRequest( + 'GET', + 'v1/accounts/search', + { + signal: searchRequestRef.current.signal, + params: { + q: value, + resolve: true, + }, + }, + ); + const accounts = filterResults ? data.filter(filterResults) : data; + const accountIds = accounts.map((a) => a.id); + dispatch(importFetchedAccounts(accounts)); + if (withRelationships) { + dispatch(fetchRelationships(accountIds)); + } + setAccounts(accounts); + setLoadingState('idle'); + onSettled?.(value); + } catch { + setLoadingState('error'); + onSettled?.(value); + } }, 500, { leading: true, trailing: true }, ); + const startSearch = useCallback( + (value: string) => { + void searchAccounts(value); + }, + [searchAccounts], + ); + const resetAccounts = useCallback(() => { setAccounts([]); }, []); - return { - searchAccounts, - resetAccounts, + const currentUserId = useCurrentAccountId(); + const [defaultAccounts, setDefaultAccounts] = useState< + ApiAccountJSON[] | null + >(null); + useEffect(() => { + if ( + !currentUserId || + loadingState !== 'idle' || + defaultAccounts !== null || + !withDefaultFollows + ) { + return; + } + + async function doRequest() { + setLoadingState('loading'); + try { + const data = await apiRequest( + 'GET', + `v1/accounts/${currentUserId}/following`, + { params: { limit: 40 } }, + ); + const accounts = filterResults ? data.filter(filterResults) : data; + const accountIds = accounts.map((a) => a.id); + dispatch(importFetchedAccounts(accounts)); + if (withRelationships) { + dispatch(fetchRelationships(accountIds)); + } + setDefaultAccounts(accounts); + setLoadingState('idle'); + } catch { + setLoadingState('error'); + } + } + void doRequest(); + }, [ + currentUserId, accounts, + dispatch, + filterResults, + loadingState, + withRelationships, + defaultAccounts, + withDefaultFollows, + ]); + + return { + searchAccounts: startSearch, + resetAccounts, + accounts: + accounts.length === 0 && withDefaultFollows + ? (defaultAccounts ?? []) + : accounts, isLoading: loadingState === 'loading', isError: loadingState === 'error', }; From a86f3a4000bac9d502f5a7613f2fa544755a8321 Mon Sep 17 00:00:00 2001 From: diondiondion Date: Fri, 29 May 2026 14:48:12 +0200 Subject: [PATCH 67/70] Use new Collections endpoint version (#39214) --- app/javascript/mastodon/api/collections.ts | 26 ++++++++-------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/app/javascript/mastodon/api/collections.ts b/app/javascript/mastodon/api/collections.ts index 7f39651f02a..badd3b43976 100644 --- a/app/javascript/mastodon/api/collections.ts +++ b/app/javascript/mastodon/api/collections.ts @@ -15,48 +15,40 @@ import type { } from '../api_types/collections'; export const apiCreateCollection = (collection: ApiCreateCollectionPayload) => - apiRequestPost('v1_alpha/collections', collection); + apiRequestPost('v1/collections', collection); export const apiUpdateCollection = ({ id, ...collection }: ApiUpdateCollectionPayload) => - apiRequestPut( - `v1_alpha/collections/${id}`, - collection, - ); + apiRequestPut(`v1/collections/${id}`, collection); export const apiDeleteCollection = (collectionId: string) => - apiRequestDelete(`v1_alpha/collections/${collectionId}`); + apiRequestDelete(`v1/collections/${collectionId}`); export const apiGetCollection = (collectionId: string) => apiRequestGet( - `v1_alpha/collections/${collectionId}`, + `v1/collections/${collectionId}`, ); export const apiGetCollectionsCreatedByAccount = (accountId: string) => - apiRequestGet( - `v1_alpha/accounts/${accountId}/collections`, - ); + apiRequestGet(`v1/accounts/${accountId}/collections`); export const apiGetCollectionsFeaturingAccount = (accountId: string) => - apiRequestGet( - `v1_alpha/accounts/${accountId}/in_collections`, - ); + apiRequestGet(`v1/accounts/${accountId}/in_collections`); export const apiAddCollectionItem = (collectionId: string, accountId: string) => apiRequestPost( - `v1_alpha/collections/${collectionId}/items`, + `v1/collections/${collectionId}/items`, { account_id: accountId }, ); export const apiRemoveCollectionItem = (collectionId: string, itemId: string) => apiRequestDelete( - `v1_alpha/collections/${collectionId}/items/${itemId}`, + `v1/collections/${collectionId}/items/${itemId}`, ); export const apiRevokeCollectionInclusion = ( collectionId: string, itemId: string, -) => - apiRequestPost(`v1_alpha/collections/${collectionId}/items/${itemId}/revoke`); +) => apiRequestPost(`v1/collections/${collectionId}/items/${itemId}/revoke`); From 7fba458d9227bea224a6c779f895c4945005f074 Mon Sep 17 00:00:00 2001 From: diondiondion Date: Fri, 29 May 2026 15:07:00 +0200 Subject: [PATCH 68/70] Remove frontend check for collections feature flag (#39215) --- .../components/empty_message.tsx | 78 +++++-------- .../features/account_featured/index.tsx | 106 ++++++++---------- .../collections/overview/created_by_you.tsx | 3 +- .../collections/overview/featuring_you.tsx | 3 +- .../mastodon/features/collections/utils.ts | 5 - .../features/navigation_panel/index.tsx | 23 ++-- .../features/ui/components/block_modal.jsx | 11 +- app/javascript/mastodon/features/ui/index.jsx | 11 +- app/javascript/mastodon/locales/en.json | 2 - app/javascript/mastodon/utils/environment.ts | 2 +- 10 files changed, 98 insertions(+), 146 deletions(-) diff --git a/app/javascript/mastodon/features/account_featured/components/empty_message.tsx b/app/javascript/mastodon/features/account_featured/components/empty_message.tsx index aa1dc4078ea..ad903d5a5d1 100644 --- a/app/javascript/mastodon/features/account_featured/components/empty_message.tsx +++ b/app/javascript/mastodon/features/account_featured/components/empty_message.tsx @@ -9,7 +9,6 @@ import { Button } from '@/mastodon/components/button'; import { DisplayName } from '@/mastodon/components/display_name'; import { EmptyState } from '@/mastodon/components/empty_state'; import { LimitedAccountHint } from '@/mastodon/components/limited_account_hint'; -import { areCollectionsEnabled } from '@/mastodon/features/collections/utils'; import { useAccount } from '@/mastodon/hooks/useAccount'; import { useCurrentAccountId } from '@/mastodon/hooks/useAccountId'; import { useAppDispatch } from '@/mastodon/store'; @@ -50,56 +49,39 @@ export const EmptyMessage: React.FC = ({ let title: React.ReactNode = null; let message: React.ReactNode = null; - const hasCollections = areCollectionsEnabled(); - if (me === accountId) { - if (hasCollections) { - // Return only here to insert the "Create a collection" button as the action for the empty state. - return ( - + } + message={ + + } + > + {!withoutAddCollectionButton && ( + - } - message={ - - } - > - {!withoutAddCollectionButton && ( - - - - )} - - - ); - } else { - title = ( - - ); - message = ( - - ); - } + + )} + + + ); } else if (suspended) { title = ( = ({ multiColumn, }) => { @@ -98,14 +95,11 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({ ); const hasCollections = - collectionsEnabled && - collectionsLoadStatus === 'idle' && - listedCollections.length > 0; + collectionsLoadStatus === 'idle' && listedCollections.length > 0; const hasFeaturedAccounts = !featuredAccountIds.isEmpty(); - const isLoading = - !accountId || (collectionsEnabled && collectionsLoadStatus !== 'idle'); + const isLoading = !accountId || collectionsLoadStatus !== 'idle'; if (accountId === null) { return ; @@ -165,57 +159,53 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({ )} - {collectionsEnabled && ( - <> - -

    - -

    - {accountId === me && ( - - - - )} -
    - {hasCollections ? ( - - - ), - subtitle: ( - - ), - }} - renderListItem={renderListItem} - /> - - ) : ( -
  • - {areCollectionsEnabled() && ( -
  • - -
  • - )} +
  • + +
  • { const dispatch = useDispatch(); @@ -73,12 +72,10 @@ export const BlockModal = ({ accountId, acct }) => {
  • - {areCollectionsEnabled() && -
  • -
    -
    -
  • - } +
  • +
    +
    +
  • diff --git a/app/javascript/mastodon/features/ui/index.jsx b/app/javascript/mastodon/features/ui/index.jsx index 1bf0842cb8c..4910950b44f 100644 --- a/app/javascript/mastodon/features/ui/index.jsx +++ b/app/javascript/mastodon/features/ui/index.jsx @@ -93,7 +93,6 @@ import { CustomHomepage } from 'mastodon/features/custom_homepage'; // Dummy import, to make sure that ends up in the application bundle. // Without this it ends up in ~8 very commonly used bundles. import '../../components/status'; -import { areCollectionsEnabled } from '../collections/utils'; import { getNavigationSkipLinkId, SkipLinks } from './components/skip_links'; const messages = defineMessages({ @@ -235,13 +234,9 @@ class SwitchingColumnsArea extends PureComponent { - {areCollectionsEnabled() && - [ - , - , - , - ] - } + + + diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index f111e436b82..86b080e0837 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -637,8 +637,6 @@ "empty_column.account_featured.other": "{acct} has not featured anything yet.", "empty_column.account_featured_self.no_collections_button": "Create a collection", "empty_column.account_featured_self.no_collections_hide_tab": "Hide this tab instead", - "empty_column.account_featured_self.pre_collections": "Stay tuned for Collections", - "empty_column.account_featured_self.pre_collections_desc": "Collections (coming in Mastodon 4.6) allow you to create your own curated lists of accounts to recommend to others.", "empty_column.account_featured_self.showcase_accounts": "Showcase your favorite accounts", "empty_column.account_featured_self.showcase_accounts_desc": "Collections are curated lists of accounts to help others discover more of the Fediverse.", "empty_column.account_featured_unknown.other": "This account hasn’t featured anything yet.", diff --git a/app/javascript/mastodon/utils/environment.ts b/app/javascript/mastodon/utils/environment.ts index cdcb88d68b9..e2936bd224e 100644 --- a/app/javascript/mastodon/utils/environment.ts +++ b/app/javascript/mastodon/utils/environment.ts @@ -12,7 +12,7 @@ export function isProduction() { else return import.meta.env.PROD; } -export type ServerFeatures = 'fasp' | 'collections'; +export type ServerFeatures = 'fasp'; export function isServerFeatureEnabled(feature: ServerFeatures) { return initialState?.features.includes(feature) ?? false; From 8e15e49e87984e5165b64c7bb4b58e4a51c8dd58 Mon Sep 17 00:00:00 2001 From: diondiondion Date: Fri, 29 May 2026 15:14:06 +0200 Subject: [PATCH 69/70] [Profile] Make handle button text selectable (#39217) --- .../mastodon/components/account_header/styles.module.scss | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/javascript/mastodon/components/account_header/styles.module.scss b/app/javascript/mastodon/components/account_header/styles.module.scss index ab751ce170e..4de49f79aea 100644 --- a/app/javascript/mastodon/components/account_header/styles.module.scss +++ b/app/javascript/mastodon/components/account_header/styles.module.scss @@ -110,6 +110,9 @@ word-break: break-all; text-align: left; + /* Allow the handle text to be selected */ + user-select: text; + > svg { width: 16px; height: 16px; From 0caf334891e0a5f4e995f1d667eb83d3aad7e41e Mon Sep 17 00:00:00 2001 From: diondiondion Date: Fri, 29 May 2026 17:27:57 +0200 Subject: [PATCH 70/70] Reduce account overfetching when displaying collection lists (#39220) --- .../mastodon/actions/accounts_typed.ts | 10 +++++++ app/javascript/mastodon/api/accounts.ts | 5 ++++ app/javascript/mastodon/api/lists.ts | 2 +- .../mastodon/features/lists/members.tsx | 4 +-- .../mastodon/features/lists/new.tsx | 4 +-- .../mastodon/reducers/slices/collections.ts | 28 +++++++++++++++++++ 6 files changed, 48 insertions(+), 5 deletions(-) diff --git a/app/javascript/mastodon/actions/accounts_typed.ts b/app/javascript/mastodon/actions/accounts_typed.ts index fe7c7327ce3..3d8396c81a9 100644 --- a/app/javascript/mastodon/actions/accounts_typed.ts +++ b/app/javascript/mastodon/actions/accounts_typed.ts @@ -3,6 +3,7 @@ import { createAction } from '@reduxjs/toolkit'; import { apiRemoveAccountFromFollowers, apiGetEndorsedAccounts, + apiGetAccounts, } from 'mastodon/api/accounts'; import type { ApiRelationshipJSON } from 'mastodon/api_types/relationships'; import { createDataLoadingThunk } from 'mastodon/store/typed_functions'; @@ -113,3 +114,12 @@ export const fetchEndorsedAccounts = createDataLoadingThunk( return data; }, ); + +export const fetchAccounts = createDataLoadingThunk( + 'accounts/multi_accounts', + ({ accountIds }: { accountIds: string[] }) => apiGetAccounts(accountIds), + (data, { dispatch }) => { + dispatch(importFetchedAccounts(data)); + return data; + }, +); diff --git a/app/javascript/mastodon/api/accounts.ts b/app/javascript/mastodon/api/accounts.ts index 2229d17c560..52c5b017d96 100644 --- a/app/javascript/mastodon/api/accounts.ts +++ b/app/javascript/mastodon/api/accounts.ts @@ -19,6 +19,11 @@ import type { ApiProfileUpdateParams, } from '../api_types/profile'; +export const apiGetAccounts = (ids: string[]) => + apiRequestGet('v1/accounts', { + id: ids, + }); + export const apiSubmitAccountNote = (id: string, value: string) => apiRequestPost(`v1/accounts/${id}/note`, { comment: value, diff --git a/app/javascript/mastodon/api/lists.ts b/app/javascript/mastodon/api/lists.ts index fa7e6e4554b..a3f4b5be95f 100644 --- a/app/javascript/mastodon/api/lists.ts +++ b/app/javascript/mastodon/api/lists.ts @@ -15,7 +15,7 @@ export const apiUpdate = (list: Partial) => export const apiGetLists = () => apiRequestGet('v1/lists'); -export const apiGetAccounts = (listId: string) => +export const apiGetListAccounts = (listId: string) => apiRequestGet(`v1/lists/${listId}/accounts`, { limit: 0, }); diff --git a/app/javascript/mastodon/features/lists/members.tsx b/app/javascript/mastodon/features/lists/members.tsx index 66ea1bb1277..a788034030a 100644 --- a/app/javascript/mastodon/features/lists/members.tsx +++ b/app/javascript/mastodon/features/lists/members.tsx @@ -15,7 +15,7 @@ import { fetchList } from 'mastodon/actions/lists'; import { openModal } from 'mastodon/actions/modal'; import { apiFollowAccount } from 'mastodon/api/accounts'; import { - apiGetAccounts, + apiGetListAccounts, apiAddAccountToList, apiRemoveAccountFromList, } from 'mastodon/api/lists'; @@ -184,7 +184,7 @@ const ListMembers: React.FC<{ if (id) { dispatch(fetchList(id)); - void apiGetAccounts(id) + void apiGetListAccounts(id) .then((data) => { dispatch(importFetchedAccounts(data)); setAccountIds(data.map((a) => a.id)); diff --git a/app/javascript/mastodon/features/lists/new.tsx b/app/javascript/mastodon/features/lists/new.tsx index b2f916b738f..e8f6343278c 100644 --- a/app/javascript/mastodon/features/lists/new.tsx +++ b/app/javascript/mastodon/features/lists/new.tsx @@ -12,7 +12,7 @@ import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react' import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react'; import { fetchList } from 'mastodon/actions/lists'; import { createList, updateList } from 'mastodon/actions/lists_typed'; -import { apiGetAccounts } from 'mastodon/api/lists'; +import { apiGetListAccounts } from 'mastodon/api/lists'; import type { ApiAccountJSON } from 'mastodon/api_types/accounts'; import type { RepliesPolicyType } from 'mastodon/api_types/lists'; import { Avatar } from 'mastodon/components/avatar'; @@ -44,7 +44,7 @@ const MembersLink: React.FC<{ const [avatarAccounts, setAvatarAccounts] = useState([]); useEffect(() => { - void apiGetAccounts(id) + void apiGetListAccounts(id) .then((data) => { setAvatarCount(data.length); setAvatarAccounts(data.slice(0, 3)); diff --git a/app/javascript/mastodon/reducers/slices/collections.ts b/app/javascript/mastodon/reducers/slices/collections.ts index aa45bfc6e92..ec2143351ab 100644 --- a/app/javascript/mastodon/reducers/slices/collections.ts +++ b/app/javascript/mastodon/reducers/slices/collections.ts @@ -1,6 +1,7 @@ import type { PayloadAction } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit'; +import { fetchAccounts } from '@/mastodon/actions/accounts_typed'; import { importFetchedAccounts } from '@/mastodon/actions/importer'; import { apiCreateCollection, @@ -20,6 +21,7 @@ import type { CollectionAccountItem, } from '@/mastodon/api_types/collections'; import { initialState, me } from '@/mastodon/initial_state'; +import type { AppDispatch } from '@/mastodon/store'; import { createAppAsyncThunk, createAppSelector, @@ -322,16 +324,42 @@ const collectionSlice = createSlice({ }, }); +/** + * Prefetch accounts whose avatars will be displayed in the collection list + */ +async function importAccountsForPreviewCard( + collections: ApiCollectionJSON[], + dispatch: AppDispatch, +) { + const previewAccountIds = collections + .flatMap((collection) => + collection.items.slice(0, 3).map((item) => item.account_id), + ) + .filter((id): id is string => !!id); + + await dispatch( + fetchAccounts({ + accountIds: previewAccountIds, + }), + ); +} + export const fetchCollectionsCreatedByAccount = createDataLoadingThunk( `${collectionSlice.name}/fetchCollectionsCreatedByAccount`, ({ accountId }: { accountId: string }) => apiGetCollectionsCreatedByAccount(accountId), + async ({ collections }, { dispatch }) => { + await importAccountsForPreviewCard(collections, dispatch); + }, ); export const fetchCollectionsFeaturingAccount = createDataLoadingThunk( `${collectionSlice.name}/fetchCollectionsFeaturingAccount`, ({ accountId }: { accountId: string }) => apiGetCollectionsFeaturingAccount(accountId), + async ({ collections }, { dispatch }) => { + await importAccountsForPreviewCard(collections, dispatch); + }, ); export const fetchCollection = createDataLoadingThunk(