diff --git a/.env.production.sample b/.env.production.sample index 4fc13ecb2e189d..e8c1529f920c08 100644 --- a/.env.production.sample +++ b/.env.production.sample @@ -1,5 +1,5 @@ # This is a sample configuration file. You can generate your configuration -# with the `rake mastodon:setup` interactive setup wizard, but to customize +# with the `bundle exec rails mastodon:setup` interactive setup wizard, but to customize # your setup even further, you'll need to edit it manually. This sample does # not demonstrate all available configuration options. Please look at # https://docs.joinmastodon.org/admin/config/ for the full documentation. @@ -68,7 +68,7 @@ DB_PORT=5432 # Secrets # ------- -# Generate each with the `RAILS_ENV=production bundle exec rake secret` task (`docker-compose run --rm web bundle exec rake secret` if you use docker compose) +# Generate each with the `RAILS_ENV=production bundle exec rails secret` task (`docker-compose run --rm web bundle exec rails secret` if you use docker compose) # ------- SECRET_KEY_BASE= OTP_SECRET= @@ -76,7 +76,7 @@ OTP_SECRET= # Web Push # -------- -# Generate with `rake mastodon:webpush:generate_vapid_key` (first is the private key, second is the public one) +# Generate with `bundle exec rails mastodon:webpush:generate_vapid_key` (first is the private key, second is the public one) # You should only generate this once per instance. If you later decide to change it, all push subscription will # be invalidated, requiring the users to access the website again to resubscribe. # -------- diff --git a/.github/workflows/bundler-audit.yml b/.github/workflows/bundler-audit.yml index e3e2da0c787a54..2341d6e67f6241 100644 --- a/.github/workflows/bundler-audit.yml +++ b/.github/workflows/bundler-audit.yml @@ -1,8 +1,10 @@ name: Bundler Audit on: + merge_group: push: - branches-ignore: - - 'dependabot/**' + branches: + - 'main' + - 'stable-*' paths: - 'Gemfile*' - '.ruby-version' diff --git a/.github/workflows/check-i18n.yml b/.github/workflows/check-i18n.yml index ceb385933b29bb..5a1c0519665873 100644 --- a/.github/workflows/check-i18n.yml +++ b/.github/workflows/check-i18n.yml @@ -2,9 +2,13 @@ name: Check i18n on: push: - branches: [main] + branches: + - 'main' + - 'stable-*' pull_request: - branches: [main] + branches: + - 'main' + - 'stable-*' env: RAILS_ENV: test diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 6fb93b7fef45a6..8690e9ed6d1639 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,11 +1,15 @@ name: 'CodeQL' on: + merge_group: push: - branches: ['main'] + branches: + - 'main' + - 'stable-*' pull_request: - # The branches below must be a subset of the branches above - branches: ['main'] + branches: + - 'main' + - 'stable-*' schedule: - cron: '22 6 * * 1' diff --git a/.github/workflows/crowdin-upload.yml b/.github/workflows/crowdin-upload.yml index 32c09802b42a0c..6717853304a6c3 100644 --- a/.github/workflows/crowdin-upload.yml +++ b/.github/workflows/crowdin-upload.yml @@ -1,9 +1,11 @@ name: Crowdin / Upload translations on: + merge_group: push: branches: - - main + - 'main' + - 'stable-*' paths: - crowdin-glitch.yml - app/javascript/flavours/glitch/locales/en.json diff --git a/.github/workflows/format-check.yml b/.github/workflows/format-check.yml index 2d483b50229626..c10f350a02ef28 100644 --- a/.github/workflows/format-check.yml +++ b/.github/workflows/format-check.yml @@ -1,6 +1,10 @@ name: Check formatting on: + merge_group: push: + branches: + - 'main' + - 'stable-*' pull_request: jobs: diff --git a/.github/workflows/lint-css.yml b/.github/workflows/lint-css.yml index d3b8035cd86521..95fcd569420fdf 100644 --- a/.github/workflows/lint-css.yml +++ b/.github/workflows/lint-css.yml @@ -1,9 +1,10 @@ name: CSS Linting on: + merge_group: push: - branches-ignore: - - 'dependabot/**' - - 'renovate/**' + branches: + - 'main' + - 'stable-*' paths: - 'package.json' - 'yarn.lock' diff --git a/.github/workflows/lint-haml.yml b/.github/workflows/lint-haml.yml index ca4b0c80bfdc3e..a1a9e99c902bfb 100644 --- a/.github/workflows/lint-haml.yml +++ b/.github/workflows/lint-haml.yml @@ -1,9 +1,10 @@ name: Haml Linting on: + merge_group: push: - branches-ignore: - - 'dependabot/**' - - 'renovate/**' + branches: + - 'main' + - 'stable-*' paths: - '.github/workflows/haml-lint-problem-matcher.json' - '.github/workflows/lint-haml.yml' diff --git a/.github/workflows/lint-js.yml b/.github/workflows/lint-js.yml index 1c1ecc2b22049b..7d31a5e20e7804 100644 --- a/.github/workflows/lint-js.yml +++ b/.github/workflows/lint-js.yml @@ -1,9 +1,10 @@ name: JavaScript Linting on: + merge_group: push: - branches-ignore: - - 'dependabot/**' - - 'renovate/**' + branches: + - 'main' + - 'stable-*' paths: - 'package.json' - 'yarn.lock' diff --git a/.github/workflows/lint-ruby.yml b/.github/workflows/lint-ruby.yml index b3a89c3caf1cbd..277e456146fdcf 100644 --- a/.github/workflows/lint-ruby.yml +++ b/.github/workflows/lint-ruby.yml @@ -1,9 +1,10 @@ name: Ruby Linting on: + merge_group: push: - branches-ignore: - - 'dependabot/**' - - 'renovate/**' + branches: + - 'main' + - 'stable-*' paths: - 'Gemfile*' - '.rubocop*.yml' diff --git a/.github/workflows/test-js.yml b/.github/workflows/test-js.yml index 481afdba30366d..e9e43ac9e80184 100644 --- a/.github/workflows/test-js.yml +++ b/.github/workflows/test-js.yml @@ -1,9 +1,10 @@ name: JavaScript Testing on: + merge_group: push: - branches-ignore: - - 'dependabot/**' - - 'renovate/**' + branches: + - 'main' + - 'stable-*' paths: - 'package.json' - 'yarn.lock' diff --git a/.github/workflows/test-migrations.yml b/.github/workflows/test-migrations.yml index 3eaf2c2d7402b8..6a0e67c58ee500 100644 --- a/.github/workflows/test-migrations.yml +++ b/.github/workflows/test-migrations.yml @@ -1,29 +1,29 @@ name: Historical data migration test on: + merge_group: push: - branches-ignore: - - 'dependabot/**' - - 'renovate/**' + branches: + - 'main' + - 'stable-*' + paths: + - 'Gemfile*' + - '.ruby-version' + - '**/*.rb' + - '.github/workflows/test-migrations.yml' + - 'lib/tasks/tests.rake' + pull_request: + paths: + - 'Gemfile*' + - '.ruby-version' + - '**/*.rb' + - '.github/workflows/test-migrations.yml' + - 'lib/tasks/tests.rake' jobs: - pre_job: - runs-on: ubuntu-latest - - outputs: - should_skip: ${{ steps.skip_check.outputs.should_skip }} - - steps: - - id: skip_check - uses: fkirc/skip-duplicate-actions@v5 - with: - paths: '["Gemfile*", ".ruby-version", "**/*.rb", ".github/workflows/test-migrations.yml", "lib/tasks/tests.rake"]' - test: runs-on: ubuntu-latest - needs: pre_job - if: needs.pre_job.outputs.should_skip != 'true' strategy: fail-fast: false diff --git a/.github/workflows/test-ruby.yml b/.github/workflows/test-ruby.yml index ef898968d0128c..fcfeed5fbad7b3 100644 --- a/.github/workflows/test-ruby.yml +++ b/.github/workflows/test-ruby.yml @@ -1,10 +1,11 @@ name: Ruby Testing on: + merge_group: push: - branches-ignore: - - 'dependabot/**' - - 'renovate/**' + branches: + - 'main' + - 'stable-*' pull_request: env: @@ -223,7 +224,7 @@ jobs: - name: Load database schema run: './bin/rails db:create db:schema:load db:seed' - - run: bin/rspec --tag paperclip_processing + - run: bin/rspec --tag attachment_processing - name: Upload coverage reports to Codecov if: matrix.ruby-version == '.ruby-version' diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 4a86051c421dca..2549202410eaf1 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config --auto-gen-only-exclude --no-offense-counts --no-auto-gen-timestamp` -# using RuboCop version 1.64.1. +# using RuboCop version 1.65.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -14,7 +14,7 @@ Lint/NonLocalExitFromIterator: Metrics/AbcSize: Max: 90 -# Configuration parameters: CountBlocks, Max. +# Configuration parameters: CountBlocks, CountModifierForms, Max. Metrics/BlockNesting: Exclude: - 'lib/tasks/mastodon.rake' diff --git a/.ruby-version b/.ruby-version index 619b537668489e..a0891f563f38b0 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.3.3 +3.3.4 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2271802ca961a9..66aa01ffe4f206 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -50,6 +50,11 @@ You can contribute in the following ways: If your contributions are accepted into Mastodon, you can request to be paid through [our OpenCollective](https://opencollective.com/mastodon). +Please review the org-level [contribution guidelines] for high-level acceptance +criteria guidance. + +[contribution guidelines]: https://github.com/mastodon/.github/blob/main/CONTRIBUTING.md + ## API Changes and Additions Please note that any changes or additions made to the API should have an accompanying pull request on [our documentation repository](https://github.com/mastodon/documentation). diff --git a/Dockerfile b/Dockerfile index 7f7eca06dac040..758db9bcc90b56 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,7 @@ ARG BUILDPLATFORM=${BUILDPLATFORM} # Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.3.x"] # renovate: datasource=docker depName=docker.io/ruby -ARG RUBY_VERSION="3.3.3" +ARG RUBY_VERSION="3.3.4" # # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"] # renovate: datasource=node-version depName=node ARG NODE_MAJOR_VERSION="20" @@ -67,7 +67,9 @@ ENV \ # Optimize jemalloc 5.x performance MALLOC_CONF="narenas:2,background_thread:true,thp:never,dirty_decay_ms:1000,muzzy_decay_ms:0" \ # Enable libvips, should not be changed - MASTODON_USE_LIBVIPS=true + MASTODON_USE_LIBVIPS=true \ +# Sidekiq will touch tmp/sidekiq_process_has_started_and_will_begin_processing_jobs to indicate it is ready. This can be used for a readiness check in Kubernetes + MASTODON_SIDEKIQ_READY_FILENAME=sidekiq_process_has_started_and_will_begin_processing_jobs # Set default shell used for running commands SHELL ["/bin/bash", "-o", "pipefail", "-o", "errexit", "-c"] diff --git a/Gemfile.lock b/Gemfile.lock index eb6720e4542b77..c9781a40500cb0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -159,7 +159,7 @@ GEM case_transform (0.2) activesupport cbor (0.5.9.8) - charlock_holmes (0.7.8) + charlock_holmes (0.7.9) chewy (7.6.0) activesupport (>= 5.2) elasticsearch (>= 7.14.0, < 8) @@ -180,7 +180,7 @@ GEM css_parser (1.17.1) addressable csv (3.3.0) - database_cleaner-active_record (2.1.0) + database_cleaner-active_record (2.2.0) activerecord (>= 5.a) database_cleaner-core (~> 2.0.0) database_cleaner-core (2.0.1) @@ -231,7 +231,7 @@ GEM tzinfo excon (0.110.0) fabrication (2.31.0) - faker (3.4.1) + faker (3.4.2) i18n (>= 1.8.11, < 2) faraday (1.10.3) faraday-em_http (~> 1.0) @@ -346,7 +346,7 @@ GEM activesupport (>= 3.0) nokogiri (>= 1.6) io-console (0.7.2) - irb (1.13.2) + irb (1.14.0) rdoc (>= 4.0.0) reline (>= 0.4.2) jmespath (1.6.2) @@ -367,7 +367,7 @@ GEM json-ld-preloaded (3.3.0) json-ld (~> 3.3) rdf (~> 3.3) - json-schema (4.3.0) + json-schema (4.3.1) addressable (>= 2.8) jsonapi-renderer (0.2.2) jwt (2.7.1) @@ -583,15 +583,15 @@ GEM orm_adapter (0.5.0) ox (2.14.18) parallel (1.25.1) - parser (3.3.3.0) + parser (3.3.4.0) ast (~> 2.4.1) racc parslet (2.0.0) pastel (0.8.0) tty-color (~> 0.5) pg (1.5.6) - pghero (3.5.0) - activerecord (>= 6) + pghero (3.6.0) + activerecord (>= 6.1) premailer (1.23.0) addressable css_parser (>= 1.12.0) @@ -696,7 +696,7 @@ GEM responders (3.1.1) actionpack (>= 5.2) railties (>= 5.2) - rexml (3.3.1) + rexml (3.3.2) strscan rotp (6.3.0) rouge (4.2.1) @@ -733,13 +733,13 @@ GEM rspec-mocks (~> 3.0) sidekiq (>= 5, < 8) rspec-support (3.13.1) - rubocop (1.64.1) + rubocop (1.65.0) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 1.8, < 3.0) + regexp_parser (>= 2.4, < 3.0) rexml (>= 3.2.5, < 4.0) rubocop-ast (>= 1.31.1, < 2.0) ruby-progressbar (~> 1.7) @@ -756,7 +756,7 @@ GEM rack (>= 1.1) rubocop (>= 1.33.0, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) - rubocop-rspec (3.0.2) + rubocop-rspec (3.0.3) rubocop (~> 1.61) rubocop-rspec_rails (2.30.0) rubocop (~> 1.61) @@ -766,8 +766,9 @@ GEM ruby-saml (1.16.0) nokogiri (>= 1.13.10) rexml - ruby-vips (2.2.1) + ruby-vips (2.2.2) ffi (~> 1.12) + logger ruby2_keywords (0.0.5) rubyzip (2.3.2) rufus-scheduler (3.9.1) @@ -793,10 +794,10 @@ GEM redis (>= 4.5.0, < 5) sidekiq-bulk (0.2.0) sidekiq - sidekiq-scheduler (5.0.3) + sidekiq-scheduler (5.0.5) rufus-scheduler (~> 3.2) sidekiq (>= 6, < 8) - tilt (>= 1.4.0) + tilt (>= 1.4.0, < 3) sidekiq-unique-jobs (7.1.33) brpoplpush-redis_script (> 0.1.1, <= 2.0.0) concurrent-ruby (~> 1.0, >= 1.0.5) diff --git a/app/controllers/api/v1/notifications/requests_controller.rb b/app/controllers/api/v1/notifications/requests_controller.rb index 0e58379a382e85..9ae80c28ed0732 100644 --- a/app/controllers/api/v1/notifications/requests_controller.rb +++ b/app/controllers/api/v1/notifications/requests_controller.rb @@ -28,14 +28,14 @@ def accept end def dismiss - @request.update!(dismissed: true) + @request.destroy! render_empty end private def load_requests - requests = NotificationRequest.where(account: current_account).where(dismissed: truthy_param?(:dismissed) || false).includes(:last_status, from_account: [:account_stat, :user]).to_a_paginated_by_id( + requests = NotificationRequest.where(account: current_account).includes(:last_status, from_account: [:account_stat, :user]).to_a_paginated_by_id( limit_param(DEFAULT_ACCOUNTS_LIMIT), params_slice(:max_id, :since_id, :min_id) ) @@ -68,8 +68,4 @@ def pagination_max_id def pagination_since_id @requests.first.id end - - def pagination_params(core_params) - params.slice(:dismissed).permit(:dismissed).merge(core_params) - end end diff --git a/app/controllers/api/v1/polls/votes_controller.rb b/app/controllers/api/v1/polls/votes_controller.rb index 513b937ef2de34..ad1b82cb522c69 100644 --- a/app/controllers/api/v1/polls/votes_controller.rb +++ b/app/controllers/api/v1/polls/votes_controller.rb @@ -8,7 +8,7 @@ class Api::V1::Polls::VotesController < Api::BaseController before_action :set_poll def create - VoteService.new.call(current_account, @poll, vote_params[:choices]) + VoteService.new.call(current_account, @poll, vote_params) render json: @poll, serializer: REST::PollSerializer end @@ -22,6 +22,6 @@ def set_poll end def vote_params - params.permit(choices: []) + params.require(:choices) end end diff --git a/app/controllers/api/v1/reports_controller.rb b/app/controllers/api/v1/reports_controller.rb index 300c9faa3f0ee9..72f358bb5bcd95 100644 --- a/app/controllers/api/v1/reports_controller.rb +++ b/app/controllers/api/v1/reports_controller.rb @@ -10,7 +10,7 @@ def create @report = ReportService.new.call( current_account, reported_account, - report_params + report_params.merge(application: doorkeeper_token.application) ) render json: @report, serializer: REST::ReportSerializer diff --git a/app/controllers/api/v2_alpha/notifications_controller.rb b/app/controllers/api/v2_alpha/notifications_controller.rb index edba23ab4a823c..83d40a0886f52f 100644 --- a/app/controllers/api/v2_alpha/notifications_controller.rb +++ b/app/controllers/api/v2_alpha/notifications_controller.rb @@ -12,10 +12,27 @@ def index with_read_replica do @notifications = load_notifications @group_metadata = load_group_metadata + @grouped_notifications = load_grouped_notifications @relationships = StatusRelationshipsPresenter.new(target_statuses_from_notifications, current_user&.account_id) + @sample_accounts = @grouped_notifications.flat_map(&:sample_accounts) + + # Preload associations to avoid N+1s + ActiveRecord::Associations::Preloader.new(records: @sample_accounts, associations: [:account_stat, { user: :role }]).call end - render json: @notifications.map { |notification| NotificationGroup.from_notification(notification, max_id: @group_metadata.dig(notification.group_key, :max_id)) }, each_serializer: REST::NotificationGroupSerializer, relationships: @relationships, group_metadata: @group_metadata + MastodonOTELTracer.in_span('Api::V2Alpha::NotificationsController#index rendering') do |span| + statuses = @grouped_notifications.filter_map { |group| group.target_status&.id } + + span.add_attributes( + 'app.notification_grouping.count' => @grouped_notifications.size, + 'app.notification_grouping.sample_account.count' => @sample_accounts.size, + 'app.notification_grouping.sample_account.unique_count' => @sample_accounts.pluck(:id).uniq.size, + 'app.notification_grouping.status.count' => statuses.size, + 'app.notification_grouping.status.unique_count' => statuses.uniq.size + ) + + render json: @grouped_notifications, each_serializer: REST::NotificationGroupSerializer, relationships: @relationships, group_metadata: @group_metadata + end end def show @@ -36,25 +53,35 @@ def dismiss private def load_notifications - notifications = browserable_account_notifications.includes(from_account: [:account_stat, :user]).to_a_grouped_paginated_by_id( - limit_param(DEFAULT_NOTIFICATIONS_LIMIT), - params_slice(:max_id, :since_id, :min_id) - ) - - Notification.preload_cache_collection_target_statuses(notifications) do |target_statuses| - preload_collection(target_statuses, Status) + MastodonOTELTracer.in_span('Api::V2Alpha::NotificationsController#load_notifications') do + notifications = browserable_account_notifications.includes(from_account: [:account_stat, :user]).to_a_grouped_paginated_by_id( + limit_param(DEFAULT_NOTIFICATIONS_LIMIT), + params_slice(:max_id, :since_id, :min_id) + ) + + Notification.preload_cache_collection_target_statuses(notifications) do |target_statuses| + preload_collection(target_statuses, Status) + end end end def load_group_metadata return {} if @notifications.empty? - browserable_account_notifications - .where(group_key: @notifications.filter_map(&:group_key)) - .where(id: (@notifications.last.id)..(@notifications.first.id)) - .group(:group_key) - .pluck(:group_key, 'min(notifications.id) as min_id', 'max(notifications.id) as max_id', 'max(notifications.created_at) as latest_notification_at') - .to_h { |group_key, min_id, max_id, latest_notification_at| [group_key, { min_id: min_id, max_id: max_id, latest_notification_at: latest_notification_at }] } + MastodonOTELTracer.in_span('Api::V2Alpha::NotificationsController#load_group_metadata') do + browserable_account_notifications + .where(group_key: @notifications.filter_map(&:group_key)) + .where(id: (@notifications.last.id)..(@notifications.first.id)) + .group(:group_key) + .pluck(:group_key, 'min(notifications.id) as min_id', 'max(notifications.id) as max_id', 'max(notifications.created_at) as latest_notification_at') + .to_h { |group_key, min_id, max_id, latest_notification_at| [group_key, { min_id: min_id, max_id: max_id, latest_notification_at: latest_notification_at }] } + end + end + + def load_grouped_notifications + MastodonOTELTracer.in_span('Api::V2Alpha::NotificationsController#load_grouped_notifications') do + @notifications.map { |notification| NotificationGroup.from_notification(notification, max_id: @group_metadata.dig(notification.group_key, :max_id)) } + end end def browserable_account_notifications diff --git a/app/helpers/theme_helper.rb b/app/helpers/theme_helper.rb index bb8ef4547c8c4e..c5d226f70e6205 100644 --- a/app/helpers/theme_helper.rb +++ b/app/helpers/theme_helper.rb @@ -5,8 +5,10 @@ def theme_style_tags(flavour_and_skin) flavour, theme = flavour_and_skin if theme == 'system' - stylesheet_pack_tag("skins/#{flavour}/mastodon-light", media: 'not all and (prefers-color-scheme: dark)', crossorigin: 'anonymous') + - stylesheet_pack_tag("skins/#{flavour}/default", media: '(prefers-color-scheme: dark)', crossorigin: 'anonymous') + ''.html_safe.tap do |tags| + tags << stylesheet_pack_tag("skins/#{flavour}/mastodon-light", media: 'not all and (prefers-color-scheme: dark)', crossorigin: 'anonymous') + tags << stylesheet_pack_tag("skins/#{flavour}/default", media: '(prefers-color-scheme: dark)', crossorigin: 'anonymous') + end else stylesheet_pack_tag "skins/#{flavour}/#{theme}", media: 'all', crossorigin: 'anonymous' end @@ -16,8 +18,10 @@ def theme_color_tags(flavour_and_skin) _, theme = flavour_and_skin if theme == 'system' - tag.meta(name: 'theme-color', content: Themes::THEME_COLORS[:dark], media: '(prefers-color-scheme: dark)') + - tag.meta(name: 'theme-color', content: Themes::THEME_COLORS[:light], media: '(prefers-color-scheme: light)') + ''.html_safe.tap do |tags| + tags << tag.meta(name: 'theme-color', content: Themes::THEME_COLORS[:dark], media: '(prefers-color-scheme: dark)') + tags << tag.meta(name: 'theme-color', content: Themes::THEME_COLORS[:light], media: '(prefers-color-scheme: light)') + end else tag.meta name: 'theme-color', content: theme_color_for(theme) end diff --git a/app/javascript/flavours/glitch/actions/app.ts b/app/javascript/flavours/glitch/actions/app.ts index 6fbfc07f68c931..be1a5cced20f4d 100644 --- a/app/javascript/flavours/glitch/actions/app.ts +++ b/app/javascript/flavours/glitch/actions/app.ts @@ -2,6 +2,9 @@ import { createAction } from '@reduxjs/toolkit'; import type { LayoutType } from '../is_mobile'; +export const focusApp = createAction('APP_FOCUS'); +export const unfocusApp = createAction('APP_UNFOCUS'); + interface ChangeLayoutPayload { layout: LayoutType; } diff --git a/app/javascript/flavours/glitch/actions/compose.js b/app/javascript/flavours/glitch/actions/compose.js index 8ac719737e10fa..3e15d6ff0951b6 100644 --- a/app/javascript/flavours/glitch/actions/compose.js +++ b/app/javascript/flavours/glitch/actions/compose.js @@ -313,7 +313,7 @@ export function doodleSet(options) { export function uploadCompose(files) { return function (dispatch, getState) { - const uploadLimit = 4; + const uploadLimit = getState().getIn(['server', 'server', '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); @@ -333,7 +333,7 @@ export function uploadCompose(files) { dispatch(uploadComposeRequest()); for (const [i, f] of Array.from(files).entries()) { - if (media.size + i > 3) break; + if (media.size + i > (uploadLimit - 1)) break; resizeImage(f).then(file => { const data = new FormData(); diff --git a/app/javascript/flavours/glitch/actions/markers.ts b/app/javascript/flavours/glitch/actions/markers.ts index a85af1c4beec48..861eae41ec4f1e 100644 --- a/app/javascript/flavours/glitch/actions/markers.ts +++ b/app/javascript/flavours/glitch/actions/markers.ts @@ -75,9 +75,17 @@ interface MarkerParam { } function getLastNotificationId(state: RootState): string | undefined { - // @ts-expect-error state.notifications is not yet typed - // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call - return state.getIn(['notifications', 'lastReadId']); + // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access + const enableBeta = state.settings.getIn( + ['notifications', 'groupingBeta'], + false, + ) as boolean; + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return enableBeta + ? state.notificationGroups.lastReadId + : // @ts-expect-error state.notifications is not yet typed + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + state.getIn(['notifications', 'lastReadId']); } const buildPostMarkersParams = (state: RootState) => { diff --git a/app/javascript/flavours/glitch/actions/notification_groups.ts b/app/javascript/flavours/glitch/actions/notification_groups.ts new file mode 100644 index 00000000000000..3f6d14a978b154 --- /dev/null +++ b/app/javascript/flavours/glitch/actions/notification_groups.ts @@ -0,0 +1,144 @@ +import { createAction } from '@reduxjs/toolkit'; + +import { + apiClearNotifications, + apiFetchNotifications, +} from 'flavours/glitch/api/notifications'; +import type { ApiAccountJSON } from 'flavours/glitch/api_types/accounts'; +import type { + ApiNotificationGroupJSON, + ApiNotificationJSON, +} from 'flavours/glitch/api_types/notifications'; +import { allNotificationTypes } from 'flavours/glitch/api_types/notifications'; +import type { ApiStatusJSON } from 'flavours/glitch/api_types/statuses'; +import type { NotificationGap } from 'flavours/glitch/reducers/notification_groups'; +import { + selectSettingsNotificationsExcludedTypes, + selectSettingsNotificationsQuickFilterActive, +} from 'flavours/glitch/selectors/settings'; +import type { AppDispatch } from 'flavours/glitch/store'; +import { + createAppAsyncThunk, + createDataLoadingThunk, +} from 'flavours/glitch/store/typed_functions'; + +import { importFetchedAccounts, importFetchedStatuses } from './importer'; +import { NOTIFICATIONS_FILTER_SET } from './notifications'; +import { saveSettings } from './settings'; + +function excludeAllTypesExcept(filter: string) { + return allNotificationTypes.filter((item) => item !== filter); +} + +function dispatchAssociatedRecords( + dispatch: AppDispatch, + notifications: ApiNotificationGroupJSON[] | ApiNotificationJSON[], +) { + const fetchedAccounts: ApiAccountJSON[] = []; + const fetchedStatuses: ApiStatusJSON[] = []; + + notifications.forEach((notification) => { + if ('sample_accounts' in notification) { + fetchedAccounts.push(...notification.sample_accounts); + } + + if (notification.type === 'admin.report') { + fetchedAccounts.push(notification.report.target_account); + } + + if (notification.type === 'moderation_warning') { + fetchedAccounts.push(notification.moderation_warning.target_account); + } + + if ('status' in notification) { + fetchedStatuses.push(notification.status); + } + }); + + if (fetchedAccounts.length > 0) + dispatch(importFetchedAccounts(fetchedAccounts)); + + if (fetchedStatuses.length > 0) + dispatch(importFetchedStatuses(fetchedStatuses)); +} + +export const fetchNotifications = createDataLoadingThunk( + 'notificationGroups/fetch', + async (_params, { getState }) => { + const activeFilter = + selectSettingsNotificationsQuickFilterActive(getState()); + + return apiFetchNotifications({ + exclude_types: + activeFilter === 'all' + ? selectSettingsNotificationsExcludedTypes(getState()) + : excludeAllTypesExcept(activeFilter), + }); + }, + ({ notifications }, { dispatch }) => { + dispatchAssociatedRecords(dispatch, notifications); + const payload: (ApiNotificationGroupJSON | NotificationGap)[] = + notifications; + + // TODO: might be worth not using gaps for that… + // if (nextLink) payload.push({ type: 'gap', loadUrl: nextLink.uri }); + if (notifications.length > 1) + payload.push({ type: 'gap', maxId: notifications.at(-1)?.page_min_id }); + + return payload; + // dispatch(submitMarkers()); + }, +); + +export const fetchNotificationsGap = createDataLoadingThunk( + 'notificationGroups/fetchGap', + async (params: { gap: NotificationGap }) => + apiFetchNotifications({ max_id: params.gap.maxId }), + + ({ notifications }, { dispatch }) => { + dispatchAssociatedRecords(dispatch, notifications); + + return { notifications }; + }, +); + +export const processNewNotificationForGroups = createAppAsyncThunk( + 'notificationGroups/processNew', + (notification: ApiNotificationJSON, { dispatch }) => { + dispatchAssociatedRecords(dispatch, [notification]); + + return notification; + }, +); + +export const loadPending = createAction('notificationGroups/loadPending'); + +export const updateScrollPosition = createAction<{ top: boolean }>( + 'notificationGroups/updateScrollPosition', +); + +export const setNotificationsFilter = createAppAsyncThunk( + 'notifications/filter/set', + ({ filterType }: { filterType: string }, { dispatch }) => { + dispatch({ + type: NOTIFICATIONS_FILTER_SET, + path: ['notifications', 'quickFilter', 'active'], + value: filterType, + }); + // dispatch(expandNotifications({ forceLoad: true })); + void dispatch(fetchNotifications()); + dispatch(saveSettings()); + }, +); + +export const clearNotifications = createDataLoadingThunk( + 'notifications/clear', + () => apiClearNotifications(), +); + +export const markNotificationsAsRead = createAction( + 'notificationGroups/markAsRead', +); + +export const mountNotifications = createAction('notificationGroups/mount'); +export const unmountNotifications = createAction('notificationGroups/unmount'); diff --git a/app/javascript/flavours/glitch/actions/notifications.js b/app/javascript/flavours/glitch/actions/notifications.js index 3a1af501c8d9e6..7a97e71bdd22e5 100644 --- a/app/javascript/flavours/glitch/actions/notifications.js +++ b/app/javascript/flavours/glitch/actions/notifications.js @@ -43,7 +43,6 @@ export const NOTIFICATIONS_EXPAND_FAIL = 'NOTIFICATIONS_EXPAND_FAIL'; export const NOTIFICATIONS_FILTER_SET = 'NOTIFICATIONS_FILTER_SET'; -export const NOTIFICATIONS_CLEAR = 'NOTIFICATIONS_CLEAR'; export const NOTIFICATIONS_SCROLL_TOP = 'NOTIFICATIONS_SCROLL_TOP'; export const NOTIFICATIONS_LOAD_PENDING = 'NOTIFICATIONS_LOAD_PENDING'; @@ -186,7 +185,7 @@ const noOp = () => {}; let expandNotificationsController = new AbortController(); -export function expandNotifications({ maxId, forceLoad } = {}, done = noOp) { +export function expandNotifications({ maxId, forceLoad = false } = {}, done = noOp) { return (dispatch, getState) => { const activeFilter = getState().getIn(['settings', 'notifications', 'quickFilter', 'active']); const notifications = getState().get('notifications'); @@ -269,16 +268,6 @@ export function expandNotificationsFail(error, isLoadingMore) { }; } -export function clearNotifications() { - return (dispatch) => { - dispatch({ - type: NOTIFICATIONS_CLEAR, - }); - - api().post('/api/v1/notifications/clear'); - }; -} - export function scrollTopNotifications(top) { return { type: NOTIFICATIONS_SCROLL_TOP, diff --git a/app/javascript/flavours/glitch/actions/notifications_migration.tsx b/app/javascript/flavours/glitch/actions/notifications_migration.tsx new file mode 100644 index 00000000000000..32844d4b42e2d6 --- /dev/null +++ b/app/javascript/flavours/glitch/actions/notifications_migration.tsx @@ -0,0 +1,18 @@ +import { createAppAsyncThunk } from 'flavours/glitch/store'; + +import { fetchNotifications } from './notification_groups'; +import { expandNotifications } from './notifications'; + +export const initializeNotifications = createAppAsyncThunk( + 'notifications/initialize', + (_, { dispatch, getState }) => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access + const enableBeta = getState().settings.getIn( + ['notifications', 'groupingBeta'], + false, + ) as boolean; + + if (enableBeta) void dispatch(fetchNotifications()); + else dispatch(expandNotifications()); + }, +); diff --git a/app/javascript/flavours/glitch/actions/notifications_typed.ts b/app/javascript/flavours/glitch/actions/notifications_typed.ts index 176362f4b1edd4..55896f4c378f49 100644 --- a/app/javascript/flavours/glitch/actions/notifications_typed.ts +++ b/app/javascript/flavours/glitch/actions/notifications_typed.ts @@ -1,11 +1,6 @@ import { createAction } from '@reduxjs/toolkit'; -import type { ApiAccountJSON } from '../api_types/accounts'; -// To be replaced once ApiNotificationJSON type exists -interface FakeApiNotificationJSON { - type: string; - account: ApiAccountJSON; -} +import type { ApiNotificationJSON } from 'flavours/glitch/api_types/notifications'; export const notificationsUpdate = createAction( 'notifications/update', @@ -13,7 +8,7 @@ export const notificationsUpdate = createAction( playSound, ...args }: { - notification: FakeApiNotificationJSON; + notification: ApiNotificationJSON; usePendingItems: boolean; playSound: boolean; }) => ({ diff --git a/app/javascript/flavours/glitch/actions/streaming.js b/app/javascript/flavours/glitch/actions/streaming.js index a55240646f3e69..7b006c1be7c019 100644 --- a/app/javascript/flavours/glitch/actions/streaming.js +++ b/app/javascript/flavours/glitch/actions/streaming.js @@ -10,6 +10,7 @@ import { deleteAnnouncement, } from './announcements'; import { updateConversations } from './conversations'; +import { processNewNotificationForGroups } from './notification_groups'; import { updateNotifications, expandNotifications } from './notifications'; import { updateStatus } from './statuses'; import { @@ -98,10 +99,16 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti case 'delete': dispatch(deleteFromTimelines(data.payload)); break; - case 'notification': + case 'notification': { // @ts-expect-error - dispatch(updateNotifications(JSON.parse(data.payload), messages, locale)); + const notificationJSON = JSON.parse(data.payload); + dispatch(updateNotifications(notificationJSON, messages, locale)); + // TODO: remove this once the groups feature replaces the previous one + if(getState().notificationGroups.groups.length > 0) { + dispatch(processNewNotificationForGroups(notificationJSON)); + } break; + } case 'conversation': // @ts-expect-error dispatch(updateConversations(JSON.parse(data.payload))); diff --git a/app/javascript/flavours/glitch/api/notifications.ts b/app/javascript/flavours/glitch/api/notifications.ts new file mode 100644 index 00000000000000..fe718788220d44 --- /dev/null +++ b/app/javascript/flavours/glitch/api/notifications.ts @@ -0,0 +1,18 @@ +import api, { apiRequest, getLinks } from 'flavours/glitch/api'; +import type { ApiNotificationGroupJSON } from 'flavours/glitch/api_types/notifications'; + +export const apiFetchNotifications = async (params?: { + exclude_types?: string[]; + max_id?: string; +}) => { + const response = await api().request({ + method: 'GET', + url: '/api/v2_alpha/notifications', + params, + }); + + return { notifications: response.data, links: getLinks(response) }; +}; + +export const apiClearNotifications = () => + apiRequest('POST', 'v1/notifications/clear'); diff --git a/app/javascript/flavours/glitch/api_types/notifications.ts b/app/javascript/flavours/glitch/api_types/notifications.ts new file mode 100644 index 00000000000000..ea37556d8d0af0 --- /dev/null +++ b/app/javascript/flavours/glitch/api_types/notifications.ts @@ -0,0 +1,145 @@ +// See app/serializers/rest/notification_group_serializer.rb + +import type { AccountWarningAction } from 'flavours/glitch/models/notification_group'; + +import type { ApiAccountJSON } from './accounts'; +import type { ApiReportJSON } from './reports'; +import type { ApiStatusJSON } from './statuses'; + +// See app/model/notification.rb +export const allNotificationTypes = [ + 'follow', + 'follow_request', + 'favourite', + 'reblog', + 'mention', + 'poll', + 'status', + 'update', + 'admin.sign_up', + 'admin.report', + 'moderation_warning', + 'severed_relationships', +]; + +export type NotificationWithStatusType = + | 'favourite' + | 'reblog' + | 'status' + | 'mention' + | 'poll' + | 'update'; + +export type NotificationType = + | NotificationWithStatusType + | 'follow' + | 'follow_request' + | 'moderation_warning' + | 'severed_relationships' + | 'admin.sign_up' + | 'admin.report'; + +export interface BaseNotificationJSON { + id: string; + type: NotificationType; + created_at: string; + group_key: string; + account: ApiAccountJSON; +} + +export interface BaseNotificationGroupJSON { + group_key: string; + notifications_count: number; + type: NotificationType; + sample_accounts: ApiAccountJSON[]; + latest_page_notification_at: string; // FIXME: This will only be present if the notification group is returned in a paginated list, not requested directly + most_recent_notification_id: string; + page_min_id?: string; + page_max_id?: string; +} + +interface NotificationGroupWithStatusJSON extends BaseNotificationGroupJSON { + type: NotificationWithStatusType; + status: ApiStatusJSON; +} + +interface NotificationWithStatusJSON extends BaseNotificationJSON { + type: NotificationWithStatusType; + status: ApiStatusJSON; +} + +interface ReportNotificationGroupJSON extends BaseNotificationGroupJSON { + type: 'admin.report'; + report: ApiReportJSON; +} + +interface ReportNotificationJSON extends BaseNotificationJSON { + type: 'admin.report'; + report: ApiReportJSON; +} + +type SimpleNotificationTypes = 'follow' | 'follow_request' | 'admin.sign_up'; +interface SimpleNotificationGroupJSON extends BaseNotificationGroupJSON { + type: SimpleNotificationTypes; +} + +interface SimpleNotificationJSON extends BaseNotificationJSON { + type: SimpleNotificationTypes; +} + +export interface ApiAccountWarningJSON { + id: string; + action: AccountWarningAction; + text: string; + status_ids: string[]; + created_at: string; + target_account: ApiAccountJSON; + appeal: unknown; +} + +interface ModerationWarningNotificationGroupJSON + extends BaseNotificationGroupJSON { + type: 'moderation_warning'; + moderation_warning: ApiAccountWarningJSON; +} + +interface ModerationWarningNotificationJSON extends BaseNotificationJSON { + type: 'moderation_warning'; + moderation_warning: ApiAccountWarningJSON; +} + +export interface ApiAccountRelationshipSeveranceEventJSON { + id: string; + type: 'account_suspension' | 'domain_block' | 'user_domain_block'; + purged: boolean; + target_name: string; + followers_count: number; + following_count: number; + created_at: string; +} + +interface AccountRelationshipSeveranceNotificationGroupJSON + extends BaseNotificationGroupJSON { + type: 'severed_relationships'; + event: ApiAccountRelationshipSeveranceEventJSON; +} + +interface AccountRelationshipSeveranceNotificationJSON + extends BaseNotificationJSON { + type: 'severed_relationships'; + event: ApiAccountRelationshipSeveranceEventJSON; +} + +export type ApiNotificationJSON = + | SimpleNotificationJSON + | ReportNotificationJSON + | AccountRelationshipSeveranceNotificationJSON + | NotificationWithStatusJSON + | ModerationWarningNotificationJSON; + +export type ApiNotificationGroupJSON = + | SimpleNotificationGroupJSON + | ReportNotificationGroupJSON + | AccountRelationshipSeveranceNotificationGroupJSON + | NotificationGroupWithStatusJSON + | ModerationWarningNotificationGroupJSON; diff --git a/app/javascript/flavours/glitch/api_types/reports.ts b/app/javascript/flavours/glitch/api_types/reports.ts new file mode 100644 index 00000000000000..b11cfdd2eb59c8 --- /dev/null +++ b/app/javascript/flavours/glitch/api_types/reports.ts @@ -0,0 +1,16 @@ +import type { ApiAccountJSON } from './accounts'; + +export type ReportCategory = 'other' | 'spam' | 'legal' | 'violation'; + +export interface ApiReportJSON { + id: string; + action_taken: unknown; + action_taken_at: unknown; + category: ReportCategory; + comment: string; + forwarded: boolean; + created_at: string; + status_ids: string[]; + rule_ids: string[]; + target_account: ApiAccountJSON; +} diff --git a/app/javascript/flavours/glitch/components/account.jsx b/app/javascript/flavours/glitch/components/account.jsx index 038009cfa86e5a..e2ea8995242b3b 100644 --- a/app/javascript/flavours/glitch/components/account.jsx +++ b/app/javascript/flavours/glitch/components/account.jsx @@ -131,7 +131,7 @@ const Account = ({ size = 46, account, onFollow, onBlock, onMute, onMuteNotifica return (
- +
diff --git a/app/javascript/flavours/glitch/components/hover_card_controller.tsx b/app/javascript/flavours/glitch/components/hover_card_controller.tsx index 347dcd4f2f99a4..d2a636e939ca4b 100644 --- a/app/javascript/flavours/glitch/components/hover_card_controller.tsx +++ b/app/javascript/flavours/glitch/components/hover_card_controller.tsx @@ -43,6 +43,7 @@ export const HoverCardController: React.FC = () => { useEffect(() => { let isScrolling = false; let currentAnchor: HTMLElement | null = null; + let currentTitle: string | null = null; const open = (target: HTMLElement) => { target.setAttribute('aria-describedby', 'hover-card'); @@ -75,6 +76,9 @@ export const HoverCardController: React.FC = () => { currentAnchor?.removeAttribute('aria-describedby'); currentAnchor = target; + currentTitle = target.getAttribute('title'); + target.removeAttribute('title'); + setEnterTimeout(() => { open(target); }, enterDelay); @@ -90,11 +94,20 @@ export const HoverCardController: React.FC = () => { }; const handleMouseLeave = (e: MouseEvent) => { + const { target } = e; + if (!currentAnchor) { return; } - if (e.target === currentAnchor || e.target === cardRef.current) { + if ( + currentTitle && + target instanceof HTMLElement && + target === currentAnchor + ) + target.setAttribute('title', currentTitle); + + if (target === currentAnchor || target === cardRef.current) { cancelEnterTimeout(); setLeaveTimeout(() => { diff --git a/app/javascript/flavours/glitch/components/load_gap.tsx b/app/javascript/flavours/glitch/components/load_gap.tsx index f0d15d37761030..1870185c2914d9 100644 --- a/app/javascript/flavours/glitch/components/load_gap.tsx +++ b/app/javascript/flavours/glitch/components/load_gap.tsx @@ -9,18 +9,18 @@ const messages = defineMessages({ load_more: { id: 'status.load_more', defaultMessage: 'Load more' }, }); -interface Props { +interface Props { disabled: boolean; - maxId: string; - onClick: (maxId: string) => void; + param: T; + onClick: (params: T) => void; } -export const LoadGap: React.FC = ({ disabled, maxId, onClick }) => { +export const LoadGap = ({ disabled, param, onClick }: Props) => { const intl = useIntl(); const handleClick = useCallback(() => { - onClick(maxId); - }, [maxId, onClick]); + onClick(param); + }, [param, onClick]); return ( + ); +}; + +export const FilterBar: React.FC = () => { + const intl = useIntl(); + + const selectedFilter = useAppSelector( + selectSettingsNotificationsQuickFilterActive, + ); + const advancedMode = useAppSelector( + selectSettingsNotificationsQuickFilterAdvanced, + ); + + if (advancedMode) + return ( +
+ + + + + + + + + + + + + + + + + + + + + +
+ ); + else + return ( +
+ + + + + + +
+ ); +}; diff --git a/app/javascript/flavours/glitch/features/notifications_v2/index.tsx b/app/javascript/flavours/glitch/features/notifications_v2/index.tsx new file mode 100644 index 00000000000000..94051713751779 --- /dev/null +++ b/app/javascript/flavours/glitch/features/notifications_v2/index.tsx @@ -0,0 +1,354 @@ +import { useCallback, useEffect, useMemo, useRef } from 'react'; + +import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; + +import { Helmet } from 'react-helmet'; + +import { createSelector } from '@reduxjs/toolkit'; + +import { useDebouncedCallback } from 'use-debounce'; + +import DoneAllIcon from '@/material-icons/400-24px/done_all.svg?react'; +import NotificationsIcon from '@/material-icons/400-24px/notifications-fill.svg?react'; +import { + fetchNotificationsGap, + updateScrollPosition, + loadPending, + markNotificationsAsRead, + mountNotifications, + unmountNotifications, +} from 'flavours/glitch/actions/notification_groups'; +import { compareId } from 'flavours/glitch/compare_id'; +import { Icon } from 'flavours/glitch/components/icon'; +import { NotSignedInIndicator } from 'flavours/glitch/components/not_signed_in_indicator'; +import { useIdentity } from 'flavours/glitch/identity_context'; +import type { NotificationGap } from 'flavours/glitch/reducers/notification_groups'; +import { + selectUnreadNotificationGroupsCount, + selectPendingNotificationGroupsCount, +} from 'flavours/glitch/selectors/notifications'; +import { + selectNeedsNotificationPermission, + selectSettingsNotificationsExcludedTypes, + selectSettingsNotificationsQuickFilterActive, + selectSettingsNotificationsQuickFilterShow, + selectSettingsNotificationsShowUnread, +} from 'flavours/glitch/selectors/settings'; +import { useAppDispatch, useAppSelector } from 'flavours/glitch/store'; +import type { RootState } from 'flavours/glitch/store'; + +import { addColumn, removeColumn, moveColumn } from '../../actions/columns'; +import { submitMarkers } from '../../actions/markers'; +import Column from '../../components/column'; +import { ColumnHeader } from '../../components/column_header'; +import { LoadGap } from '../../components/load_gap'; +import ScrollableList from '../../components/scrollable_list'; +import { FilteredNotificationsBanner } from '../notifications/components/filtered_notifications_banner'; +import NotificationsPermissionBanner from '../notifications/components/notifications_permission_banner'; +import ColumnSettingsContainer from '../notifications/containers/column_settings_container'; + +import { NotificationGroup } from './components/notification_group'; +import { FilterBar } from './filter_bar'; + +const messages = defineMessages({ + title: { id: 'column.notifications', defaultMessage: 'Notifications' }, + markAsRead: { + id: 'notifications.mark_as_read', + defaultMessage: 'Mark every notification as read', + }, +}); + +const getNotifications = createSelector( + [ + selectSettingsNotificationsQuickFilterShow, + selectSettingsNotificationsQuickFilterActive, + selectSettingsNotificationsExcludedTypes, + (state: RootState) => state.notificationGroups.groups, + ], + (showFilterBar, allowedType, excludedTypes, notifications) => { + if (!showFilterBar || allowedType === 'all') { + // used if user changed the notification settings after loading the notifications from the server + // otherwise a list of notifications will come pre-filtered from the backend + // we need to turn it off for FilterBar in order not to block ourselves from seeing a specific category + return notifications.filter( + (item) => item.type === 'gap' || !excludedTypes.includes(item.type), + ); + } + return notifications.filter( + (item) => item.type === 'gap' || allowedType === item.type, + ); + }, +); + +export const Notifications: React.FC<{ + columnId?: string; + multiColumn?: boolean; +}> = ({ columnId, multiColumn }) => { + const intl = useIntl(); + const notifications = useAppSelector(getNotifications); + const dispatch = useAppDispatch(); + const isLoading = useAppSelector((s) => s.notificationGroups.isLoading); + const hasMore = notifications.at(-1)?.type === 'gap'; + + const lastReadId = useAppSelector((s) => + selectSettingsNotificationsShowUnread(s) + ? s.notificationGroups.lastReadId + : '0', + ); + + const numPending = useAppSelector(selectPendingNotificationGroupsCount); + + const unreadNotificationsCount = useAppSelector( + selectUnreadNotificationGroupsCount, + ); + + const isUnread = unreadNotificationsCount > 0; + + const canMarkAsRead = + useAppSelector(selectSettingsNotificationsShowUnread) && + unreadNotificationsCount > 0; + + const needsNotificationPermission = useAppSelector( + selectNeedsNotificationPermission, + ); + + const columnRef = useRef(null); + + const selectChild = useCallback((index: number, alignTop: boolean) => { + const container = columnRef.current?.node as HTMLElement | undefined; + + if (!container) return; + + const element = container.querySelector( + `article:nth-of-type(${index + 1}) .focusable`, + ); + + if (element) { + if (alignTop && container.scrollTop > element.offsetTop) { + element.scrollIntoView(true); + } else if ( + !alignTop && + container.scrollTop + container.clientHeight < + element.offsetTop + element.offsetHeight + ) { + element.scrollIntoView(false); + } + element.focus(); + } + }, []); + + // Keep track of mounted components for unread notification handling + useEffect(() => { + dispatch(mountNotifications()); + + return () => { + dispatch(unmountNotifications()); + dispatch(updateScrollPosition({ top: false })); + }; + }, [dispatch]); + + const handleLoadGap = useCallback( + (gap: NotificationGap) => { + void dispatch(fetchNotificationsGap({ gap })); + }, + [dispatch], + ); + + const handleLoadOlder = useDebouncedCallback( + () => { + const gap = notifications.at(-1); + if (gap?.type === 'gap') void dispatch(fetchNotificationsGap({ gap })); + }, + 300, + { leading: true }, + ); + + const handleLoadPending = useCallback(() => { + dispatch(loadPending()); + }, [dispatch]); + + const handleScrollToTop = useDebouncedCallback(() => { + dispatch(updateScrollPosition({ top: true })); + }, 100); + + const handleScroll = useDebouncedCallback(() => { + dispatch(updateScrollPosition({ top: false })); + }, 100); + + useEffect(() => { + return () => { + handleLoadOlder.cancel(); + handleScrollToTop.cancel(); + handleScroll.cancel(); + }; + }, [handleLoadOlder, handleScrollToTop, handleScroll]); + + const handlePin = useCallback(() => { + if (columnId) { + dispatch(removeColumn(columnId)); + } else { + dispatch(addColumn('NOTIFICATIONS', {})); + } + }, [columnId, dispatch]); + + const handleMove = useCallback( + (dir: unknown) => { + dispatch(moveColumn(columnId, dir)); + }, + [dispatch, columnId], + ); + + const handleHeaderClick = useCallback(() => { + columnRef.current?.scrollTop(); + }, []); + + const handleMoveUp = useCallback( + (id: string) => { + const elementIndex = + notifications.findIndex( + (item) => item.type !== 'gap' && item.group_key === id, + ) - 1; + selectChild(elementIndex, true); + }, + [notifications, selectChild], + ); + + const handleMoveDown = useCallback( + (id: string) => { + const elementIndex = + notifications.findIndex( + (item) => item.type !== 'gap' && item.group_key === id, + ) + 1; + selectChild(elementIndex, false); + }, + [notifications, selectChild], + ); + + const handleMarkAsRead = useCallback(() => { + dispatch(markNotificationsAsRead()); + void dispatch(submitMarkers({ immediate: true })); + }, [dispatch]); + + const pinned = !!columnId; + const emptyMessage = ( + + ); + + const { signedIn } = useIdentity(); + + const filterBar = signedIn ? : null; + + const scrollableContent = useMemo(() => { + if (notifications.length === 0 && !hasMore) return null; + + return notifications.map((item) => + item.type === 'gap' ? ( + + ) : ( + 0 + } + /> + ), + ); + }, [ + notifications, + isLoading, + hasMore, + lastReadId, + handleLoadGap, + handleMoveUp, + handleMoveDown, + ]); + + const prepend = ( + <> + {needsNotificationPermission && } + + + ); + + const scrollContainer = signedIn ? ( + + {scrollableContent} + + ) : ( + + ); + + const extraButton = canMarkAsRead ? ( + + ) : null; + + return ( + + + + + + {filterBar} + + {scrollContainer} + + + {intl.formatMessage(messages.title)} + + + + ); +}; + +// eslint-disable-next-line import/no-default-export +export default Notifications; diff --git a/app/javascript/flavours/glitch/features/notifications_wrapper.jsx b/app/javascript/flavours/glitch/features/notifications_wrapper.jsx new file mode 100644 index 00000000000000..15ab3367cc1bf8 --- /dev/null +++ b/app/javascript/flavours/glitch/features/notifications_wrapper.jsx @@ -0,0 +1,13 @@ +import Notifications from 'flavours/glitch/features/notifications'; +import Notifications_v2 from 'flavours/glitch/features/notifications_v2'; +import { useAppSelector } from 'flavours/glitch/store'; + +export const NotificationsWrapper = (props) => { + const optedInGroupedNotifications = useAppSelector((state) => state.getIn(['settings', 'notifications', 'groupingBeta'], false)); + + return ( + optedInGroupedNotifications ? : + ); +}; + +export default NotificationsWrapper; \ No newline at end of file diff --git a/app/javascript/flavours/glitch/features/status/components/card.jsx b/app/javascript/flavours/glitch/features/status/components/card.jsx index 0d315cbbf10ad9..933f2b1045b559 100644 --- a/app/javascript/flavours/glitch/features/status/components/card.jsx +++ b/app/javascript/flavours/glitch/features/status/components/card.jsx @@ -130,7 +130,7 @@ export default class Card extends PureComponent { const showAuthor = !!card.getIn(['authors', 0, 'accountId']); const description = ( -
+
{provider} {card.get('published_at') && <> · } diff --git a/app/javascript/flavours/glitch/features/ui/components/columns_area.jsx b/app/javascript/flavours/glitch/features/ui/components/columns_area.jsx index 9166499c5a08b9..e4c67ed65ef728 100644 --- a/app/javascript/flavours/glitch/features/ui/components/columns_area.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/columns_area.jsx @@ -10,7 +10,7 @@ import { scrollRight } from '../../../scroll'; import BundleContainer from '../containers/bundle_container'; import { Compose, - Notifications, + NotificationsWrapper, HomeTimeline, CommunityTimeline, PublicTimeline, @@ -32,7 +32,7 @@ import NavigationPanel from './navigation_panel'; const componentMap = { 'COMPOSE': Compose, 'HOME': HomeTimeline, - 'NOTIFICATIONS': Notifications, + 'NOTIFICATIONS': NotificationsWrapper, 'PUBLIC': PublicTimeline, 'REMOTE': PublicTimeline, 'COMMUNITY': CommunityTimeline, diff --git a/app/javascript/flavours/glitch/features/ui/components/navigation_panel.jsx b/app/javascript/flavours/glitch/features/ui/components/navigation_panel.jsx index 98d82342cf3b6e..6153b3ceaa7c4e 100644 --- a/app/javascript/flavours/glitch/features/ui/components/navigation_panel.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/navigation_panel.jsx @@ -33,6 +33,7 @@ import { NavigationPortal } from 'flavours/glitch/components/navigation_portal'; import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; import { timelinePreview, trendsEnabled } from 'flavours/glitch/initial_state'; import { transientSingleColumn } from 'flavours/glitch/is_mobile'; +import { selectUnreadNotificationGroupsCount } from 'flavours/glitch/selectors/notifications'; import { preferencesLink } from 'flavours/glitch/utils/backend_links'; import ColumnLink from './column_link'; @@ -60,15 +61,19 @@ const messages = defineMessages({ }); const NotificationsLink = () => { + const optedInGroupedNotifications = useSelector((state) => state.getIn(['settings', 'notifications', 'groupingBeta'], false)); const count = useSelector(state => state.getIn(['local_settings', 'notifications', 'tab_badge']) ? state.getIn(['notifications', 'unread']) : 0); const intl = useIntl(); + const newCount = useSelector(selectUnreadNotificationGroupsCount); + return ( } - activeIcon={} + icon={} + activeIcon={} text={intl.formatMessage(messages.notifications)} /> ); diff --git a/app/javascript/flavours/glitch/features/ui/index.jsx b/app/javascript/flavours/glitch/features/ui/index.jsx index 747922f23e2dc9..7a2aa21f8812c7 100644 --- a/app/javascript/flavours/glitch/features/ui/index.jsx +++ b/app/javascript/flavours/glitch/features/ui/index.jsx @@ -12,8 +12,9 @@ import Favico from 'favico.js'; import { debounce } from 'lodash'; import { HotKeys } from 'react-hotkeys'; -import { changeLayout } from 'flavours/glitch/actions/app'; +import { focusApp, unfocusApp, changeLayout } from 'flavours/glitch/actions/app'; import { synchronouslySubmitMarkers, submitMarkers, fetchMarkers } from 'flavours/glitch/actions/markers'; +import { initializeNotifications } from 'flavours/glitch/actions/notifications_migration'; import { INTRODUCTION_VERSION } from 'flavours/glitch/actions/onboarding'; import { HoverCardController } from 'flavours/glitch/components/hover_card_controller'; import { Permalink } from 'flavours/glitch/components/permalink'; @@ -24,10 +25,10 @@ import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router'; import { uploadCompose, resetCompose, changeComposeSpoilerness } from '../../actions/compose'; import { clearHeight } from '../../actions/height_cache'; -import { expandNotifications, notificationsSetVisibility } from '../../actions/notifications'; +import { notificationsSetVisibility } from '../../actions/notifications'; import { fetchServer, fetchServerTranslationLanguages } from '../../actions/server'; import { expandHomeTimeline } from '../../actions/timelines'; -import initialState, { me, owner, singleUserMode, trendsEnabled, trendsAsLanding } from '../../initial_state'; +import initialState, { me, owner, singleUserMode, trendsEnabled, trendsAsLanding, disableHoverCards } from '../../initial_state'; import BundleColumnError from './components/bundle_column_error'; import Header from './components/header'; @@ -51,7 +52,7 @@ import { Favourites, DirectTimeline, HashtagTimeline, - Notifications, + NotificationsWrapper, NotificationRequests, NotificationRequest, FollowRequests, @@ -74,6 +75,7 @@ import { } from './util/async-components'; import { ColumnsContextProvider } from './util/columns_context'; import { WrappedSwitch, WrappedRoute } from './util/react_router_helpers'; + // 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'; @@ -214,7 +216,7 @@ class SwitchingColumnsArea extends PureComponent { - + @@ -304,7 +306,10 @@ class UI extends PureComponent { const visibility = !document[this.visibilityHiddenProp]; this.props.dispatch(notificationsSetVisibility(visibility)); if (visibility) { + this.props.dispatch(focusApp()); this.props.dispatch(submitMarkers({ immediate: true })); + } else { + this.props.dispatch(unfocusApp()); } }; @@ -419,7 +424,7 @@ class UI extends PureComponent { if (signedIn) { this.props.dispatch(fetchMarkers()); this.props.dispatch(expandHomeTimeline()); - this.props.dispatch(expandNotifications()); + this.props.dispatch(initializeNotifications()); this.props.dispatch(fetchServerTranslationLanguages()); setTimeout(() => this.props.dispatch(fetchServer()), 3000); @@ -651,7 +656,7 @@ class UI extends PureComponent { {layout !== 'mobile' && } - + {!disableHoverCards && } diff --git a/app/javascript/flavours/glitch/features/ui/util/async-components.js b/app/javascript/flavours/glitch/features/ui/util/async-components.js index a312cefff7dcfb..e334e1a3b6ea38 100644 --- a/app/javascript/flavours/glitch/features/ui/util/async-components.js +++ b/app/javascript/flavours/glitch/features/ui/util/async-components.js @@ -7,7 +7,15 @@ export function Compose () { } export function Notifications () { - return import(/* webpackChunkName: "flavours/glitch/async/notifications" */'../../notifications'); + return import(/* webpackChunkName: "flavours/glitch/async/notifications_v1" */'../../notifications'); +} + +export function Notifications_v2 () { + return import(/* webpackChunkName: "flavours/glitch/async/notifications_v2" */'../../notifications_v2'); +} + +export function NotificationsWrapper () { + return import(/* webpackChunkName: "flavours/glitch/async/notifications" */'../../notifications_wrapper'); } export function HomeTimeline () { diff --git a/app/javascript/flavours/glitch/initial_state.js b/app/javascript/flavours/glitch/initial_state.js index 4492813fd3a6ce..c5628f51ce475c 100644 --- a/app/javascript/flavours/glitch/initial_state.js +++ b/app/javascript/flavours/glitch/initial_state.js @@ -17,6 +17,7 @@ * @property {boolean} crop_images * @property {boolean=} delete_modal * @property {boolean=} disable_swiping + * @property {boolean=} disable_hover_cards * @property {string=} disabled_account_id * @property {string} display_media * @property {string} domain @@ -106,6 +107,7 @@ export const boostModal = getMeta('boost_modal'); export const cropImages = getMeta('crop_images'); export const deleteModal = getMeta('delete_modal'); export const disableSwiping = getMeta('disable_swiping'); +export const disableHoverCards = getMeta('disable_hover_cards'); export const disabledAccountId = getMeta('disabled_account_id'); export const displayMedia = getMeta('display_media'); export const domain = getMeta('domain'); diff --git a/app/javascript/flavours/glitch/locales/de.json b/app/javascript/flavours/glitch/locales/de.json index caad1ebcfe1ebe..6a20c8c396fda3 100644 --- a/app/javascript/flavours/glitch/locales/de.json +++ b/app/javascript/flavours/glitch/locales/de.json @@ -154,6 +154,5 @@ "status.in_reply_to": "Dieser Toot ist eine Antwort", "status.is_poll": "Dieser Toot ist eine Umfrage", "status.local_only": "Nur auf deiner Instanz sichtbar", - "status.uncollapse": "Ausklappen", - "suggestions.dismiss": "Vorschlag ablehnen" + "status.uncollapse": "Ausklappen" } diff --git a/app/javascript/flavours/glitch/locales/es-AR.json b/app/javascript/flavours/glitch/locales/es-AR.json index 95dc7c85a6fdaf..706109d6e86fd5 100644 --- a/app/javascript/flavours/glitch/locales/es-AR.json +++ b/app/javascript/flavours/glitch/locales/es-AR.json @@ -155,6 +155,5 @@ "status.in_reply_to": "Esta publicaciĂ³n es una respuesta", "status.is_poll": "Esta publicaciĂ³n es una encuesta", "status.local_only": "SĂ³lo visible para tu instancia", - "status.uncollapse": "Descolapsar", - "suggestions.dismiss": "Descartar sugerencia" + "status.uncollapse": "Descolapsar" } diff --git a/app/javascript/flavours/glitch/locales/ko.json b/app/javascript/flavours/glitch/locales/ko.json index b1da79d102e65c..18e61dc03418eb 100644 --- a/app/javascript/flavours/glitch/locales/ko.json +++ b/app/javascript/flavours/glitch/locales/ko.json @@ -25,6 +25,9 @@ "compose.content-type.plain_meta": "고급 ́–‘́‹ ́—†́´ ́‘́„±", "compose.disable_threaded_mode": "ê¸€íƒ€ë˜ ëª¨ë“œ 비활́„±í™”", "compose.enable_threaded_mode": "ê¸€íƒ€ë˜ ëª¨ë“œ 활́„±í™”", + "compose_form.sensitive.hide": "{count, plural, other {미디́–´ë¥¼ 민ê°í•΅œ¼ë¡œ í‘œ́‹œ}}", + "compose_form.sensitive.marked": "{count, plural, other {미디́–´ê°€ 민ê°í•΅œ¼ë¡œ í‘œ́‹œë˜́—ˆ́µë‹ˆë‹¤}}", + "compose_form.sensitive.unmarked": "{count, plural, other {미디́–´ê°€ 민ê°í•΅œ¼ë¡œ í‘œ́‹œë˜́§€ ́•́•˜́µë‹ˆë‹¤}}", "confirmation_modal.do_not_ask_again": "다́Œë¶€í„° 확́¸́°½́„ ë„́°́§€ ́•ê¸°", "confirmations.deprecated_settings.confirm": "마́¤í† ëˆ ́„¤́ • ́‚¬́©", "confirmations.deprecated_settings.message": "́‚¬́©í•˜ë˜ 몇몇 기기별 글리́¹˜ {app_settings}́€ 마́¤í† ëˆ {preferences}́œ¼ë¡œ 대́²´ë˜́—ˆ́µë‹ˆë‹¤:", @@ -61,6 +64,7 @@ "notification_purge.btn_invert": "́„ íƒë°˜́ „", "notification_purge.btn_none": "́ „́²´́„ íƒí•´́ œ", "notification_purge.start": "́•Œë¦¼ ́‚­́ œëª¨ë“œë¡œ 들́–´ê°€ê¸°", + "notifications.column_settings.filter_bar.show_bar": "í•„í„° 막대 í‘œ́‹œ", "notifications.marked_clear": "́„ íƒëœ ́•Œë¦¼ ëª¨ë‘ ́‚­́ œ", "notifications.marked_clear_confirmation": "́ •ë§ë¡œ ́„ íƒëœ ́•Œë¦¼ë“¤́„ ́˜êµ¬́ ́œ¼ë¡œ ́‚­́ œí• ê¹Œ́”?", "settings.always_show_spoilers_field": "́—´ëŒ́£¼́˜ 항목́„ ́–¸́ œë‚˜ 활́„±í™”", @@ -124,6 +128,7 @@ "settings.shared_settings_link": "́‚¬́©́ ́„¤́ •", "settings.show_action_bar": "́ ‘íŒ ê¸€́— ́•¡́…˜ 버í¼ë“¤ ë³´́´ê¸°", "settings.show_content_type_choice": "글́„ ́‘́„±í•  ë•Œ ́½˜í…í¸ íƒ€́…́„ 고를 ́ˆ˜ ́ˆë„ë¡ í•©ë‹ˆë‹¤", + "settings.show_published_toast": "게́‹œë¬¼́„ 게́‹œ/́ €́¥í•  ë•Œ 토́¤í¸ í‘œ́‹œ", "settings.show_reply_counter": "대ëµ́ ́¸ 답글 ê°œ́ˆ˜ë¥¼ í‘œ́‹œí•©ë‹ˆë‹¤", "settings.side_arm": "ë³´́¡° ́‘́„± 버í¼:", "settings.side_arm.none": "́—†́Œ", diff --git a/app/javascript/flavours/glitch/locales/zh-CN.json b/app/javascript/flavours/glitch/locales/zh-CN.json index 26f142807abd88..e9999136fb97b7 100644 --- a/app/javascript/flavours/glitch/locales/zh-CN.json +++ b/app/javascript/flavours/glitch/locales/zh-CN.json @@ -155,6 +155,5 @@ "status.in_reply_to": "此嘟文是å›å¤", "status.is_poll": "此嘟文是æ•ç¥¨", "status.local_only": "此嘟文仅本站å¯è§", - "status.uncollapse": "展开", - "suggestions.dismiss": "关闭建议" + "status.uncollapse": "展开" } diff --git a/app/javascript/flavours/glitch/locales/zh-TW.json b/app/javascript/flavours/glitch/locales/zh-TW.json index 2fcb217434afd4..aaf00651506c40 100644 --- a/app/javascript/flavours/glitch/locales/zh-TW.json +++ b/app/javascript/flavours/glitch/locales/zh-TW.json @@ -151,6 +151,5 @@ "status.in_reply_to": "貼文有å›è¦†", "status.is_poll": "貼文有æ•ç¥¨", "status.local_only": "åªåœ¨æ­¤å¯¦ä¾‹å¯è¦‹", - "status.uncollapse": "展開", - "suggestions.dismiss": "關閉建議" + "status.uncollapse": "展開" } diff --git a/app/javascript/flavours/glitch/models/notification_group.ts b/app/javascript/flavours/glitch/models/notification_group.ts new file mode 100644 index 00000000000000..6c8b8eb6e3d555 --- /dev/null +++ b/app/javascript/flavours/glitch/models/notification_group.ts @@ -0,0 +1,207 @@ +import type { + ApiAccountRelationshipSeveranceEventJSON, + ApiAccountWarningJSON, + BaseNotificationGroupJSON, + ApiNotificationGroupJSON, + ApiNotificationJSON, + NotificationType, + NotificationWithStatusType, +} from 'flavours/glitch/api_types/notifications'; +import type { ApiReportJSON } from 'flavours/glitch/api_types/reports'; + +// Maximum number of avatars displayed in a notification group +// This corresponds to the max lenght of `group.sampleAccountIds` +export const NOTIFICATIONS_GROUP_MAX_AVATARS = 8; + +interface BaseNotificationGroup + extends Omit { + sampleAccountIds: string[]; +} + +interface BaseNotificationWithStatus + extends BaseNotificationGroup { + type: Type; + statusId: string; +} + +interface BaseNotification + extends BaseNotificationGroup { + type: Type; +} + +export type NotificationGroupFavourite = + BaseNotificationWithStatus<'favourite'>; +export type NotificationGroupReblog = BaseNotificationWithStatus<'reblog'>; +export type NotificationGroupStatus = BaseNotificationWithStatus<'status'>; +export type NotificationGroupMention = BaseNotificationWithStatus<'mention'>; +export type NotificationGroupPoll = BaseNotificationWithStatus<'poll'>; +export type NotificationGroupUpdate = BaseNotificationWithStatus<'update'>; +export type NotificationGroupFollow = BaseNotification<'follow'>; +export type NotificationGroupFollowRequest = BaseNotification<'follow_request'>; +export type NotificationGroupAdminSignUp = BaseNotification<'admin.sign_up'>; + +export type AccountWarningAction = + | 'none' + | 'disable' + | 'mark_statuses_as_sensitive' + | 'delete_statuses' + | 'sensitive' + | 'silence' + | 'suspend'; +export interface AccountWarning + extends Omit { + targetAccountId: string; +} + +export interface NotificationGroupModerationWarning + extends BaseNotification<'moderation_warning'> { + moderationWarning: AccountWarning; +} + +type AccountRelationshipSeveranceEvent = + ApiAccountRelationshipSeveranceEventJSON; +export interface NotificationGroupSeveredRelationships + extends BaseNotification<'severed_relationships'> { + event: AccountRelationshipSeveranceEvent; +} + +interface Report extends Omit { + targetAccountId: string; +} + +export interface NotificationGroupAdminReport + extends BaseNotification<'admin.report'> { + report: Report; +} + +export type NotificationGroup = + | NotificationGroupFavourite + | NotificationGroupReblog + | NotificationGroupStatus + | NotificationGroupMention + | NotificationGroupPoll + | NotificationGroupUpdate + | NotificationGroupFollow + | NotificationGroupFollowRequest + | NotificationGroupModerationWarning + | NotificationGroupSeveredRelationships + | NotificationGroupAdminSignUp + | NotificationGroupAdminReport; + +function createReportFromJSON(reportJSON: ApiReportJSON): Report { + const { target_account, ...report } = reportJSON; + return { + targetAccountId: target_account.id, + ...report, + }; +} + +function createAccountWarningFromJSON( + warningJSON: ApiAccountWarningJSON, +): AccountWarning { + const { target_account, ...warning } = warningJSON; + return { + targetAccountId: target_account.id, + ...warning, + }; +} + +function createAccountRelationshipSeveranceEventFromJSON( + eventJson: ApiAccountRelationshipSeveranceEventJSON, +): AccountRelationshipSeveranceEvent { + return eventJson; +} + +export function createNotificationGroupFromJSON( + groupJson: ApiNotificationGroupJSON, +): NotificationGroup { + const { sample_accounts, ...group } = groupJson; + const sampleAccountIds = sample_accounts.map((account) => account.id); + + switch (group.type) { + case 'favourite': + case 'reblog': + case 'status': + case 'mention': + case 'poll': + case 'update': { + const { status, ...groupWithoutStatus } = group; + return { + statusId: status.id, + sampleAccountIds, + ...groupWithoutStatus, + }; + } + case 'admin.report': { + const { report, ...groupWithoutTargetAccount } = group; + return { + report: createReportFromJSON(report), + sampleAccountIds, + ...groupWithoutTargetAccount, + }; + } + case 'severed_relationships': + return { + ...group, + event: createAccountRelationshipSeveranceEventFromJSON(group.event), + sampleAccountIds, + }; + + case 'moderation_warning': { + const { moderation_warning, ...groupWithoutModerationWarning } = group; + return { + ...groupWithoutModerationWarning, + moderationWarning: createAccountWarningFromJSON(moderation_warning), + sampleAccountIds, + }; + } + default: + return { + sampleAccountIds, + ...group, + }; + } +} + +export function createNotificationGroupFromNotificationJSON( + notification: ApiNotificationJSON, +) { + const group = { + sampleAccountIds: [notification.account.id], + group_key: notification.group_key, + notifications_count: 1, + type: notification.type, + most_recent_notification_id: notification.id, + page_min_id: notification.id, + page_max_id: notification.id, + latest_page_notification_at: notification.created_at, + } as NotificationGroup; + + switch (notification.type) { + case 'favourite': + case 'reblog': + case 'status': + case 'mention': + case 'poll': + case 'update': + return { ...group, statusId: notification.status.id }; + case 'admin.report': + return { ...group, report: createReportFromJSON(notification.report) }; + case 'severed_relationships': + return { + ...group, + event: createAccountRelationshipSeveranceEventFromJSON( + notification.event, + ), + }; + case 'moderation_warning': + return { + ...group, + moderationWarning: createAccountWarningFromJSON( + notification.moderation_warning, + ), + }; + default: + return group; + } +} diff --git a/app/javascript/flavours/glitch/reducers/index.ts b/app/javascript/flavours/glitch/reducers/index.ts index 3fee5818f981d5..d8d50be7d21621 100644 --- a/app/javascript/flavours/glitch/reducers/index.ts +++ b/app/javascript/flavours/glitch/reducers/index.ts @@ -25,6 +25,7 @@ import { markersReducer } from './markers'; import media_attachments from './media_attachments'; import meta from './meta'; import { modalReducer } from './modal'; +import { notificationGroupsReducer } from './notification_groups'; import { notificationPolicyReducer } from './notification_policy'; import { notificationRequestsReducer } from './notification_requests'; import notifications from './notifications'; @@ -68,6 +69,7 @@ const reducers = { search, media_attachments, notifications, + notificationGroups: notificationGroupsReducer, height_cache, custom_emojis, lists, diff --git a/app/javascript/flavours/glitch/reducers/markers.ts b/app/javascript/flavours/glitch/reducers/markers.ts index 380e9d39952378..8b997e47be2eab 100644 --- a/app/javascript/flavours/glitch/reducers/markers.ts +++ b/app/javascript/flavours/glitch/reducers/markers.ts @@ -1,6 +1,10 @@ import { createReducer } from '@reduxjs/toolkit'; -import { submitMarkersAction } from 'flavours/glitch/actions/markers'; +import { + submitMarkersAction, + fetchMarkers, +} from 'flavours/glitch/actions/markers'; +import { compareId } from 'flavours/glitch/compare_id'; const initialState = { home: '0', @@ -15,4 +19,23 @@ export const markersReducer = createReducer(initialState, (builder) => { if (notifications) state.notifications = notifications; }, ); + builder.addCase( + fetchMarkers.fulfilled, + ( + state, + { + payload: { + markers: { home, notifications }, + }, + }, + ) => { + if (home && compareId(home.last_read_id, state.home) > 0) + state.home = home.last_read_id; + if ( + notifications && + compareId(notifications.last_read_id, state.notifications) > 0 + ) + state.notifications = notifications.last_read_id; + }, + ); }); diff --git a/app/javascript/flavours/glitch/reducers/notification_groups.ts b/app/javascript/flavours/glitch/reducers/notification_groups.ts new file mode 100644 index 00000000000000..b0b284b696e4bb --- /dev/null +++ b/app/javascript/flavours/glitch/reducers/notification_groups.ts @@ -0,0 +1,508 @@ +import { createReducer, isAnyOf } from '@reduxjs/toolkit'; + +import { + authorizeFollowRequestSuccess, + blockAccountSuccess, + muteAccountSuccess, + rejectFollowRequestSuccess, +} from 'flavours/glitch/actions/accounts_typed'; +import { focusApp, unfocusApp } from 'flavours/glitch/actions/app'; +import { blockDomainSuccess } from 'flavours/glitch/actions/domain_blocks_typed'; +import { fetchMarkers } from 'flavours/glitch/actions/markers'; +import { + clearNotifications, + fetchNotifications, + fetchNotificationsGap, + processNewNotificationForGroups, + loadPending, + updateScrollPosition, + markNotificationsAsRead, + mountNotifications, + unmountNotifications, +} from 'flavours/glitch/actions/notification_groups'; +import { + disconnectTimeline, + timelineDelete, +} from 'flavours/glitch/actions/timelines_typed'; +import type { ApiNotificationJSON } from 'flavours/glitch/api_types/notifications'; +import { compareId } from 'flavours/glitch/compare_id'; +import { usePendingItems } from 'flavours/glitch/initial_state'; +import { + NOTIFICATIONS_GROUP_MAX_AVATARS, + createNotificationGroupFromJSON, + createNotificationGroupFromNotificationJSON, +} from 'flavours/glitch/models/notification_group'; +import type { NotificationGroup } from 'flavours/glitch/models/notification_group'; + +const NOTIFICATIONS_TRIM_LIMIT = 50; + +export interface NotificationGap { + type: 'gap'; + maxId?: string; + sinceId?: string; +} + +interface NotificationGroupsState { + groups: (NotificationGroup | NotificationGap)[]; + pendingGroups: (NotificationGroup | NotificationGap)[]; + scrolledToTop: boolean; + isLoading: boolean; + lastReadId: string; + mounted: number; + isTabVisible: boolean; +} + +const initialState: NotificationGroupsState = { + groups: [], + pendingGroups: [], // holds pending groups in slow mode + scrolledToTop: false, + isLoading: false, + // The following properties are used to track unread notifications + lastReadId: '0', // used for unread notifications + mounted: 0, // number of mounted notification list components, usually 0 or 1 + isTabVisible: true, +}; + +function filterNotificationsForAccounts( + groups: NotificationGroupsState['groups'], + accountIds: string[], + onlyForType?: string, +) { + groups = groups + .map((group) => { + if ( + group.type !== 'gap' && + (!onlyForType || group.type === onlyForType) + ) { + const previousLength = group.sampleAccountIds.length; + + group.sampleAccountIds = group.sampleAccountIds.filter( + (id) => !accountIds.includes(id), + ); + + const newLength = group.sampleAccountIds.length; + const removed = previousLength - newLength; + + group.notifications_count -= removed; + } + + return group; + }) + .filter( + (group) => group.type === 'gap' || group.sampleAccountIds.length > 0, + ); + mergeGaps(groups); + return groups; +} + +function filterNotificationsForStatus( + groups: NotificationGroupsState['groups'], + statusId: string, +) { + groups = groups.filter( + (group) => + group.type === 'gap' || + !('statusId' in group) || + group.statusId !== statusId, + ); + mergeGaps(groups); + return groups; +} + +function removeNotificationsForAccounts( + state: NotificationGroupsState, + accountIds: string[], + onlyForType?: string, +) { + state.groups = filterNotificationsForAccounts( + state.groups, + accountIds, + onlyForType, + ); + state.pendingGroups = filterNotificationsForAccounts( + state.pendingGroups, + accountIds, + onlyForType, + ); +} + +function removeNotificationsForStatus( + state: NotificationGroupsState, + statusId: string, +) { + state.groups = filterNotificationsForStatus(state.groups, statusId); + state.pendingGroups = filterNotificationsForStatus( + state.pendingGroups, + statusId, + ); +} + +function isNotificationGroup( + groupOrGap: NotificationGroup | NotificationGap, +): groupOrGap is NotificationGroup { + return groupOrGap.type !== 'gap'; +} + +// Merge adjacent gaps in `groups` in-place +function mergeGaps(groups: NotificationGroupsState['groups']) { + for (let i = 0; i < groups.length; i++) { + const firstGroupOrGap = groups[i]; + + if (firstGroupOrGap?.type === 'gap') { + let lastGap = firstGroupOrGap; + let j = i + 1; + + for (; j < groups.length; j++) { + const groupOrGap = groups[j]; + if (groupOrGap?.type === 'gap') lastGap = groupOrGap; + else break; + } + + if (j - i > 1) { + groups.splice(i, j - i, { + type: 'gap', + maxId: firstGroupOrGap.maxId, + sinceId: lastGap.sinceId, + }); + } + } + } +} + +// Checks if `groups[index-1]` and `groups[index]` are gaps, and merge them in-place if they are +function mergeGapsAround( + groups: NotificationGroupsState['groups'], + index: number, +) { + if (index > 0) { + const potentialFirstGap = groups[index - 1]; + const potentialSecondGap = groups[index]; + + if ( + potentialFirstGap?.type === 'gap' && + potentialSecondGap?.type === 'gap' + ) { + groups.splice(index - 1, 2, { + type: 'gap', + maxId: potentialFirstGap.maxId, + sinceId: potentialSecondGap.sinceId, + }); + } + } +} + +function processNewNotification( + groups: NotificationGroupsState['groups'], + notification: ApiNotificationJSON, +) { + const existingGroupIndex = groups.findIndex( + (group) => + group.type !== 'gap' && group.group_key === notification.group_key, + ); + + // In any case, we are going to add a group at the top + // If there is currently a gap at the top, now is the time to update it + if (groups.length > 0 && groups[0]?.type === 'gap') { + groups[0].maxId = notification.id; + } + + if (existingGroupIndex > -1) { + const existingGroup = groups[existingGroupIndex]; + + if ( + existingGroup && + existingGroup.type !== 'gap' && + !existingGroup.sampleAccountIds.includes(notification.account.id) // This can happen for example if you like, then unlike, then like again the same post + ) { + // Update the existing group + if ( + existingGroup.sampleAccountIds.unshift(notification.account.id) > + NOTIFICATIONS_GROUP_MAX_AVATARS + ) + existingGroup.sampleAccountIds.pop(); + + existingGroup.most_recent_notification_id = notification.id; + existingGroup.page_max_id = notification.id; + existingGroup.latest_page_notification_at = notification.created_at; + existingGroup.notifications_count += 1; + + groups.splice(existingGroupIndex, 1); + mergeGapsAround(groups, existingGroupIndex); + + groups.unshift(existingGroup); + } + } else { + // Create a new group + groups.unshift(createNotificationGroupFromNotificationJSON(notification)); + } +} + +function trimNotifications(state: NotificationGroupsState) { + if (state.scrolledToTop) { + state.groups.splice(NOTIFICATIONS_TRIM_LIMIT); + } +} + +function shouldMarkNewNotificationsAsRead( + { + isTabVisible, + scrolledToTop, + mounted, + lastReadId, + groups, + }: NotificationGroupsState, + ignoreScroll = false, +) { + const isMounted = mounted > 0; + const oldestGroup = groups.findLast(isNotificationGroup); + const hasMore = groups.at(-1)?.type === 'gap'; + const oldestGroupReached = + !hasMore || + lastReadId === '0' || + (oldestGroup?.page_min_id && + compareId(oldestGroup.page_min_id, lastReadId) <= 0); + + return ( + isTabVisible && + (ignoreScroll || scrolledToTop) && + isMounted && + oldestGroupReached + ); +} + +function updateLastReadId( + state: NotificationGroupsState, + group: NotificationGroup | undefined = undefined, +) { + if (shouldMarkNewNotificationsAsRead(state)) { + group = group ?? state.groups.find(isNotificationGroup); + if ( + group?.page_max_id && + compareId(state.lastReadId, group.page_max_id) < 0 + ) + state.lastReadId = group.page_max_id; + } +} + +export const notificationGroupsReducer = createReducer( + initialState, + (builder) => { + builder + .addCase(fetchNotifications.fulfilled, (state, action) => { + state.groups = action.payload.map((json) => + json.type === 'gap' ? json : createNotificationGroupFromJSON(json), + ); + state.isLoading = false; + updateLastReadId(state); + }) + .addCase(fetchNotificationsGap.fulfilled, (state, action) => { + const { notifications } = action.payload; + + // find the gap in the existing notifications + const gapIndex = state.groups.findIndex( + (groupOrGap) => + groupOrGap.type === 'gap' && + groupOrGap.sinceId === action.meta.arg.gap.sinceId && + groupOrGap.maxId === action.meta.arg.gap.maxId, + ); + + if (gapIndex < 0) + // We do not know where to insert, let's return + return; + + // Filling a disconnection gap means we're getting historical data + // about groups we may know or may not know about. + + // The notifications timeline is split in two by the gap, with + // group information newer than the gap, and group information older + // than the gap. + + // Filling a gap should not touch anything before the gap, so any + // information on groups already appearing before the gap should be + // discarded, while any information on groups appearing after the gap + // can be updated and re-ordered. + + const oldestPageNotification = notifications.at(-1)?.page_min_id; + + // replace the gap with the notifications + a new gap + + const newerGroupKeys = state.groups + .slice(0, gapIndex) + .filter(isNotificationGroup) + .map((group) => group.group_key); + + const toInsert: NotificationGroupsState['groups'] = notifications + .map((json) => createNotificationGroupFromJSON(json)) + .filter( + (notification) => !newerGroupKeys.includes(notification.group_key), + ); + + const apiGroupKeys = (toInsert as NotificationGroup[]).map( + (group) => group.group_key, + ); + + const sinceId = action.meta.arg.gap.sinceId; + if ( + notifications.length > 0 && + !( + oldestPageNotification && + sinceId && + compareId(oldestPageNotification, sinceId) <= 0 + ) + ) { + // If we get an empty page, it means we reached the bottom, so we do not need to insert a new gap + // Similarly, if we've fetched more than the gap's, this means we have completely filled it + toInsert.push({ + type: 'gap', + maxId: notifications.at(-1)?.page_max_id, + sinceId, + } as NotificationGap); + } + + // Remove older groups covered by the API + state.groups = state.groups.filter( + (groupOrGap) => + groupOrGap.type !== 'gap' && + !apiGroupKeys.includes(groupOrGap.group_key), + ); + + // Replace the gap with API results (+ the new gap if needed) + state.groups.splice(gapIndex, 1, ...toInsert); + + // Finally, merge any adjacent gaps that could have been created by filtering + // groups earlier + mergeGaps(state.groups); + + state.isLoading = false; + + updateLastReadId(state); + }) + .addCase(processNewNotificationForGroups.fulfilled, (state, action) => { + const notification = action.payload; + processNewNotification( + usePendingItems ? state.pendingGroups : state.groups, + notification, + ); + updateLastReadId(state); + trimNotifications(state); + }) + .addCase(disconnectTimeline, (state, action) => { + if (action.payload.timeline === 'home') { + if (state.groups.length > 0 && state.groups[0]?.type !== 'gap') { + state.groups.unshift({ + type: 'gap', + sinceId: state.groups[0]?.page_min_id, + }); + } + } + }) + .addCase(timelineDelete, (state, action) => { + removeNotificationsForStatus(state, action.payload.statusId); + }) + .addCase(clearNotifications.pending, (state) => { + state.groups = []; + state.pendingGroups = []; + }) + .addCase(blockAccountSuccess, (state, action) => { + removeNotificationsForAccounts(state, [action.payload.relationship.id]); + }) + .addCase(muteAccountSuccess, (state, action) => { + if (action.payload.relationship.muting_notifications) + removeNotificationsForAccounts(state, [ + action.payload.relationship.id, + ]); + }) + .addCase(blockDomainSuccess, (state, action) => { + removeNotificationsForAccounts( + state, + action.payload.accounts.map((account) => account.id), + ); + }) + .addCase(loadPending, (state) => { + // First, remove any existing group and merge data + state.pendingGroups.forEach((group) => { + if (group.type !== 'gap') { + const existingGroupIndex = state.groups.findIndex( + (groupOrGap) => + isNotificationGroup(groupOrGap) && + groupOrGap.group_key === group.group_key, + ); + if (existingGroupIndex > -1) { + const existingGroup = state.groups[existingGroupIndex]; + if (existingGroup && existingGroup.type !== 'gap') { + group.notifications_count += existingGroup.notifications_count; + group.sampleAccountIds = group.sampleAccountIds + .concat(existingGroup.sampleAccountIds) + .slice(0, NOTIFICATIONS_GROUP_MAX_AVATARS); + state.groups.splice(existingGroupIndex, 1); + } + } + } + trimNotifications(state); + }); + + // Then build the consolidated list and clear pending groups + state.groups = state.pendingGroups.concat(state.groups); + state.pendingGroups = []; + }) + .addCase(updateScrollPosition, (state, action) => { + state.scrolledToTop = action.payload.top; + updateLastReadId(state); + trimNotifications(state); + }) + .addCase(markNotificationsAsRead, (state) => { + const mostRecentGroup = state.groups.find(isNotificationGroup); + if ( + mostRecentGroup?.page_max_id && + compareId(state.lastReadId, mostRecentGroup.page_max_id) < 0 + ) + state.lastReadId = mostRecentGroup.page_max_id; + }) + .addCase(fetchMarkers.fulfilled, (state, action) => { + if ( + action.payload.markers.notifications && + compareId( + state.lastReadId, + action.payload.markers.notifications.last_read_id, + ) < 0 + ) + state.lastReadId = action.payload.markers.notifications.last_read_id; + }) + .addCase(mountNotifications, (state) => { + state.mounted += 1; + updateLastReadId(state); + }) + .addCase(unmountNotifications, (state) => { + state.mounted -= 1; + }) + .addCase(focusApp, (state) => { + state.isTabVisible = true; + updateLastReadId(state); + }) + .addCase(unfocusApp, (state) => { + state.isTabVisible = false; + }) + .addMatcher( + isAnyOf(authorizeFollowRequestSuccess, rejectFollowRequestSuccess), + (state, action) => { + removeNotificationsForAccounts( + state, + [action.payload.id], + 'follow_request', + ); + }, + ) + .addMatcher( + isAnyOf(fetchNotifications.pending, fetchNotificationsGap.pending), + (state) => { + state.isLoading = true; + }, + ) + .addMatcher( + isAnyOf(fetchNotifications.rejected, fetchNotificationsGap.rejected), + (state) => { + state.isLoading = false; + }, + ); + }, +); diff --git a/app/javascript/flavours/glitch/reducers/notifications.js b/app/javascript/flavours/glitch/reducers/notifications.js index 226f2affe1030a..b3c138583c7f7c 100644 --- a/app/javascript/flavours/glitch/reducers/notifications.js +++ b/app/javascript/flavours/glitch/reducers/notifications.js @@ -12,6 +12,7 @@ import { import { fetchMarkers, } from '../actions/markers'; +import { clearNotifications } from '../actions/notification_groups'; import { NOTIFICATIONS_MOUNT, NOTIFICATIONS_UNMOUNT, @@ -21,7 +22,6 @@ import { NOTIFICATIONS_EXPAND_REQUEST, NOTIFICATIONS_EXPAND_FAIL, NOTIFICATIONS_FILTER_SET, - NOTIFICATIONS_CLEAR, NOTIFICATIONS_SCROLL_TOP, NOTIFICATIONS_LOAD_PENDING, NOTIFICATIONS_DELETE_MARKED_REQUEST, @@ -332,7 +332,7 @@ export default function notifications(state = initialState, action) { case authorizeFollowRequestSuccess.type: case rejectFollowRequestSuccess.type: return filterNotifications(state, [action.payload.id], 'follow_request'); - case NOTIFICATIONS_CLEAR: + case clearNotifications.pending.type: return state.set('items', ImmutableList()).set('pendingItems', ImmutableList()).set('hasMore', false); case timelineDelete.type: return deleteByStatus(state, action.payload.statusId); diff --git a/app/javascript/flavours/glitch/selectors/notifications.ts b/app/javascript/flavours/glitch/selectors/notifications.ts new file mode 100644 index 00000000000000..7cc64aa6c584da --- /dev/null +++ b/app/javascript/flavours/glitch/selectors/notifications.ts @@ -0,0 +1,34 @@ +import { createSelector } from '@reduxjs/toolkit'; + +import { compareId } from 'flavours/glitch/compare_id'; +import type { RootState } from 'flavours/glitch/store'; + +export const selectUnreadNotificationGroupsCount = createSelector( + [ + (s: RootState) => s.notificationGroups.lastReadId, + (s: RootState) => s.notificationGroups.pendingGroups, + (s: RootState) => s.notificationGroups.groups, + ], + (notificationMarker, pendingGroups, groups) => { + return ( + groups.filter( + (group) => + group.type !== 'gap' && + group.page_max_id && + compareId(group.page_max_id, notificationMarker) > 0, + ).length + + pendingGroups.filter( + (group) => + group.type !== 'gap' && + group.page_max_id && + compareId(group.page_max_id, notificationMarker) > 0, + ).length + ); + }, +); + +export const selectPendingNotificationGroupsCount = createSelector( + [(s: RootState) => s.notificationGroups.pendingGroups], + (pendingGroups) => + pendingGroups.filter((group) => group.type !== 'gap').length, +); diff --git a/app/javascript/flavours/glitch/selectors/settings.ts b/app/javascript/flavours/glitch/selectors/settings.ts new file mode 100644 index 00000000000000..ce2b8b15e59cb1 --- /dev/null +++ b/app/javascript/flavours/glitch/selectors/settings.ts @@ -0,0 +1,40 @@ +import type { RootState } from 'flavours/glitch/store'; + +/* eslint-disable @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */ +// state.settings is not yet typed, so we disable some ESLint checks for those selectors +export const selectSettingsNotificationsShows = (state: RootState) => + state.settings.getIn(['notifications', 'shows']).toJS() as Record< + string, + boolean + >; + +export const selectSettingsNotificationsExcludedTypes = (state: RootState) => + Object.entries(selectSettingsNotificationsShows(state)) + .filter(([_type, enabled]) => !enabled) + .map(([type, _enabled]) => type); + +export const selectSettingsNotificationsQuickFilterShow = (state: RootState) => + state.settings.getIn(['notifications', 'quickFilter', 'show']) as boolean; + +export const selectSettingsNotificationsQuickFilterActive = ( + state: RootState, +) => state.settings.getIn(['notifications', 'quickFilter', 'active']) as string; + +export const selectSettingsNotificationsQuickFilterAdvanced = ( + state: RootState, +) => + state.settings.getIn(['notifications', 'quickFilter', 'advanced']) as boolean; + +export const selectSettingsNotificationsShowUnread = (state: RootState) => + state.settings.getIn(['notifications', 'showUnread']) as boolean; + +export const selectNeedsNotificationPermission = (state: RootState) => + (state.settings.getIn(['notifications', 'alerts']).includes(true) && + state.notifications.get('browserSupport') && + state.notifications.get('browserPermission') === 'default' && + !state.settings.getIn([ + 'notifications', + 'dismissPermissionBanner', + ])) as boolean; + +/* eslint-enable @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */ diff --git a/app/javascript/flavours/glitch/styles/components.scss b/app/javascript/flavours/glitch/styles/components.scss index 5c2a130cb976a4..bcc3655155940e 100644 --- a/app/javascript/flavours/glitch/styles/components.scss +++ b/app/javascript/flavours/glitch/styles/components.scss @@ -1430,6 +1430,8 @@ body > [data-popper-placement] { min-height: 54px; border-bottom: 1px solid var(--background-border-color); cursor: auto; + opacity: 1; + animation: fade 150ms linear; @keyframes fade { 0% { @@ -1441,9 +1443,6 @@ body > [data-popper-placement] { } } - opacity: 1; - animation: fade 150ms linear; - .media-gallery, .video-player, .audio-player, @@ -1791,10 +1790,19 @@ body > [data-popper-placement] { } } -.status__wrapper-direct { +.status__wrapper-direct, +.notification-ungrouped--direct { background: rgba($ui-highlight-color, 0.05); - .status__prepend { + &:focus { + background: rgba($ui-highlight-color, 0.1); + } +} + +.status__wrapper-direct, +.notification-ungrouped--direct { + .status__prepend, + .notification-ungrouped__header { color: $highlight-text-color; } } @@ -2390,41 +2398,28 @@ a.account__display-name { } } -.notification__relationships-severance-event, -.notification__moderation-warning { - display: flex; - gap: 16px; +.notification-group--link { color: $secondary-text-color; text-decoration: none; - align-items: flex-start; - padding: 16px 32px; - border-bottom: 1px solid var(--background-border-color); - - &:hover { - color: $primary-text-color; - } - - .icon { - padding: 2px; - color: $highlight-text-color; - } - &__content { + .notification-group__main { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; flex-grow: 1; - font-size: 16px; - line-height: 24px; + font-size: 15px; + line-height: 22px; - strong { + strong, + bdi { font-weight: 700; } .link-button { font-size: inherit; line-height: inherit; + font-weight: inherit; } } } @@ -5199,8 +5194,10 @@ a.status-card { &__menu { @include search-popout; - padding: 0; - background: $ui-secondary-color; + & { + padding: 0; + background: $ui-secondary-color; + } } &__menu-list { @@ -10745,10 +10742,9 @@ noscript { .filtered-notifications-banner { display: flex; align-items: center; - border: 1px solid var(--background-border-color); - border-top: 0; - padding: 24px 32px; - gap: 16px; + border-bottom: 1px solid var(--background-border-color); + padding: 16px 24px; + gap: 8px; color: $darker-text-color; text-decoration: none; @@ -10758,10 +10754,8 @@ noscript { color: $secondary-text-color; } - .icon { - width: 24px; - height: 24px; - padding: 2px; + .notification-group__icon { + color: inherit; } &__text { @@ -10899,6 +10893,251 @@ noscript { } } +.notification-group { + display: flex; + align-items: flex-start; + gap: 8px; + padding: 10px 14px; // glitch: reduced padding + border-bottom: 1px solid var(--background-border-color); + + &__icon { + width: 40px; + display: flex; + align-items: center; + justify-content: center; + flex: 0 0 auto; + color: $dark-text-color; + + .icon { + width: 28px; + height: 28px; + } + } + + &--follow &__icon, + &--follow-request &__icon { + color: $highlight-text-color; + } + + &--favourite &__icon { + color: $gold-star; + } + + &--reblog &__icon { + color: $valid-value-color; + } + + &--relationships-severance-event &__icon, + &--admin-report &__icon, + &--admin-sign-up &__icon { + color: $dark-text-color; + } + + &--moderation-warning &__icon { + color: $red-bookmark; + } + + &--follow-request &__actions { + align-items: center; + display: flex; + gap: 8px; + + .icon-button { + border: 1px solid var(--background-border-color); + border-radius: 50%; + padding: 1px; + } + } + + &__main { + display: flex; + flex-direction: column; + gap: 8px; + flex: 1 1 auto; + overflow: hidden; + + &__header { + display: flex; + flex-direction: column; + gap: 8px; + + &__wrapper { + display: flex; + justify-content: space-between; + } + + &__label { + display: flex; + gap: 8px; + font-size: 15px; + line-height: 22px; + color: $darker-text-color; + + a { + color: inherit; + text-decoration: none; + } + + bdi { + font-weight: 700; + color: $primary-text-color; + } + + time { + color: $dark-text-color; + } + } + } + + &__status { + border: 1px solid var(--background-border-color); + border-radius: 8px; + padding: 8px; + } + } + + &__avatar-group { + display: flex; + gap: 8px; + height: 28px; + overflow-y: hidden; + flex-wrap: wrap; + } + + .status { + padding: 0; + border: 0; + } + + &__embedded-status { + &__account { + display: flex; + align-items: center; + gap: 4px; + margin-bottom: 8px; + color: $dark-text-color; + + bdi { + color: inherit; + } + } + + .account__avatar { + opacity: 0.5; + } + + &__content { + display: -webkit-box; + font-size: 15px; + line-height: 22px; + color: $dark-text-color; + cursor: pointer; + -webkit-line-clamp: 4; + -webkit-box-orient: vertical; + max-height: 4 * 22px; + overflow: hidden; + + p, + a { + color: inherit; + } + } + } +} + +.notification-ungrouped { + padding: 16px 24px; + border-bottom: 1px solid var(--background-border-color); + + &__header { + display: flex; + align-items: center; + gap: 8px; + color: $dark-text-color; + font-size: 15px; + line-height: 22px; + font-weight: 500; + padding-inline-start: 24px; + margin-bottom: 16px; + + &__icon { + display: flex; + align-items: center; + justify-content: center; + flex: 0 0 auto; + + .icon { + width: 16px; + height: 16px; + } + } + + a { + color: inherit; + text-decoration: none; + } + } + + .status { + border: 0; + padding: 0; + + &__avatar { + width: 40px; + height: 40px; + } + } + + .status__wrapper-direct { + background: transparent; + } + + $icon-margin: 48px; // 40px avatar + 8px gap + + .status__content, + .status__action-bar, + .media-gallery, + .video-player, + .audio-player, + .attachment-list, + .picture-in-picture-placeholder, + .more-from-author, + .status-card, + .hashtag-bar { + margin-inline-start: $icon-margin; + width: calc(100% - $icon-margin); + } + + .more-from-author { + width: calc(100% - $icon-margin + 2px); + } + + .status__content__read-more-button { + margin-inline-start: $icon-margin; + } + + .notification__report { + border: 0; + padding: 0; + } +} + +.notification-group--unread, +.notification-ungrouped--unread { + position: relative; + + &::before { + content: ''; + position: absolute; + top: 0; + inset-inline-start: 0; + width: 100%; + height: 100%; + border-inline-start: 4px solid $highlight-text-color; + pointer-events: none; + } +} + .hover-card-controller[data-popper-reference-hidden='true'] { opacity: 0; pointer-events: none; @@ -11007,7 +11246,7 @@ noscript { gap: 4px; dt { - flex: 0 0 auto; + flex: 0 1 auto; color: $dark-text-color; min-width: 0; overflow: hidden; diff --git a/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss b/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss index 4040ee0fe0c598..1f5059c321e765 100644 --- a/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss +++ b/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss @@ -48,6 +48,10 @@ html { } } +.icon-button:disabled { + color: darken($action-button-color, 25%); +} + .account__header__bar .avatar .account__avatar { border-color: $white; } diff --git a/app/javascript/flavours/glitch/styles/neuromatchstodon/latex.scss b/app/javascript/flavours/glitch/styles/neuromatchstodon/latex.scss index 10a59dc1ee17dd..7517509ed07200 100644 --- a/app/javascript/flavours/glitch/styles/neuromatchstodon/latex.scss +++ b/app/javascript/flavours/glitch/styles/neuromatchstodon/latex.scss @@ -1,6 +1,5 @@ .compose-form { .latex-dropdown { - position: absolute; top: 24px; right: 0; } diff --git a/app/javascript/mastodon/actions/compose.js b/app/javascript/mastodon/actions/compose.js index e4b4cda8571721..863d93bccf8763 100644 --- a/app/javascript/mastodon/actions/compose.js +++ b/app/javascript/mastodon/actions/compose.js @@ -284,7 +284,7 @@ export function submitComposeFail(error) { export function uploadCompose(files) { return function (dispatch, getState) { - const uploadLimit = 4; + const uploadLimit = getState().getIn(['server', 'server', '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); @@ -304,7 +304,7 @@ export function uploadCompose(files) { dispatch(uploadComposeRequest()); for (const [i, file] of Array.from(files).entries()) { - if (media.size + i > 3) break; + if (media.size + i > (uploadLimit - 1)) break; const data = new FormData(); data.append('file', file); diff --git a/app/javascript/mastodon/actions/markers.ts b/app/javascript/mastodon/actions/markers.ts index 03f577c540fc5d..77d91d9b9c3411 100644 --- a/app/javascript/mastodon/actions/markers.ts +++ b/app/javascript/mastodon/actions/markers.ts @@ -75,9 +75,17 @@ interface MarkerParam { } function getLastNotificationId(state: RootState): string | undefined { - // @ts-expect-error state.notifications is not yet typed - // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call - return state.getIn(['notifications', 'lastReadId']); + // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access + const enableBeta = state.settings.getIn( + ['notifications', 'groupingBeta'], + false, + ) as boolean; + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return enableBeta + ? state.notificationGroups.lastReadId + : // @ts-expect-error state.notifications is not yet typed + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + state.getIn(['notifications', 'lastReadId']); } const buildPostMarkersParams = (state: RootState) => { diff --git a/app/javascript/mastodon/actions/notification_groups.ts b/app/javascript/mastodon/actions/notification_groups.ts new file mode 100644 index 00000000000000..8fdec6e48bb4df --- /dev/null +++ b/app/javascript/mastodon/actions/notification_groups.ts @@ -0,0 +1,144 @@ +import { createAction } from '@reduxjs/toolkit'; + +import { + apiClearNotifications, + apiFetchNotifications, +} from 'mastodon/api/notifications'; +import type { ApiAccountJSON } from 'mastodon/api_types/accounts'; +import type { + ApiNotificationGroupJSON, + ApiNotificationJSON, +} from 'mastodon/api_types/notifications'; +import { allNotificationTypes } from 'mastodon/api_types/notifications'; +import type { ApiStatusJSON } from 'mastodon/api_types/statuses'; +import type { NotificationGap } from 'mastodon/reducers/notification_groups'; +import { + selectSettingsNotificationsExcludedTypes, + selectSettingsNotificationsQuickFilterActive, +} from 'mastodon/selectors/settings'; +import type { AppDispatch } from 'mastodon/store'; +import { + createAppAsyncThunk, + createDataLoadingThunk, +} from 'mastodon/store/typed_functions'; + +import { importFetchedAccounts, importFetchedStatuses } from './importer'; +import { NOTIFICATIONS_FILTER_SET } from './notifications'; +import { saveSettings } from './settings'; + +function excludeAllTypesExcept(filter: string) { + return allNotificationTypes.filter((item) => item !== filter); +} + +function dispatchAssociatedRecords( + dispatch: AppDispatch, + notifications: ApiNotificationGroupJSON[] | ApiNotificationJSON[], +) { + const fetchedAccounts: ApiAccountJSON[] = []; + const fetchedStatuses: ApiStatusJSON[] = []; + + notifications.forEach((notification) => { + if ('sample_accounts' in notification) { + fetchedAccounts.push(...notification.sample_accounts); + } + + if (notification.type === 'admin.report') { + fetchedAccounts.push(notification.report.target_account); + } + + if (notification.type === 'moderation_warning') { + fetchedAccounts.push(notification.moderation_warning.target_account); + } + + if ('status' in notification) { + fetchedStatuses.push(notification.status); + } + }); + + if (fetchedAccounts.length > 0) + dispatch(importFetchedAccounts(fetchedAccounts)); + + if (fetchedStatuses.length > 0) + dispatch(importFetchedStatuses(fetchedStatuses)); +} + +export const fetchNotifications = createDataLoadingThunk( + 'notificationGroups/fetch', + async (_params, { getState }) => { + const activeFilter = + selectSettingsNotificationsQuickFilterActive(getState()); + + return apiFetchNotifications({ + exclude_types: + activeFilter === 'all' + ? selectSettingsNotificationsExcludedTypes(getState()) + : excludeAllTypesExcept(activeFilter), + }); + }, + ({ notifications }, { dispatch }) => { + dispatchAssociatedRecords(dispatch, notifications); + const payload: (ApiNotificationGroupJSON | NotificationGap)[] = + notifications; + + // TODO: might be worth not using gaps for that… + // if (nextLink) payload.push({ type: 'gap', loadUrl: nextLink.uri }); + if (notifications.length > 1) + payload.push({ type: 'gap', maxId: notifications.at(-1)?.page_min_id }); + + return payload; + // dispatch(submitMarkers()); + }, +); + +export const fetchNotificationsGap = createDataLoadingThunk( + 'notificationGroups/fetchGap', + async (params: { gap: NotificationGap }) => + apiFetchNotifications({ max_id: params.gap.maxId }), + + ({ notifications }, { dispatch }) => { + dispatchAssociatedRecords(dispatch, notifications); + + return { notifications }; + }, +); + +export const processNewNotificationForGroups = createAppAsyncThunk( + 'notificationGroups/processNew', + (notification: ApiNotificationJSON, { dispatch }) => { + dispatchAssociatedRecords(dispatch, [notification]); + + return notification; + }, +); + +export const loadPending = createAction('notificationGroups/loadPending'); + +export const updateScrollPosition = createAction<{ top: boolean }>( + 'notificationGroups/updateScrollPosition', +); + +export const setNotificationsFilter = createAppAsyncThunk( + 'notifications/filter/set', + ({ filterType }: { filterType: string }, { dispatch }) => { + dispatch({ + type: NOTIFICATIONS_FILTER_SET, + path: ['notifications', 'quickFilter', 'active'], + value: filterType, + }); + // dispatch(expandNotifications({ forceLoad: true })); + void dispatch(fetchNotifications()); + dispatch(saveSettings()); + }, +); + +export const clearNotifications = createDataLoadingThunk( + 'notifications/clear', + () => apiClearNotifications(), +); + +export const markNotificationsAsRead = createAction( + 'notificationGroups/markAsRead', +); + +export const mountNotifications = createAction('notificationGroups/mount'); +export const unmountNotifications = createAction('notificationGroups/unmount'); diff --git a/app/javascript/mastodon/actions/notifications.js b/app/javascript/mastodon/actions/notifications.js index 6a59d5624e80c4..7e4320c27b7d5b 100644 --- a/app/javascript/mastodon/actions/notifications.js +++ b/app/javascript/mastodon/actions/notifications.js @@ -32,7 +32,6 @@ export const NOTIFICATIONS_EXPAND_FAIL = 'NOTIFICATIONS_EXPAND_FAIL'; export const NOTIFICATIONS_FILTER_SET = 'NOTIFICATIONS_FILTER_SET'; -export const NOTIFICATIONS_CLEAR = 'NOTIFICATIONS_CLEAR'; export const NOTIFICATIONS_SCROLL_TOP = 'NOTIFICATIONS_SCROLL_TOP'; export const NOTIFICATIONS_LOAD_PENDING = 'NOTIFICATIONS_LOAD_PENDING'; @@ -174,7 +173,7 @@ const noOp = () => {}; let expandNotificationsController = new AbortController(); -export function expandNotifications({ maxId, forceLoad } = {}, done = noOp) { +export function expandNotifications({ maxId, forceLoad = false } = {}, done = noOp) { return (dispatch, getState) => { const activeFilter = getState().getIn(['settings', 'notifications', 'quickFilter', 'active']); const notifications = getState().get('notifications'); @@ -257,16 +256,6 @@ export function expandNotificationsFail(error, isLoadingMore) { }; } -export function clearNotifications() { - return (dispatch) => { - dispatch({ - type: NOTIFICATIONS_CLEAR, - }); - - api().post('/api/v1/notifications/clear'); - }; -} - export function scrollTopNotifications(top) { return { type: NOTIFICATIONS_SCROLL_TOP, diff --git a/app/javascript/mastodon/actions/notifications_migration.tsx b/app/javascript/mastodon/actions/notifications_migration.tsx new file mode 100644 index 00000000000000..f856e56828f11f --- /dev/null +++ b/app/javascript/mastodon/actions/notifications_migration.tsx @@ -0,0 +1,18 @@ +import { createAppAsyncThunk } from 'mastodon/store'; + +import { fetchNotifications } from './notification_groups'; +import { expandNotifications } from './notifications'; + +export const initializeNotifications = createAppAsyncThunk( + 'notifications/initialize', + (_, { dispatch, getState }) => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access + const enableBeta = getState().settings.getIn( + ['notifications', 'groupingBeta'], + false, + ) as boolean; + + if (enableBeta) void dispatch(fetchNotifications()); + else dispatch(expandNotifications()); + }, +); diff --git a/app/javascript/mastodon/actions/notifications_typed.ts b/app/javascript/mastodon/actions/notifications_typed.ts index 176362f4b1edd4..88d942d45e54b5 100644 --- a/app/javascript/mastodon/actions/notifications_typed.ts +++ b/app/javascript/mastodon/actions/notifications_typed.ts @@ -1,11 +1,6 @@ import { createAction } from '@reduxjs/toolkit'; -import type { ApiAccountJSON } from '../api_types/accounts'; -// To be replaced once ApiNotificationJSON type exists -interface FakeApiNotificationJSON { - type: string; - account: ApiAccountJSON; -} +import type { ApiNotificationJSON } from 'mastodon/api_types/notifications'; export const notificationsUpdate = createAction( 'notifications/update', @@ -13,7 +8,7 @@ export const notificationsUpdate = createAction( playSound, ...args }: { - notification: FakeApiNotificationJSON; + notification: ApiNotificationJSON; usePendingItems: boolean; playSound: boolean; }) => ({ diff --git a/app/javascript/mastodon/actions/streaming.js b/app/javascript/mastodon/actions/streaming.js index e7fe1c53ed09ed..f50f41b0d9cd4b 100644 --- a/app/javascript/mastodon/actions/streaming.js +++ b/app/javascript/mastodon/actions/streaming.js @@ -10,6 +10,7 @@ import { deleteAnnouncement, } from './announcements'; import { updateConversations } from './conversations'; +import { processNewNotificationForGroups } from './notification_groups'; import { updateNotifications, expandNotifications } from './notifications'; import { updateStatus } from './statuses'; import { @@ -98,10 +99,16 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti case 'delete': dispatch(deleteFromTimelines(data.payload)); break; - case 'notification': + case 'notification': { // @ts-expect-error - dispatch(updateNotifications(JSON.parse(data.payload), messages, locale)); + const notificationJSON = JSON.parse(data.payload); + dispatch(updateNotifications(notificationJSON, messages, locale)); + // TODO: remove this once the groups feature replaces the previous one + if(getState().notificationGroups.groups.length > 0) { + dispatch(processNewNotificationForGroups(notificationJSON)); + } break; + } case 'conversation': // @ts-expect-error dispatch(updateConversations(JSON.parse(data.payload))); diff --git a/app/javascript/mastodon/api/notifications.ts b/app/javascript/mastodon/api/notifications.ts new file mode 100644 index 00000000000000..c1ab6f70cafbde --- /dev/null +++ b/app/javascript/mastodon/api/notifications.ts @@ -0,0 +1,18 @@ +import api, { apiRequest, getLinks } from 'mastodon/api'; +import type { ApiNotificationGroupJSON } from 'mastodon/api_types/notifications'; + +export const apiFetchNotifications = async (params?: { + exclude_types?: string[]; + max_id?: string; +}) => { + const response = await api().request({ + method: 'GET', + url: '/api/v2_alpha/notifications', + params, + }); + + return { notifications: response.data, links: getLinks(response) }; +}; + +export const apiClearNotifications = () => + apiRequest('POST', 'v1/notifications/clear'); diff --git a/app/javascript/mastodon/api_types/notifications.ts b/app/javascript/mastodon/api_types/notifications.ts new file mode 100644 index 00000000000000..d7cbbca73b9ec3 --- /dev/null +++ b/app/javascript/mastodon/api_types/notifications.ts @@ -0,0 +1,145 @@ +// See app/serializers/rest/notification_group_serializer.rb + +import type { AccountWarningAction } from 'mastodon/models/notification_group'; + +import type { ApiAccountJSON } from './accounts'; +import type { ApiReportJSON } from './reports'; +import type { ApiStatusJSON } from './statuses'; + +// See app/model/notification.rb +export const allNotificationTypes = [ + 'follow', + 'follow_request', + 'favourite', + 'reblog', + 'mention', + 'poll', + 'status', + 'update', + 'admin.sign_up', + 'admin.report', + 'moderation_warning', + 'severed_relationships', +]; + +export type NotificationWithStatusType = + | 'favourite' + | 'reblog' + | 'status' + | 'mention' + | 'poll' + | 'update'; + +export type NotificationType = + | NotificationWithStatusType + | 'follow' + | 'follow_request' + | 'moderation_warning' + | 'severed_relationships' + | 'admin.sign_up' + | 'admin.report'; + +export interface BaseNotificationJSON { + id: string; + type: NotificationType; + created_at: string; + group_key: string; + account: ApiAccountJSON; +} + +export interface BaseNotificationGroupJSON { + group_key: string; + notifications_count: number; + type: NotificationType; + sample_accounts: ApiAccountJSON[]; + latest_page_notification_at: string; // FIXME: This will only be present if the notification group is returned in a paginated list, not requested directly + most_recent_notification_id: string; + page_min_id?: string; + page_max_id?: string; +} + +interface NotificationGroupWithStatusJSON extends BaseNotificationGroupJSON { + type: NotificationWithStatusType; + status: ApiStatusJSON; +} + +interface NotificationWithStatusJSON extends BaseNotificationJSON { + type: NotificationWithStatusType; + status: ApiStatusJSON; +} + +interface ReportNotificationGroupJSON extends BaseNotificationGroupJSON { + type: 'admin.report'; + report: ApiReportJSON; +} + +interface ReportNotificationJSON extends BaseNotificationJSON { + type: 'admin.report'; + report: ApiReportJSON; +} + +type SimpleNotificationTypes = 'follow' | 'follow_request' | 'admin.sign_up'; +interface SimpleNotificationGroupJSON extends BaseNotificationGroupJSON { + type: SimpleNotificationTypes; +} + +interface SimpleNotificationJSON extends BaseNotificationJSON { + type: SimpleNotificationTypes; +} + +export interface ApiAccountWarningJSON { + id: string; + action: AccountWarningAction; + text: string; + status_ids: string[]; + created_at: string; + target_account: ApiAccountJSON; + appeal: unknown; +} + +interface ModerationWarningNotificationGroupJSON + extends BaseNotificationGroupJSON { + type: 'moderation_warning'; + moderation_warning: ApiAccountWarningJSON; +} + +interface ModerationWarningNotificationJSON extends BaseNotificationJSON { + type: 'moderation_warning'; + moderation_warning: ApiAccountWarningJSON; +} + +export interface ApiAccountRelationshipSeveranceEventJSON { + id: string; + type: 'account_suspension' | 'domain_block' | 'user_domain_block'; + purged: boolean; + target_name: string; + followers_count: number; + following_count: number; + created_at: string; +} + +interface AccountRelationshipSeveranceNotificationGroupJSON + extends BaseNotificationGroupJSON { + type: 'severed_relationships'; + event: ApiAccountRelationshipSeveranceEventJSON; +} + +interface AccountRelationshipSeveranceNotificationJSON + extends BaseNotificationJSON { + type: 'severed_relationships'; + event: ApiAccountRelationshipSeveranceEventJSON; +} + +export type ApiNotificationJSON = + | SimpleNotificationJSON + | ReportNotificationJSON + | AccountRelationshipSeveranceNotificationJSON + | NotificationWithStatusJSON + | ModerationWarningNotificationJSON; + +export type ApiNotificationGroupJSON = + | SimpleNotificationGroupJSON + | ReportNotificationGroupJSON + | AccountRelationshipSeveranceNotificationGroupJSON + | NotificationGroupWithStatusJSON + | ModerationWarningNotificationGroupJSON; diff --git a/app/javascript/mastodon/api_types/reports.ts b/app/javascript/mastodon/api_types/reports.ts new file mode 100644 index 00000000000000..b11cfdd2eb59c8 --- /dev/null +++ b/app/javascript/mastodon/api_types/reports.ts @@ -0,0 +1,16 @@ +import type { ApiAccountJSON } from './accounts'; + +export type ReportCategory = 'other' | 'spam' | 'legal' | 'violation'; + +export interface ApiReportJSON { + id: string; + action_taken: unknown; + action_taken_at: unknown; + category: ReportCategory; + comment: string; + forwarded: boolean; + created_at: string; + status_ids: string[]; + rule_ids: string[]; + target_account: ApiAccountJSON; +} diff --git a/app/javascript/mastodon/components/__tests__/hashtag_bar.tsx b/app/javascript/mastodon/components/__tests__/hashtag_bar.tsx index b7225fc92e01e4..f86c1a2a6bc5b5 100644 --- a/app/javascript/mastodon/components/__tests__/hashtag_bar.tsx +++ b/app/javascript/mastodon/components/__tests__/hashtag_bar.tsx @@ -165,7 +165,7 @@ describe('computeHashtagBarForStatus', () => { ); }); - it('puts the hashtags in the bar if a status content has hashtags in the only line and has a media', () => { + it('does not put the hashtags in the bar if a status content has hashtags in the only line and has a media', () => { const status = createStatus( '

This is my content! #hashtag

', ['hashtag'], diff --git a/app/javascript/mastodon/components/account.jsx b/app/javascript/mastodon/components/account.jsx index 18a31cba244867..2a748e67ff139b 100644 --- a/app/javascript/mastodon/components/account.jsx +++ b/app/javascript/mastodon/components/account.jsx @@ -131,7 +131,7 @@ const Account = ({ size = 46, account, onFollow, onBlock, onMute, onMuteNotifica return (
- +
diff --git a/app/javascript/mastodon/components/hover_card_controller.tsx b/app/javascript/mastodon/components/hover_card_controller.tsx index 5ca55ebde91049..057ef1aaed4a71 100644 --- a/app/javascript/mastodon/components/hover_card_controller.tsx +++ b/app/javascript/mastodon/components/hover_card_controller.tsx @@ -43,6 +43,7 @@ export const HoverCardController: React.FC = () => { useEffect(() => { let isScrolling = false; let currentAnchor: HTMLElement | null = null; + let currentTitle: string | null = null; const open = (target: HTMLElement) => { target.setAttribute('aria-describedby', 'hover-card'); @@ -75,6 +76,9 @@ export const HoverCardController: React.FC = () => { currentAnchor?.removeAttribute('aria-describedby'); currentAnchor = target; + currentTitle = target.getAttribute('title'); + target.removeAttribute('title'); + setEnterTimeout(() => { open(target); }, enterDelay); @@ -90,11 +94,20 @@ export const HoverCardController: React.FC = () => { }; const handleMouseLeave = (e: MouseEvent) => { + const { target } = e; + if (!currentAnchor) { return; } - if (e.target === currentAnchor || e.target === cardRef.current) { + if ( + currentTitle && + target instanceof HTMLElement && + target === currentAnchor + ) + target.setAttribute('title', currentTitle); + + if (target === currentAnchor || target === cardRef.current) { cancelEnterTimeout(); setLeaveTimeout(() => { diff --git a/app/javascript/mastodon/components/load_gap.tsx b/app/javascript/mastodon/components/load_gap.tsx index 1d4193a35951ab..544b5e1461b17f 100644 --- a/app/javascript/mastodon/components/load_gap.tsx +++ b/app/javascript/mastodon/components/load_gap.tsx @@ -9,18 +9,18 @@ const messages = defineMessages({ load_more: { id: 'status.load_more', defaultMessage: 'Load more' }, }); -interface Props { +interface Props { disabled: boolean; - maxId: string; - onClick: (maxId: string) => void; + param: T; + onClick: (params: T) => void; } -export const LoadGap: React.FC = ({ disabled, maxId, onClick }) => { +export const LoadGap = ({ disabled, param, onClick }: Props) => { const intl = useIntl(); const handleClick = useCallback(() => { - onClick(maxId); - }, [maxId, onClick]); + onClick(param); + }, [param, onClick]); return ( + ); +}; + +export const FilterBar: React.FC = () => { + const intl = useIntl(); + + const selectedFilter = useAppSelector( + selectSettingsNotificationsQuickFilterActive, + ); + const advancedMode = useAppSelector( + selectSettingsNotificationsQuickFilterAdvanced, + ); + + if (advancedMode) + return ( +
+ + + + + + + + + + + + + + + + + + + + + +
+ ); + else + return ( +
+ + + + + + +
+ ); +}; diff --git a/app/javascript/mastodon/features/notifications_v2/index.tsx b/app/javascript/mastodon/features/notifications_v2/index.tsx new file mode 100644 index 00000000000000..fc20f0583631ed --- /dev/null +++ b/app/javascript/mastodon/features/notifications_v2/index.tsx @@ -0,0 +1,354 @@ +import { useCallback, useEffect, useMemo, useRef } from 'react'; + +import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; + +import { Helmet } from 'react-helmet'; + +import { createSelector } from '@reduxjs/toolkit'; + +import { useDebouncedCallback } from 'use-debounce'; + +import DoneAllIcon from '@/material-icons/400-24px/done_all.svg?react'; +import NotificationsIcon from '@/material-icons/400-24px/notifications-fill.svg?react'; +import { + fetchNotificationsGap, + updateScrollPosition, + loadPending, + markNotificationsAsRead, + mountNotifications, + unmountNotifications, +} from 'mastodon/actions/notification_groups'; +import { compareId } from 'mastodon/compare_id'; +import { Icon } from 'mastodon/components/icon'; +import { NotSignedInIndicator } from 'mastodon/components/not_signed_in_indicator'; +import { useIdentity } from 'mastodon/identity_context'; +import type { NotificationGap } from 'mastodon/reducers/notification_groups'; +import { + selectUnreadNotificationGroupsCount, + selectPendingNotificationGroupsCount, +} from 'mastodon/selectors/notifications'; +import { + selectNeedsNotificationPermission, + selectSettingsNotificationsExcludedTypes, + selectSettingsNotificationsQuickFilterActive, + selectSettingsNotificationsQuickFilterShow, + selectSettingsNotificationsShowUnread, +} from 'mastodon/selectors/settings'; +import { useAppDispatch, useAppSelector } from 'mastodon/store'; +import type { RootState } from 'mastodon/store'; + +import { addColumn, removeColumn, moveColumn } from '../../actions/columns'; +import { submitMarkers } from '../../actions/markers'; +import Column from '../../components/column'; +import { ColumnHeader } from '../../components/column_header'; +import { LoadGap } from '../../components/load_gap'; +import ScrollableList from '../../components/scrollable_list'; +import { FilteredNotificationsBanner } from '../notifications/components/filtered_notifications_banner'; +import NotificationsPermissionBanner from '../notifications/components/notifications_permission_banner'; +import ColumnSettingsContainer from '../notifications/containers/column_settings_container'; + +import { NotificationGroup } from './components/notification_group'; +import { FilterBar } from './filter_bar'; + +const messages = defineMessages({ + title: { id: 'column.notifications', defaultMessage: 'Notifications' }, + markAsRead: { + id: 'notifications.mark_as_read', + defaultMessage: 'Mark every notification as read', + }, +}); + +const getNotifications = createSelector( + [ + selectSettingsNotificationsQuickFilterShow, + selectSettingsNotificationsQuickFilterActive, + selectSettingsNotificationsExcludedTypes, + (state: RootState) => state.notificationGroups.groups, + ], + (showFilterBar, allowedType, excludedTypes, notifications) => { + if (!showFilterBar || allowedType === 'all') { + // used if user changed the notification settings after loading the notifications from the server + // otherwise a list of notifications will come pre-filtered from the backend + // we need to turn it off for FilterBar in order not to block ourselves from seeing a specific category + return notifications.filter( + (item) => item.type === 'gap' || !excludedTypes.includes(item.type), + ); + } + return notifications.filter( + (item) => item.type === 'gap' || allowedType === item.type, + ); + }, +); + +export const Notifications: React.FC<{ + columnId?: string; + multiColumn?: boolean; +}> = ({ columnId, multiColumn }) => { + const intl = useIntl(); + const notifications = useAppSelector(getNotifications); + const dispatch = useAppDispatch(); + const isLoading = useAppSelector((s) => s.notificationGroups.isLoading); + const hasMore = notifications.at(-1)?.type === 'gap'; + + const lastReadId = useAppSelector((s) => + selectSettingsNotificationsShowUnread(s) + ? s.notificationGroups.lastReadId + : '0', + ); + + const numPending = useAppSelector(selectPendingNotificationGroupsCount); + + const unreadNotificationsCount = useAppSelector( + selectUnreadNotificationGroupsCount, + ); + + const isUnread = unreadNotificationsCount > 0; + + const canMarkAsRead = + useAppSelector(selectSettingsNotificationsShowUnread) && + unreadNotificationsCount > 0; + + const needsNotificationPermission = useAppSelector( + selectNeedsNotificationPermission, + ); + + const columnRef = useRef(null); + + const selectChild = useCallback((index: number, alignTop: boolean) => { + const container = columnRef.current?.node as HTMLElement | undefined; + + if (!container) return; + + const element = container.querySelector( + `article:nth-of-type(${index + 1}) .focusable`, + ); + + if (element) { + if (alignTop && container.scrollTop > element.offsetTop) { + element.scrollIntoView(true); + } else if ( + !alignTop && + container.scrollTop + container.clientHeight < + element.offsetTop + element.offsetHeight + ) { + element.scrollIntoView(false); + } + element.focus(); + } + }, []); + + // Keep track of mounted components for unread notification handling + useEffect(() => { + dispatch(mountNotifications()); + + return () => { + dispatch(unmountNotifications()); + dispatch(updateScrollPosition({ top: false })); + }; + }, [dispatch]); + + const handleLoadGap = useCallback( + (gap: NotificationGap) => { + void dispatch(fetchNotificationsGap({ gap })); + }, + [dispatch], + ); + + const handleLoadOlder = useDebouncedCallback( + () => { + const gap = notifications.at(-1); + if (gap?.type === 'gap') void dispatch(fetchNotificationsGap({ gap })); + }, + 300, + { leading: true }, + ); + + const handleLoadPending = useCallback(() => { + dispatch(loadPending()); + }, [dispatch]); + + const handleScrollToTop = useDebouncedCallback(() => { + dispatch(updateScrollPosition({ top: true })); + }, 100); + + const handleScroll = useDebouncedCallback(() => { + dispatch(updateScrollPosition({ top: false })); + }, 100); + + useEffect(() => { + return () => { + handleLoadOlder.cancel(); + handleScrollToTop.cancel(); + handleScroll.cancel(); + }; + }, [handleLoadOlder, handleScrollToTop, handleScroll]); + + const handlePin = useCallback(() => { + if (columnId) { + dispatch(removeColumn(columnId)); + } else { + dispatch(addColumn('NOTIFICATIONS', {})); + } + }, [columnId, dispatch]); + + const handleMove = useCallback( + (dir: unknown) => { + dispatch(moveColumn(columnId, dir)); + }, + [dispatch, columnId], + ); + + const handleHeaderClick = useCallback(() => { + columnRef.current?.scrollTop(); + }, []); + + const handleMoveUp = useCallback( + (id: string) => { + const elementIndex = + notifications.findIndex( + (item) => item.type !== 'gap' && item.group_key === id, + ) - 1; + selectChild(elementIndex, true); + }, + [notifications, selectChild], + ); + + const handleMoveDown = useCallback( + (id: string) => { + const elementIndex = + notifications.findIndex( + (item) => item.type !== 'gap' && item.group_key === id, + ) + 1; + selectChild(elementIndex, false); + }, + [notifications, selectChild], + ); + + const handleMarkAsRead = useCallback(() => { + dispatch(markNotificationsAsRead()); + void dispatch(submitMarkers({ immediate: true })); + }, [dispatch]); + + const pinned = !!columnId; + const emptyMessage = ( + + ); + + const { signedIn } = useIdentity(); + + const filterBar = signedIn ? : null; + + const scrollableContent = useMemo(() => { + if (notifications.length === 0 && !hasMore) return null; + + return notifications.map((item) => + item.type === 'gap' ? ( + + ) : ( + 0 + } + /> + ), + ); + }, [ + notifications, + isLoading, + hasMore, + lastReadId, + handleLoadGap, + handleMoveUp, + handleMoveDown, + ]); + + const prepend = ( + <> + {needsNotificationPermission && } + + + ); + + const scrollContainer = signedIn ? ( + + {scrollableContent} + + ) : ( + + ); + + const extraButton = canMarkAsRead ? ( + + ) : null; + + return ( + + + + + + {filterBar} + + {scrollContainer} + + + {intl.formatMessage(messages.title)} + + + + ); +}; + +// eslint-disable-next-line import/no-default-export +export default Notifications; diff --git a/app/javascript/mastodon/features/notifications_wrapper.jsx b/app/javascript/mastodon/features/notifications_wrapper.jsx new file mode 100644 index 00000000000000..057ed1b395f8ec --- /dev/null +++ b/app/javascript/mastodon/features/notifications_wrapper.jsx @@ -0,0 +1,13 @@ +import Notifications from 'mastodon/features/notifications'; +import Notifications_v2 from 'mastodon/features/notifications_v2'; +import { useAppSelector } from 'mastodon/store'; + +export const NotificationsWrapper = (props) => { + const optedInGroupedNotifications = useAppSelector((state) => state.getIn(['settings', 'notifications', 'groupingBeta'], false)); + + return ( + optedInGroupedNotifications ? : + ); +}; + +export default NotificationsWrapper; \ No newline at end of file diff --git a/app/javascript/mastodon/features/status/components/card.jsx b/app/javascript/mastodon/features/status/components/card.jsx index f0ae40cbc412f5..ee1fbe0f8fe826 100644 --- a/app/javascript/mastodon/features/status/components/card.jsx +++ b/app/javascript/mastodon/features/status/components/card.jsx @@ -141,7 +141,7 @@ export default class Card extends PureComponent { const showAuthor = !!card.getIn(['authors', 0, 'accountId']); const description = ( -
+
{provider} {card.get('published_at') && <> · } diff --git a/app/javascript/mastodon/features/ui/components/columns_area.jsx b/app/javascript/mastodon/features/ui/components/columns_area.jsx index 19c2f40ac61c8f..063ac28d96fd26 100644 --- a/app/javascript/mastodon/features/ui/components/columns_area.jsx +++ b/app/javascript/mastodon/features/ui/components/columns_area.jsx @@ -10,7 +10,7 @@ import { scrollRight } from '../../../scroll'; import BundleContainer from '../containers/bundle_container'; import { Compose, - Notifications, + NotificationsWrapper, HomeTimeline, CommunityTimeline, PublicTimeline, @@ -32,7 +32,7 @@ import NavigationPanel from './navigation_panel'; const componentMap = { 'COMPOSE': Compose, 'HOME': HomeTimeline, - 'NOTIFICATIONS': Notifications, + 'NOTIFICATIONS': NotificationsWrapper, 'PUBLIC': PublicTimeline, 'REMOTE': PublicTimeline, 'COMMUNITY': CommunityTimeline, diff --git a/app/javascript/mastodon/features/ui/components/navigation_panel.jsx b/app/javascript/mastodon/features/ui/components/navigation_panel.jsx index ff90eef359fb6d..2648923bfc4161 100644 --- a/app/javascript/mastodon/features/ui/components/navigation_panel.jsx +++ b/app/javascript/mastodon/features/ui/components/navigation_panel.jsx @@ -34,6 +34,7 @@ import { NavigationPortal } from 'mastodon/components/navigation_portal'; import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; import { timelinePreview, trendsEnabled } from 'mastodon/initial_state'; import { transientSingleColumn } from 'mastodon/is_mobile'; +import { selectUnreadNotificationGroupsCount } from 'mastodon/selectors/notifications'; import ColumnLink from './column_link'; import DisabledAccountBanner from './disabled_account_banner'; @@ -59,15 +60,19 @@ const messages = defineMessages({ }); const NotificationsLink = () => { + const optedInGroupedNotifications = useSelector((state) => state.getIn(['settings', 'notifications', 'groupingBeta'], false)); const count = useSelector(state => state.getIn(['notifications', 'unread'])); const intl = useIntl(); + const newCount = useSelector(selectUnreadNotificationGroupsCount); + return ( } - activeIcon={} + icon={} + activeIcon={} text={intl.formatMessage(messages.notifications)} /> ); diff --git a/app/javascript/mastodon/features/ui/index.jsx b/app/javascript/mastodon/features/ui/index.jsx index d41132f9ca1e40..f36e0cf501fdbf 100644 --- a/app/javascript/mastodon/features/ui/index.jsx +++ b/app/javascript/mastodon/features/ui/index.jsx @@ -13,6 +13,7 @@ import { HotKeys } from 'react-hotkeys'; import { focusApp, unfocusApp, changeLayout } from 'mastodon/actions/app'; import { synchronouslySubmitMarkers, submitMarkers, fetchMarkers } from 'mastodon/actions/markers'; +import { initializeNotifications } from 'mastodon/actions/notifications_migration'; import { INTRODUCTION_VERSION } from 'mastodon/actions/onboarding'; import { HoverCardController } from 'mastodon/components/hover_card_controller'; import { PictureInPicture } from 'mastodon/features/picture_in_picture'; @@ -22,10 +23,9 @@ import { WithRouterPropTypes } from 'mastodon/utils/react_router'; import { uploadCompose, resetCompose, changeComposeSpoilerness } from '../../actions/compose'; import { clearHeight } from '../../actions/height_cache'; -import { expandNotifications } from '../../actions/notifications'; import { fetchServer, fetchServerTranslationLanguages } from '../../actions/server'; import { expandHomeTimeline } from '../../actions/timelines'; -import initialState, { me, owner, singleUserMode, trendsEnabled, trendsAsLanding } from '../../initial_state'; +import initialState, { me, owner, singleUserMode, trendsEnabled, trendsAsLanding, disableHoverCards } from '../../initial_state'; import BundleColumnError from './components/bundle_column_error'; import Header from './components/header'; @@ -49,7 +49,7 @@ import { Favourites, DirectTimeline, HashtagTimeline, - Notifications, + NotificationsWrapper, NotificationRequests, NotificationRequest, FollowRequests, @@ -71,6 +71,7 @@ import { } from './util/async-components'; import { ColumnsContextProvider } from './util/columns_context'; import { WrappedSwitch, WrappedRoute } from './util/react_router_helpers'; + // 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'; @@ -205,7 +206,7 @@ class SwitchingColumnsArea extends PureComponent { - + @@ -405,7 +406,7 @@ class UI extends PureComponent { if (signedIn) { this.props.dispatch(fetchMarkers()); this.props.dispatch(expandHomeTimeline()); - this.props.dispatch(expandNotifications()); + this.props.dispatch(initializeNotifications()); this.props.dispatch(fetchServerTranslationLanguages()); setTimeout(() => this.props.dispatch(fetchServer()), 3000); @@ -588,7 +589,7 @@ class UI extends PureComponent { {layout !== 'mobile' && } - + {!disableHoverCards && } diff --git a/app/javascript/mastodon/features/ui/util/async-components.js b/app/javascript/mastodon/features/ui/util/async-components.js index b8a2359d92cd3f..7c4372d5a6442b 100644 --- a/app/javascript/mastodon/features/ui/util/async-components.js +++ b/app/javascript/mastodon/features/ui/util/async-components.js @@ -7,7 +7,15 @@ export function Compose () { } export function Notifications () { - return import(/* webpackChunkName: "features/notifications" */'../../notifications'); + return import(/* webpackChunkName: "features/notifications_v1" */'../../notifications'); +} + +export function Notifications_v2 () { + return import(/* webpackChunkName: "features/notifications_v2" */'../../notifications_v2'); +} + +export function NotificationsWrapper () { + return import(/* webpackChunkName: "features/notifications" */'../../notifications_wrapper'); } export function HomeTimeline () { diff --git a/app/javascript/mastodon/initial_state.js b/app/javascript/mastodon/initial_state.js index 9ec3df0df87814..60b35cb31ac72e 100644 --- a/app/javascript/mastodon/initial_state.js +++ b/app/javascript/mastodon/initial_state.js @@ -15,6 +15,7 @@ * @property {boolean=} boost_modal * @property {boolean=} delete_modal * @property {boolean=} disable_swiping + * @property {boolean=} disable_hover_cards * @property {string=} disabled_account_id * @property {string} display_media * @property {string} domain @@ -86,6 +87,7 @@ export const autoPlayGif = getMeta('auto_play_gif'); export const boostModal = getMeta('boost_modal'); export const deleteModal = getMeta('delete_modal'); export const disableSwiping = getMeta('disable_swiping'); +export const disableHoverCards = getMeta('disable_hover_cards'); export const disabledAccountId = getMeta('disabled_account_id'); export const displayMedia = getMeta('display_media'); export const domain = getMeta('domain'); diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json index a9e1bdb270ebad..5509769e04085b 100644 --- a/app/javascript/mastodon/locales/ar.json +++ b/app/javascript/mastodon/locales/ar.json @@ -4,7 +4,7 @@ "about.disclaimer": "ماستدون برنامج حر ومÙتوح المصدر وعلامة تجارÙØ© لـ Mastodon GmbH.", "about.domain_blocks.no_reason_available": "السبب غÙر متوÙر", "about.domain_blocks.preamble": "Ùسمح لك ماستدون عموماً بعرض المحتوى من المستخدمÙÙ† من أ٠خادم آخر Ù٠الÙدرالÙØ© والتÙاعل معهم. وهذه ه٠الاستثناءات الت٠وضعت على هذا الخادم بالذات.", - "about.domain_blocks.silenced.explanation": "عموماً، لن ترى ملÙات التعرÙ٠والمحتوى من هذا الخادم، إلا إذا كنت تبحث عنه بشكل صرÙØ­ أو تختار أن تتابعه.", + "about.domain_blocks.silenced.explanation": "لن تظهر لك ملÙات التعرÙ٠الشخصÙØ© والمحتوى من هذا الخادوم، إلا إن بحثت عنه عمدًا أو تابعته.", "about.domain_blocks.silenced.title": "محدود", "about.domain_blocks.suspended.explanation": "لن Ùتم معالجة أ٠بÙانات من هذا الخادم أو تخزÙنها أو تبادلها، مما Ùجعل أ٠تÙاعل أو اتصال مع المستخدمÙÙ† من هذا الخادم مستحÙلا.", "about.domain_blocks.suspended.title": "Ù…Ùعلّق", @@ -21,7 +21,7 @@ "account.blocked": "محظور", "account.browse_more_on_origin_server": "تصÙØ­ المزÙد Ù٠المل٠الشخص٠الأصلÙ", "account.cancel_follow_request": "إلغاء طلب المتابعة", - "account.copy": "نسخ الرابط إلى الحساب", + "account.copy": "نسخ الرابط إلى المل٠الشخصÙ", "account.direct": "إشارة خاصة لـ @{name}", "account.disable_notifications": "توق٠عن إشعار٠عندما Ùنشر @{name}", "account.domain_blocked": "اسم النّÙطاق محظور", @@ -32,9 +32,10 @@ "account.featured_tags.last_status_never": "لا توجد رسائل", "account.featured_tags.title": "وسوم {name} الممÙÙ‘Ùزة", "account.follow": "متابعة", - "account.follow_back": "رد المتابعة", + "account.follow_back": "تابعهم بالمثل", "account.followers": "Ù…ÙتابÙعون", "account.followers.empty": "لا أحد٠ÙÙتابع هذا المÙستخدم إلى حد الآن.", + "account.followers_counter": "{count, plural, zero {}one {{counter} متابع} two {{counter} متابعÙÙ†} few {{counter} متابعÙÙ†} many {{counter} متابعÙÙ†} other {{counter} متابعÙÙ†}}", "account.following": "الاشتراكات", "account.follows.empty": "لا ÙÙتابع هذا المÙستخدم٠أÙّ٠أحد٠حتى الآن.", "account.go_to_profile": "اذهب إلى المل٠الشخصÙ", @@ -51,7 +52,7 @@ "account.mute_notifications_short": "كتم الإشعارات", "account.mute_short": "اكتم", "account.muted": "Ù…Ùكتوم", - "account.mutual": "متبادل", + "account.mutual": "متبادلة", "account.no_bio": "لم Ùتم تقدÙÙ… وصÙ.", "account.open_original_page": "اÙتح الصÙحة الأصلÙØ©", "account.posts": "منشورات", @@ -70,8 +71,8 @@ "account.unmute_notifications_short": "إلغاء ÙƒÙتم الإشعارات", "account.unmute_short": "إلغاء الكتم", "account_note.placeholder": "اضغط لإضاÙØ© Ù…Ùلاحظة", - "admin.dashboard.daily_retention": "معدل الاحتÙاظ بالمستخدم بعد التسجÙÙ„ بÙوم", - "admin.dashboard.monthly_retention": "معدل الاحتÙاظ بالمستخدم بعد التسجÙÙ„ بالشهور", + "admin.dashboard.daily_retention": "معدّل بقاء المستخدمÙÙ† بعد إنشاء الحسابات، بالأÙام", + "admin.dashboard.monthly_retention": "معدّل بقاء المستخدمÙÙ† بعد إنشاء الحسابات، بالشهور", "admin.dashboard.retention.average": "المعدل", "admin.dashboard.retention.cohort": "شهر التسجÙÙ„", "admin.dashboard.retention.cohort_size": "المستخدمون الجدد", @@ -87,12 +88,12 @@ "attachments_list.unprocessed": "(غÙر معالÙج)", "audio.hide": "إخÙاء المقطع الصوتÙ", "block_modal.remote_users_caveat": "سو٠نطلب من الخادم {domain} أن Ùحترم قرارك، لكن الالتزام غÙر مضمون لأن بعض الخوادÙÙ… قد تتعامل مع نصوص الكتل بشكل مختلÙ. قد تظل المنشورات العامة مرئÙØ© للمستخدمÙÙ† غÙر المسجلÙÙ† الدخول.", - "block_modal.show_less": "أظهر الأقل", - "block_modal.show_more": "أظهر المزÙد", + "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.they_cant_see_posts": "لن ÙستطÙع مطالعة منشوراتك ولن تطالع منشوراته.", + "block_modal.they_will_know": "سÙعلم أنه قد Ø­ÙظÙر.", + "block_modal.title": "أترÙد حظر هذا المستخدم؟", "block_modal.you_wont_see_mentions": "لن تر المنشورات الت٠ÙÙشار ÙÙهم إلÙÙ‡.", "boost_modal.combo": "ÙÙمكنك الضّغط على {combo} لتخط٠هذا Ù٠المرة المÙقبلة", "bundle_column_error.copy_stacktrace": "انسخ تقرÙر الخطأ", @@ -156,7 +157,7 @@ "compose_form.poll.single": "اختر واحدا", "compose_form.poll.switch_to_multiple": "تغÙÙÙر الاستطلاع للسماح باÙØ®Ùارات Ù…ÙتعدّÙدة", "compose_form.poll.switch_to_single": "تغÙÙÙر الاستطلاع للسماح باÙØ®Ùار واحد Ùقط", - "compose_form.poll.type": "الأسلوب", + "compose_form.poll.type": "الطراز", "compose_form.publish": "نشر", "compose_form.publish_form": "منشور جدÙد", "compose_form.reply": "ردّ", diff --git a/app/javascript/mastodon/locales/be.json b/app/javascript/mastodon/locales/be.json index 643725270c729a..df29fbd4184fdf 100644 --- a/app/javascript/mastodon/locales/be.json +++ b/app/javascript/mastodon/locales/be.json @@ -35,7 +35,9 @@ "account.follow_back": "ĐŸĐ°Đ´Đ¿Ñ–ÑĐ°Ñ†Ñ†Đ° Ñ Đ°Đ´ĐºĐ°Đ·", "account.followers": "ĐŸĐ°Đ´Đ¿Ñ–ÑÑ‡Ñ‹ĐºÑ–", "account.followers.empty": "ĐÑ–Ñ…Ñ‚Đ¾ Đ¿Đ°ĐºÑƒĐ»ÑŒ Đ½Đµ Đ¿Đ°Đ´Đ¿Ñ–ÑĐ°Đ½Ñ‹ Đ½Đ° Đ³ÑÑ‚Đ°Đ³Đ° ĐºĐ°Ñ€Ñ‹ÑÑ‚Đ°Đ»ÑŒĐ½Ñ–ĐºĐ°.", + "account.followers_counter": "{count, plural, one {{counter} Đ¿Đ°Đ´Đ¿Ñ–ÑÑ‡Ñ‹Đº} few {{counter} Đ¿Đ°Đ´Đ¿Ñ–ÑÑ‡Ñ‹ĐºÑ–} many {{counter} Đ¿Đ°Đ´Đ¿Ñ–ÑÑ‡Ñ‹ĐºĐ°Ñ} other {{counter} Đ¿Đ°Đ´Đ¿Ñ–ÑÑ‡Ñ‹ĐºĐ°}}", "account.following": "ĐŸĐ°Đ´Đ¿Ñ–ÑĐºÑ–", + "account.following_counter": "{count, plural, one {{counter} Đ¿Đ°Đ´Đ¿Ñ–ÑĐºĐ°} few {{counter} Đ¿Đ°Đ´Đ¿Ñ–ÑĐºÑ–} many {{counter} Đ¿Đ°Đ´Đ¿Ñ–ÑĐ°Đº} other {{counter} Đ¿Đ°Đ´Đ¿Ñ–ÑĐºÑ–}}", "account.follows.empty": "ĐĐ°Ñ€Ñ‹ÑÑ‚Đ°Đ»ÑŒĐ½Ñ–Đº Đ½Ñ– Đ½Đ° ĐºĐ°Đ³Đ¾ Đ½Đµ Đ¿Đ°Đ´Đ¿Ñ–ÑĐ°Đ½Ñ‹.", "account.go_to_profile": "ĐŸĐµÑ€Đ°Đ¹Ñці Đ´Đ° Đ¿Ñ€Đ¾Ñ„Ñ–Đ»Ñ", "account.hide_reblogs": "Đ¡Ñ…Đ°Đ²Đ°Ñ†ÑŒ Đ¿Đ°ÑˆÑ‹Ñ€ÑĐ½Đ½Ñ– Đ°Đ´ @{name}", @@ -61,6 +63,7 @@ "account.requested_follow": "{name} Đ°Đ´Đ¿Ñ€Đ°Đ²Ñ–Ñ Đ·Đ°Đ¿Ñ‹Ñ‚ Đ½Đ° Đ¿Đ°Đ´Đ¿Ñ–ÑĐºÑƒ", "account.share": "ĐĐ±Đ°Đ³ÑƒĐ»Ñ–Ñ†ÑŒ Đ¿Ñ€Đ¾Ñ„Ñ–Đ»ÑŒ @{name}", "account.show_reblogs": "ĐŸĐ°ĐºĐ°Đ·Đ°Ñ†ÑŒ Đ¿Đ°Đ´ÑˆÑ‚ÑƒÑ€Ñ…Đ¾ÑĐ²Đ°Đ½Đ½Ñ– Đ°Đ´ @{name}", + "account.statuses_counter": "{count, plural, one {{counter} Đ´Đ¾Đ¿Ñ–Ñ} few {{counter} Đ´Đ¾Đ¿Ñ–ÑÑ‹} many {{counter} Đ´Đ¾Đ¿Ñ–ÑĐ°Ñ} other {{counter} Đ´Đ¾Đ¿Ñ–Ñу}}", "account.unblock": "Đ Đ°Đ·Đ±Đ»Đ°ĐºÑ–Ñ€Đ°Đ²Đ°Ñ†ÑŒ @{name}", "account.unblock_domain": "Đ Đ°Đ·Đ±Đ»Đ°ĐºÑ–Ñ€Đ°Đ²Đ°Ñ†ÑŒ Đ´Đ°Đ¼ĐµĐ½ {domain}", "account.unblock_short": "Đ Đ°Đ·Đ±Đ»Đ°ĐºÑ–Ñ€Đ°Đ²Đ°Ñ†ÑŒ", @@ -412,6 +415,7 @@ "limited_account_hint.title": "Đ“ÑÑ‚Ñ‹ Đ¿Ñ€Đ¾Ñ„Ñ–Đ»ÑŒ Đ±Ñ‹Ñ ÑÑ…Đ°Đ²Đ°Đ½Ñ‹ Đ¼Đ°Đ´ÑÑ€Đ°Ñ‚Đ°Ñ€Đ°Đ¼Ñ–", "link_preview.author": "ĐĐ´ {name}", "link_preview.more_from_author": "Đ‘Đ¾Đ»ÑŒÑˆ Đ°Đ´ {name}", + "link_preview.shares": "{count, plural, one {{counter} Đ´Đ¾Đ¿Ñ–Ñ} few {{counter} Đ´Đ¾Đ¿Ñ–ÑÑ‹} many {{counter} Đ´Đ¾Đ¿Ñ–ÑĐ°Ñ} other {{counter} Đ´Đ¾Đ¿Ñ–Ñу}}", "lists.account.add": "Đ”Đ°Đ´Đ°Ñ†ÑŒ Đ´Đ° ÑĐ¿Ñ–Ñу", "lists.account.remove": "Đ’Ñ‹Đ´Đ°Đ»Ñ–Ñ†ÑŒ ÑĐ° ÑĐ¿Ñ–Ñу", "lists.delete": "Đ’Ñ‹Đ´Đ°Đ»Ñ–Ñ†ÑŒ ÑĐ¿Ñ–Ñ", diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json index 323890ba2efe8a..98e84c45d75351 100644 --- a/app/javascript/mastodon/locales/bg.json +++ b/app/javascript/mastodon/locales/bg.json @@ -35,7 +35,9 @@ "account.follow_back": "ĐŸĐ¾ÑĐ»ĐµĐ´Đ²Đ°Đ½Đµ Đ²Đ·Đ°Đ¸Đ¼Đ½Đ¾", "account.followers": "ĐŸĐ¾ÑĐ»ĐµĐ´Đ¾Đ²Đ°Ñ‚ĐµĐ»Đ¸", "account.followers.empty": "ĐÑ‰Đµ Đ½Đ¸ĐºĐ¾Đ¹ Đ½Đµ ÑĐ»ĐµĐ´Đ²Đ° Đ¿Đ¾Ñ‚Ñ€ĐµĐ±Đ¸Ñ‚ĐµĐ»Ñ.", + "account.followers_counter": "{count, plural, one {{counter} Đ¿Đ¾ÑĐ»ĐµĐ´Đ¾Đ²Đ°Ñ‚ĐµĐ»} other {{counter} Đ¿Đ¾ÑĐ»ĐµĐ´Đ¾Đ²Đ°Ñ‚ĐµĐ»Đ¸}}", "account.following": "ĐŸĐ¾ÑĐ»ĐµĐ´Đ²Đ°Đ½Đ¾", + "account.following_counter": "{count, plural, one {{counter} Đ¿Đ¾ÑĐ»ĐµĐ´Đ²Đ°Đ½} other {{counter} Đ¿Đ¾ÑĐ»ĐµĐ´Đ²Đ°Đ½Đ¸}}", "account.follows.empty": "ĐŸĐ¾Ñ‚Ñ€ĐµĐ±Đ¸Ñ‚ĐµĐ»ÑÑ‚ Đ¾Ñ‰Đµ Đ½Đ¸ĐºĐ¾Đ³Đ¾ Đ½Đµ ÑĐ»ĐµĐ´Đ²Đ°.", "account.go_to_profile": "ĐÑĐ¼ Đ¿Ñ€Đ¾Ñ„Đ¸Đ»Đ°", "account.hide_reblogs": "Đ¡ĐºÑ€Đ¸Đ²Đ°Đ½Đµ Đ½Đ° Đ¿Đ¾Đ´ÑĐ¸Đ»Đ²Đ°Đ½Đ¸Ñ Đ¾Ñ‚ @{name}", @@ -61,6 +63,7 @@ "account.requested_follow": "{name} Đ¿Đ¾Đ¸ÑĐºĐ° Đ´Đ° Đ²Đ¸ Đ¿Đ¾ÑĐ»ĐµĐ´Đ²Đ°", "account.share": "Đ¡Đ¿Đ¾Đ´ĐµĐ»ÑĐ½Đµ Đ½Đ° Đ¿Ñ€Đ¾Ñ„Đ¸Đ»Đ° Đ½Đ° @{name}", "account.show_reblogs": "ĐŸĐ¾ĐºĐ°Đ·Đ²Đ°Đ½Đµ Đ½Đ° Đ¿Đ¾Đ´ÑĐ¸Đ»Đ²Đ°Đ½Đ¸Ñ Đ¾Ñ‚ @{name}", + "account.statuses_counter": "{count, plural, one {{counter} Đ¿ÑƒĐ±Đ»Đ¸ĐºĐ°Ñ†Đ¸Ñ} other {{counter} Đ¿ÑƒĐ±Đ»Đ¸ĐºĐ°Ñ†Đ¸Đ¸}}", "account.unblock": "ĐÑ‚Đ±Đ»Đ¾ĐºĐ¸Ñ€Đ°Đ½Đµ Đ½Đ° @{name}", "account.unblock_domain": "ĐÑ‚Đ±Đ»Đ¾ĐºĐ¸Ñ€Đ°Đ½Đµ Đ½Đ° Đ´Đ¾Đ¼ĐµĐ¹Đ½ {domain}", "account.unblock_short": "ĐÑ‚Đ±Đ»Đ¾ĐºĐ¸Ñ€Đ°Đ½Đµ", diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json index e96e283970f0ae..12de5d5ecd4794 100644 --- a/app/javascript/mastodon/locales/cs.json +++ b/app/javascript/mastodon/locales/cs.json @@ -197,7 +197,7 @@ "copy_icon_button.copied": "ZkopĂ­rovĂ¡no do schrĂ¡nky", "copypaste.copied": "ZkopĂ­rovĂ¡no", "copypaste.copy_to_clipboard": "ZkopĂ­rovat do schrĂ¡nky", - "directory.federated": "Ze znĂ¡mĂ©ho fedivesmĂ­ru", + "directory.federated": "Ze znĂ¡mĂ©ho fediversu", "directory.local": "Pouze z {domain}", "directory.new_arrivals": "NovÄ› pÅ™Ă­chozĂ­", "directory.recently_active": "NedĂ¡vno aktivnĂ­", @@ -213,7 +213,7 @@ "domain_block_modal.block_account_instead": "RadÄ›ji blokovat @{name}", "domain_block_modal.they_can_interact_with_old_posts": "LidĂ© z tohoto serveru mohou interagovat s vaÅ¡imi starĂ½mi pÅ™Ă­spÄ›vky.", "domain_block_modal.they_cant_follow": "Nikdo z tohoto serveru vĂ¡s nemůže sledovat.", - "domain_block_modal.they_wont_know": "Nebude vÄ›dÄ›t, že je zablokovĂ¡n.", + "domain_block_modal.they_wont_know": "Nebude vÄ›dÄ›t, že je zablokovĂ¡n*a.", "domain_block_modal.title": "Blokovat domĂ©nu?", "domain_block_modal.you_will_lose_followers": "VÅ¡ichni vaÅ¡i sledujĂ­cĂ­ z tohoto serveru budou odstranÄ›ni.", "domain_block_modal.you_wont_see_posts": "NeuvidĂ­te pÅ™Ă­spÄ›vky ani upozornÄ›nĂ­ od uživatelů z tohoto serveru.", @@ -341,7 +341,7 @@ "hashtag.column_settings.tag_mode.any": "JakĂ½koliv z tÄ›chto", "hashtag.column_settings.tag_mode.none": "Å½Ă¡dnĂ½ z tÄ›chto", "hashtag.column_settings.tag_toggle": "Zahrnout v tomto sloupci dalÅ¡Ă­ Å¡tĂ­tky", - "hashtag.counter_by_accounts": "{count, plural, one {{counter} ĂºÄastnĂ­k} few {{counter} ĂºÄastnĂ­ci} other {{counter} ĂºÄastnĂ­ků}}", + "hashtag.counter_by_accounts": "{count, plural, one {{counter} ĂºÄastnĂ­k*ice} few {{counter} ĂºÄastnĂ­ci} other {{counter} ĂºÄastnĂ­ků}}", "hashtag.counter_by_uses": "{count, plural, one {{counter} pÅ™Ă­spÄ›vek} few {{counter} pÅ™Ă­spÄ›vky} other {{counter} pÅ™Ă­spÄ›vků}}", "hashtag.counter_by_uses_today": "Dnes {count, plural, one {{counter} pÅ™Ă­spÄ›vek} few {{counter} pÅ™Ă­spÄ›vky} other {{counter} pÅ™Ă­spÄ›vků}}", "hashtag.follow": "Sledovat hashtag", @@ -440,7 +440,7 @@ "mute_modal.show_options": "Zobrazit možnosti", "mute_modal.they_can_mention_and_follow": "Mohou vĂ¡s zmĂ­nit a sledovat, ale neuvidĂ­te je.", "mute_modal.they_wont_know": "Nebudou vÄ›dÄ›t, že byli skryti.", - "mute_modal.title": "Ztlumit uživatele?", + "mute_modal.title": "Ztlumit uživatele*ku?", "mute_modal.you_wont_see_mentions": "NeuvidĂ­te pÅ™Ă­spÄ›vky, kterĂ© je zmiňujĂ­.", "mute_modal.you_wont_see_posts": "StĂ¡le budou moci vidÄ›t vaÅ¡e pÅ™Ă­spÄ›vky, ale vy jejich neuvidĂ­te.", "navigation_bar.about": "O aplikaci", @@ -566,8 +566,8 @@ "onboarding.share.message": "Jsem {username} na #Mastodonu! PojÄ mÄ› sledovat na {url}", "onboarding.share.next_steps": "MožnĂ© dalÅ¡Ă­ kroky:", "onboarding.share.title": "SdĂ­lejte svůj profil", - "onboarding.start.lead": "Your new Mastodon account is ready to go. Here's how you can make the most of it:", - "onboarding.start.skip": "Want to skip right ahead?", + "onboarding.start.lead": "NynĂ­ jste souÄĂ¡stĂ­ Mastodonu, unikĂ¡tnĂ­ sociĂ¡lnĂ­ sĂ­tÄ›, kde vy - ne algoritmus - vytvĂ¡Å™Ă­ vaÅ¡e vlastnĂ­ prožitky. ZaÄnÄ›te na tĂ©to novĂ© sociĂ¡lnĂ­ platformÄ›:", + "onboarding.start.skip": "NepotÅ™ebujete pomoci zaÄĂ­t?", "onboarding.start.title": "DokĂ¡zali jste to!", "onboarding.steps.follow_people.body": "Mastodon je o sledovĂ¡nĂ­ zajimavĂ½ch lidĂ­.", "onboarding.steps.follow_people.title": "PÅ™ispůsobit vlastnĂ­ domovskĂ½ kanĂ¡l", @@ -581,7 +581,7 @@ "onboarding.tips.accounts_from_other_servers": "VĂ­te, že? Protože je Mastodon decentralizovanĂ½, nÄ›kterĂ© profily, na kterĂ© narazĂ­te, budou hostovĂ¡ny na jinĂ½ch serverech, než je ten vĂ¡Å¡. A pÅ™esto s nimi můžete bezproblĂ©movÄ› komunikovat! Jejich server se nachĂ¡zĂ­ v druhĂ© polovinÄ› uživatelskĂ©ho jmĂ©na!", "onboarding.tips.migration": "VĂ­te, že? Pokud mĂ¡te pocit, že {domain} pro vĂ¡s v budoucnu nenĂ­ vhodnou volbou, můžete se pÅ™esunout na jinĂ½ Mastodon server, aniž byste pÅ™iÅ¡li o svĂ© sledujĂ­cĂ­. Můžete dokonce hostovat svůj vlastnĂ­ server!", "onboarding.tips.verification": "VĂ­te, že? Svůj ĂºÄet můžete ověřit tak, že na svĂ© webovĂ© strĂ¡nky umĂ­stĂ­te odkaz na vĂ¡Å¡ Mastodon profil a odkaz na strĂ¡nku pÅ™idĂ¡te do svĂ©ho profilu. Nejsou k tomu potÅ™eba Å¾Ă¡dnĂ© poplatky ani dokumenty!", - "password_confirmation.exceeds_maxlength": "PotvrzenĂ­ hesla pÅ™ekraÄuje maximĂ¡lnĂ­ dĂ©lku hesla", + "password_confirmation.exceeds_maxlength": "PotvrzenĂ­ hesla pÅ™ekraÄuje maximĂ¡lnĂ­ povolenou dĂ©lku hesla", "password_confirmation.mismatching": "ZadanĂ¡ hesla se neshodujĂ­", "picture_in_picture.restore": "VrĂ¡tit zpÄ›t", "poll.closed": "UzavÅ™eno", @@ -665,7 +665,7 @@ "report.unfollow": "PÅ™estat sledovat @{name}", "report.unfollow_explanation": "Tento ĂºÄet sledujete. Abyste už nevidÄ›li jeho pÅ™Ă­spÄ›vky ve svĂ© domovskĂ© ÄasovĂ© ose, pÅ™estaňte jej sledovat.", "report_notification.attached_statuses": "{count, plural, one {{count} pÅ™ipojenĂ½ pÅ™Ă­spÄ›vek} few {{count} pÅ™ipojenĂ© pÅ™Ă­spÄ›vky} many {{count} pÅ™ipojenĂ½ch pÅ™Ă­spÄ›vků} other {{count} pÅ™ipojenĂ½ch pÅ™Ă­spÄ›vků}}", - "report_notification.categories.legal": "ZĂ¡konnĂ©", + "report_notification.categories.legal": "PrĂ¡vnĂ­ ustanovenĂ­", "report_notification.categories.other": "OstatnĂ­", "report_notification.categories.spam": "Spam", "report_notification.categories.violation": "PoruÅ¡enĂ­ pravidla", diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json index 1c7e61832c1f29..9a3fab6155a399 100644 --- a/app/javascript/mastodon/locales/cy.json +++ b/app/javascript/mastodon/locales/cy.json @@ -48,8 +48,8 @@ "account.mention": "Crybwyll @{name}", "account.moved_to": "Mae {name} wedi nodi fod eu cyfrif newydd yn:", "account.mute": "Tewi @{name}", - "account.mute_notifications_short": "Distewi hysbysiadau", - "account.mute_short": "Tewi", + "account.mute_notifications_short": "Diffodd hysbysiadau", + "account.mute_short": "Anwybyddu", "account.muted": "Wedi anwybyddu", "account.mutual": "Cydgydnabod", "account.no_bio": "Dim disgrifiad wedi'i gynnig.", @@ -92,7 +92,7 @@ "block_modal.they_cant_mention": "Nid ydynt yn gallu eich crybwyll na'ch dilyn.", "block_modal.they_cant_see_posts": "Nid ydynt yn gallu gweld eich postiadau ac ni fyddwch yn gweld eu rhai hwy.", "block_modal.they_will_know": "Gallant weld eu bod wedi'u rhwystro.", - "block_modal.title": "Rhwystro defnyddiwr?", + "block_modal.title": "Blocio defnyddiwr?", "block_modal.you_wont_see_mentions": "Ni welwch bostiadau sy'n sĂ´n amdanynt.", "boost_modal.combo": "Mae modd pwyso {combo} er mwyn hepgor hyn tro nesa", "bundle_column_error.copy_stacktrace": "CopĂ¯o'r adroddiad gwall", @@ -164,7 +164,7 @@ "compose_form.spoiler.marked": "Dileu rhybudd cynnwys", "compose_form.spoiler.unmarked": "Ychwanegu rhybudd cynnwys", "compose_form.spoiler_placeholder": "Rhybudd cynnwys (dewisol)", - "confirmation_modal.cancel": "Diddymu", + "confirmation_modal.cancel": "Canslo", "confirmations.block.confirm": "Blocio", "confirmations.cancel_follow_request.confirm": "Tynnu'r cais yn Ă´l", "confirmations.cancel_follow_request.message": "Ydych chi'n siŵr eich bod am dynnu'ch cais i ddilyn {name} yn Ă´l?", @@ -174,7 +174,7 @@ "confirmations.delete_list.message": "Ydych chi'n siŵr eich bod eisiau dileu'r rhestr hwn am byth?", "confirmations.discard_edit_media.confirm": "Dileu", "confirmations.discard_edit_media.message": "Mae gennych newidiadau heb eu cadw i'r disgrifiad cyfryngau neu'r rhagolwg - eu dileu beth bynnag?", - "confirmations.domain_block.confirm": "Rhwystro gweinydd", + "confirmations.domain_block.confirm": "Blocio gweinydd", "confirmations.domain_block.message": "Ydych chi wir, wir eisiau blocio'r holl {domain}? Fel arfer, mae blocio neu dewi pobl penodol yn broses mwy effeithiol. Fyddwch chi ddim yn gweld cynnwys o'r parth hwnnw mewn ffrydiau cyhoeddus neu yn eich hysbysiadau. Bydd eich dilynwyr o'r parth hwnnw yn cael eu ddileu.", "confirmations.edit.confirm": "Golygu", "confirmations.edit.message": "Bydd golygu nawr yn trosysgrifennu'r neges rydych yn ei ysgrifennu ar hyn o bryd. Ydych chi'n siŵr eich bod eisiau gwneud hyn?", @@ -201,17 +201,17 @@ "disabled_account_banner.account_settings": "Gosodiadau'r cyfrif", "disabled_account_banner.text": "Mae eich cyfrif {disabledAccount} wedi ei analluogi ar hyn o bryd.", "dismissable_banner.community_timeline": "Dyma'r postiadau cyhoeddus diweddaraf gan bobl sydd Ă¢ chyfrifon ar {domain}.", - "dismissable_banner.dismiss": "Diddymu", + "dismissable_banner.dismiss": "Cau", "dismissable_banner.explore_links": "Dyma straeon newyddion sy’n cael eu rhannu fwyaf ar y we gymdeithasol heddiw. Mae'r straeon newyddion diweddaraf sy'n cael eu postio gan fwy o unigolion gwahanol yn cael eu graddio'n uwch.", "dismissable_banner.explore_statuses": "Mae'r rhain yn bostiadau o bob rhan o'r we gymdeithasol sydd ar gynnydd heddiw. Mae postiadau mwy diweddar sydd Ă¢ mwy o hybiau a ffefrynu'n cael eu graddio'n uwch.", "dismissable_banner.explore_tags": "Mae'r rhain yn hashnodau sydd ar gynnydd ar y we gymdeithasol heddiw. Mae hashnodau sy'n cael eu defnyddio gan fwy o unigolion gwahanol yn cael eu graddio'n uwch.", "dismissable_banner.public_timeline": "Dyma'r postiadau cyhoeddus diweddaraf gan bobl ar y we gymdeithasol y mae pobl ar {domain} yn eu dilyn.", - "domain_block_modal.block": "Rhwystro gweinydd", - "domain_block_modal.block_account_instead": "Rhwystro @{name} yn lle hynny", + "domain_block_modal.block": "Blocio gweinydd", + "domain_block_modal.block_account_instead": "Blocio @{name} yn ei le", "domain_block_modal.they_can_interact_with_old_posts": "Gall pobl o'r gweinydd hwn ryngweithio Ă¢'ch hen bostiadau.", "domain_block_modal.they_cant_follow": "Ni all neb o'r gweinydd hwn eich dilyn.", - "domain_block_modal.they_wont_know": "Fyddan nhw ddim yn gwybod eu bod wedi cael eu rhwystro.", - "domain_block_modal.title": "Rhwystro parth?", + "domain_block_modal.they_wont_know": "Fyddan nhw ddim yn gwybod eu bod wedi cael eu blocio.", + "domain_block_modal.title": "Blocio parth?", "domain_block_modal.you_will_lose_followers": "Bydd eich holl ddilynwyr o'r gweinydd hwn yn cael eu tynnu.", "domain_block_modal.you_wont_see_posts": "Fyddwch chi ddim yn gweld postiadau na hysbysiadau gan ddefnyddwyr ar y gweinydd hwn.", "domain_pill.activitypub_lets_connect": "Mae'n caniatĂ¡u ichi gysylltu a rhyngweithio Ă¢ phobl nid yn unig ar Mastodon, ond ar draws gwahanol apiau cymdeithasol hefyd.", @@ -252,7 +252,7 @@ "empty_column.bookmarked_statuses": "Nid oes gennych unrhyw bostiad wedi'u cadw fel llyfrnodau eto. Pan fyddwch yn gosod nod tudalen i un, mi fydd yn ymddangos yma.", "empty_column.community": "Mae'r ffrwd lleol yn wag. Beth am ysgrifennu rhywbeth cyhoeddus!", "empty_column.direct": "Nid oes gennych unrhyw grybwylliadau preifat eto. Pan fyddwch chi'n anfon neu'n derbyn un, bydd yn ymddangos yma.", - "empty_column.domain_blocks": "Nid oes yna unrhyw barthau cuddiedig eto.", + "empty_column.domain_blocks": "Nid oes unrhyw barthau wedi'u blocio eto.", "empty_column.explore_statuses": "Does dim yn trendio ar hyn o bryd. Dewch nĂ´l nes ymlaen!", "empty_column.favourited_statuses": "Nid oes gennych unrhyw hoff bostiadau eto. Pan byddwch yn hoffi un, bydd yn ymddangos yma.", "empty_column.favourites": "Nid oes unrhyw un wedi hoffi'r postiad hwn eto. Pan fydd rhywun yn gwneud hynny, byddan nhw'n ymddangos yma.", @@ -411,6 +411,7 @@ "limited_account_hint.action": "Dangos y proffil beth bynnag", "limited_account_hint.title": "Mae'r proffil hwn wedi cael ei guddio gan gymedrolwyr {domain}.", "link_preview.author": "Gan {name}", + "link_preview.more_from_author": "Mwy gan {name}", "lists.account.add": "Ychwanegu at restr", "lists.account.remove": "Tynnu o'r rhestr", "lists.delete": "Dileu rhestr", @@ -484,9 +485,9 @@ "notification.reblog": "Hybodd {name} eich post", "notification.relationships_severance_event": "Wedi colli cysylltiad Ă¢ {name}", "notification.relationships_severance_event.account_suspension": "Mae gweinyddwr o {from} wedi atal {target}, sy'n golygu na allwch dderbyn diweddariadau ganddynt mwyach na rhyngweithio Ă¢ nhw.", - "notification.relationships_severance_event.domain_block": "Mae gweinyddwr o {from} wedi rhwystro {target}, gan gynnwys {followersCount} o'ch dilynwyr a {followingCount, plural, one {# cyfrif} other {# cyfrif}} arall rydych chi'n ei ddilyn.", + "notification.relationships_severance_event.domain_block": "Mae gweinyddwr o {from} wedi blocio {target}, gan gynnwys {followersCount} o'ch dilynwyr a {followingCount, plural, one {# cyfrif} other {# cyfrif}} arall rydych chi'n ei ddilyn.", "notification.relationships_severance_event.learn_more": "Dysgu mwy", - "notification.relationships_severance_event.user_domain_block": "Rydych wedi rhwystro {target}, gan ddileu {followersCount} o'ch dilynwyr a {followingCount, plural, one {# cyfrif} other {#cyfrifon}} arall rydych yn ei ddilyn.", + "notification.relationships_severance_event.user_domain_block": "Rydych wedi blocio {target}, gan ddileu {followersCount} o'ch dilynwyr a {followingCount, plural, one {# cyfrif} other {#cyfrifon}} arall rydych yn ei ddilyn.", "notification.status": "{name} newydd ei bostio", "notification.update": "Golygodd {name} bostiad", "notification_requests.accept": "Derbyn", @@ -803,7 +804,7 @@ "video.expand": "Ymestyn fideo", "video.fullscreen": "Sgrin llawn", "video.hide": "Cuddio fideo", - "video.mute": "Tewi sain", + "video.mute": "Diffodd sain", "video.pause": "Oedi", "video.play": "Chwarae", "video.unmute": "Dad-dewi sain" diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index 86438757a30755..0f3b3c91a9bfd0 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -205,10 +205,10 @@ "disabled_account_banner.text": "Dein Konto {disabledAccount} ist derzeit deaktiviert.", "dismissable_banner.community_timeline": "Das sind die neuesten öffentlichen Beiträge von Profilen, deren Konten von {domain} verwaltet werden.", "dismissable_banner.dismiss": "Ablehnen", - "dismissable_banner.explore_links": "Diese Nachrichten werden heute am häufigsten im sozialen Netzwerk geteilt. Neuere Nachrichten, die von vielen verschiedenen Profilen veröffentlicht wurden, werden höher eingestuft.", - "dismissable_banner.explore_statuses": "Diese Beiträge stammen aus dem gesamten sozialen Netzwerk und gewinnen derzeit an Reichweite. Neuere Beiträge, die häufiger geteilt und favorisiert wurden, werden höher eingestuft.", - "dismissable_banner.explore_tags": "Das sind Hashtags, die derzeit an Reichweite gewinnen. Hashtags, die von vielen verschiedenen Profilen verwendet werden, werden höher eingestuft.", - "dismissable_banner.public_timeline": "Das sind die neuesten öffentlichen Beiträge von Profilen im sozialen Netzwerk, denen Leute auf {domain} folgen.", + "dismissable_banner.explore_links": "Diese Nachrichten werden heute am häufigsten im Social Web geteilt. Neuere Nachrichten, die von vielen verschiedenen Profilen geteilt wurden, erscheinen weiter oben.", + "dismissable_banner.explore_statuses": "Diese Beiträge sind heute im Social Web sehr beliebt. Neuere Beiträge, die häufiger geteilt und favorisiert wurden, erscheinen weiter oben.", + "dismissable_banner.explore_tags": "Diese Hashtags sind heute im Social Web sehr beliebt. Hashtags, die von vielen verschiedenen Profilen verwendet werden, erscheinen weiter oben.", + "dismissable_banner.public_timeline": "Das sind die neuesten öffentlichen Beiträge von Profilen im Social Web, denen Leute auf {domain} folgen.", "domain_block_modal.block": "Server blockieren", "domain_block_modal.block_account_instead": "Stattdessen @{name} blockieren", "domain_block_modal.they_can_interact_with_old_posts": "Profile von diesem Server werden mit deinen älteren Beiträgen interagieren können.", diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index 13296e1d204479..60bdfd1d445471 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -443,6 +443,8 @@ "mute_modal.title": "Mute user?", "mute_modal.you_wont_see_mentions": "You won't see posts that mention them.", "mute_modal.you_wont_see_posts": "They can still see your posts, but you won't see theirs.", + "name_and_others": "{name} and {count, plural, one {# other} other {# others}}", + "name_and_others_with_link": "{name} and {count, plural, one {# other} other {# others}}", "navigation_bar.about": "About", "navigation_bar.advanced_interface": "Open in advanced web interface", "navigation_bar.blocks": "Blocked users", @@ -470,6 +472,10 @@ "navigation_bar.security": "Security", "not_signed_in_indicator.not_signed_in": "You need to login to access this resource.", "notification.admin.report": "{name} reported {target}", + "notification.admin.report_account": "{name} reported {count, plural, one {one post} other {# posts}} from {target} for {category}", + "notification.admin.report_account_other": "{name} reported {count, plural, one {one post} other {# posts}} from {target}", + "notification.admin.report_statuses": "{name} reported {target} for {category}", + "notification.admin.report_statuses_other": "{name} reported {target}", "notification.admin.sign_up": "{name} signed up", "notification.favourite": "{name} favorited your post", "notification.follow": "{name} followed you", @@ -485,7 +491,8 @@ "notification.moderation_warning.action_silence": "Your account has been limited.", "notification.moderation_warning.action_suspend": "Your account has been suspended.", "notification.own_poll": "Your poll has ended", - "notification.poll": "A poll you have voted in has ended", + "notification.poll": "A poll you voted in has ended", + "notification.private_mention": "{name} privately mentioned you", "notification.reblog": "{name} boosted your post", "notification.relationships_severance_event": "Lost connections with {name}", "notification.relationships_severance_event.account_suspension": "An admin from {from} has suspended {target}, which means you can no longer receive updates from them or interact with them.", @@ -503,6 +510,8 @@ "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.beta.category": "Experimental features", + "notifications.column_settings.beta.grouping": "Group notifications", "notifications.column_settings.favourite": "Favorites:", "notifications.column_settings.filter_bar.advanced": "Display all categories", "notifications.column_settings.filter_bar.category": "Quick filter bar", @@ -666,9 +675,13 @@ "report.unfollow_explanation": "You are following this account. To not see their posts in your home feed anymore, unfollow them.", "report_notification.attached_statuses": "{count, plural, one {{count} post} other {{count} posts}} attached", "report_notification.categories.legal": "Legal", + "report_notification.categories.legal_sentence": "illegal content", "report_notification.categories.other": "Other", + "report_notification.categories.other_sentence": "other", "report_notification.categories.spam": "Spam", + "report_notification.categories.spam_sentence": "spam", "report_notification.categories.violation": "Rule violation", + "report_notification.categories.violation_sentence": "rule violation", "report_notification.open": "Open report", "search.no_recent_searches": "No recent searches", "search.placeholder": "Search", diff --git a/app/javascript/mastodon/locales/ga.json b/app/javascript/mastodon/locales/ga.json index edf7618148ecff..8c5039e2a46b4f 100644 --- a/app/javascript/mastodon/locales/ga.json +++ b/app/javascript/mastodon/locales/ga.json @@ -17,22 +17,28 @@ "account.badges.group": "GrĂºpa", "account.block": "DĂ©an cosc ar @{name}", "account.block_domain": "Bac ainm fearainn {domain}", + "account.block_short": "Bloc", "account.blocked": "Bactha", "account.browse_more_on_origin_server": "BrabhsĂ¡il nĂ­os mĂ³ ar an phrĂ³ifĂ­l bhunaidh", "account.cancel_follow_request": "Éirigh as iarratas leanta", + "account.copy": "CĂ³ipeĂ¡il nasc chuig an bprĂ³ifĂ­l", + "account.direct": "Luaigh @{name} go prĂ­obhĂ¡ideach", "account.disable_notifications": "Éirigh as ag cuir mĂ© in eol nuair bpostĂ¡lann @{name}", "account.domain_blocked": "Ainm fearainn bactha", "account.edit_profile": "Cuir an phrĂ³ifĂ­l in eagar", "account.enable_notifications": "Cuir mĂ© in eol nuair bpostĂ¡lann @{name}", "account.endorse": "Cuir ar an phrĂ³ifĂ­l mar ghnĂ©", "account.featured_tags.last_status_at": "PostĂ¡il is dĂ©anaĂ­ ar {date}", - "account.featured_tags.last_status_never": "NĂ­l postĂ¡il ar bith ann", - "account.featured_tags.title": "Haischlib {name}", + "account.featured_tags.last_status_never": "Gan aon phoist", + "account.featured_tags.title": "Haischlib faoi thrĂ¡cht {name}", "account.follow": "Lean", + "account.follow_back": "LeanĂºint ar ais", "account.followers": "LeantĂ³irĂ­", "account.followers.empty": "NĂ­ leanann Ă©inne an t-ĂºsĂ¡ideoir seo fĂ³s.", + "account.followers_counter": "{count, plural, one {{counter} leantĂ³ir} other {{counter} leantĂ³irĂ­}}", "account.following": "Ag leanĂºint", - "account.follows.empty": "NĂ­ leanann an t-ĂºsĂ¡ideoir seo duine ar bith fĂ³s.", + "account.following_counter": "{count, plural, one {{counter} ag leanĂºint} other {{counter} ag leanĂºint}}", + "account.follows.empty": "NĂ­ leanann an t-ĂºsĂ¡ideoir seo aon duine go fĂ³ill.", "account.go_to_profile": "TĂ©igh go dtĂ­ prĂ³ifĂ­l", "account.hide_reblogs": "Folaigh moltaĂ­ Ă³ @{name}", "account.in_memoriam": "CuimhneachĂ¡n.", @@ -40,11 +46,15 @@ "account.languages": "Athraigh teangacha foscrĂ­ofa", "account.link_verified_on": "SeiceĂ¡ladh ĂºinĂ©ireacht an naisc seo ar {date}", "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": "Ăbhair", + "account.media": "MeĂ¡in", "account.mention": "Luaigh @{name}", "account.moved_to": "TĂ¡ tugtha le fios ag {name} gurb Ă© an cuntas nua atĂ¡ acu nĂ¡:", "account.mute": "Balbhaigh @{name}", + "account.mute_notifications_short": "Balbhaigh fĂ³graĂ­", + "account.mute_short": "Balbhaigh", "account.muted": "Balbhaithe", + "account.mutual": "FrithphĂ¡irteach", + "account.no_bio": "NĂ­or tugadh tuairisc.", "account.open_original_page": "Oscail an leathanach bunaidh", "account.posts": "PostĂ¡lacha", "account.posts_with_replies": "PostĂ¡lacha agus freagraĂ­", @@ -53,12 +63,14 @@ "account.requested_follow": "D'iarr {name} ort do chuntas a leanĂºint", "account.share": "Roinn prĂ³ifĂ­l @{name}", "account.show_reblogs": "TaispeĂ¡in moltaĂ­ Ă³ @{name}", + "account.statuses_counter": "{count, plural, one {{counter} post} other {{counter} poist}}", "account.unblock": "Bain bac de @{name}", "account.unblock_domain": "Bain bac den ainm fearainn {domain}", - "account.unblock_short": "Bain bac de", + "account.unblock_short": "DĂ­bhlocĂ¡il", "account.unendorse": "NĂ¡ chuir ar an phrĂ³ifĂ­l mar ghnĂ©", "account.unfollow": "NĂ¡ lean a thuilleadh", "account.unmute": "DĂ­bhalbhaigh @{name}", + "account.unmute_notifications_short": "DĂ­bhalbhaigh fĂ³graĂ­", "account.unmute_short": "DĂ­bhalbhaigh", "account_note.placeholder": "CliceĂ¡il chun nĂ³ta a chuir leis", "admin.dashboard.daily_retention": "RĂ¡ta coinneĂ¡la an ĂºsĂ¡ideora de rĂ©ir an lae tar Ă©is clĂ¡rĂº", @@ -66,6 +78,10 @@ "admin.dashboard.retention.average": "MeĂ¡n", "admin.dashboard.retention.cohort": "MĂ­ clĂ¡raraithe", "admin.dashboard.retention.cohort_size": "ĂsĂ¡ideoirĂ­ nua", + "admin.impact_report.instance_accounts": "PrĂ³ifĂ­lĂ­ cuntais a scriosfadh sĂ© seo", + "admin.impact_report.instance_followers": "LeanĂºna a chaillfeadh Ă¡r n-ĂºsĂ¡ideoirĂ­", + "admin.impact_report.instance_follows": "LeanĂºna a bheadh ​​​​a n-ĂºsĂ¡ideoirĂ­ chailleadh", + "admin.impact_report.title": "Achoimre ar an tionchar", "alert.rate_limited.message": "Atriail aris tar Ă©is {retry_time, time, medium}.", "alert.rate_limited.title": "RĂ¡tatheoranta", "alert.unexpected.message": "Tharla earrĂ¡id gan choinne.", @@ -73,10 +89,18 @@ "announcement.announcement": "FĂ³gra", "attachments_list.unprocessed": "(neamhphrĂ³iseĂ¡ilte)", "audio.hide": "Cuir fuaim i bhfolach", + "block_modal.remote_users_caveat": "Iarrfaimid ar an bhfreastalaĂ­ {domain} meas a bheith agat ar do chinneadh. Mar sin fĂ©in, nĂ­ rĂ¡thaĂ­tear comhlĂ­onadh toisc go bhfĂ©adfadh roinnt freastalaithe bloic a lĂ¡imhseĂ¡il ar bhealach difriĂºil. Seans go mbeidh postĂ¡lacha poiblĂ­ fĂ³s le feiceĂ¡il ag ĂºsĂ¡ideoirĂ­ nach bhfuil logĂ¡ilte isteach.", + "block_modal.show_less": "TaispeĂ¡in nĂ­os lĂº", + "block_modal.show_more": "TaispeĂ¡in nĂ­os mĂ³", + "block_modal.they_cant_mention": "NĂ­ fĂ©idir leo tĂº a lua nĂ¡ a leanĂºint.", + "block_modal.they_cant_see_posts": "NĂ­ fĂ©idir leo do chuid postĂ¡lacha a fheiceĂ¡il agus nĂ­ fheicfidh tĂº a gcuid postanna.", + "block_modal.they_will_know": "Is fĂ©idir leo a fheiceĂ¡il go bhfuil bac orthu.", + "block_modal.title": "An bhfuil fonn ort an t-ĂºsĂ¡ideoir a bhlocĂ¡il?", + "block_modal.you_wont_see_mentions": "NĂ­ fheicfidh tĂº postĂ¡lacha a luann iad.", "boost_modal.combo": "Is fĂ©idir leat {combo} a bhrĂº chun Ă© seo a scipeĂ¡il an chĂ©ad uair eile", "bundle_column_error.copy_stacktrace": "CĂ³ipeĂ¡il tuairisc earrĂ¡ide", "bundle_column_error.error.body": "NĂ­ fĂ©idir an leathanach a iarradh a sholĂ¡thar. Seans gurb amhlaidh mar gheall ar fhabht sa chĂ³d, nĂ³ mar gheall ar mhĂ­rĂ©ireacht leis an mbrabhsĂ¡laĂ­.", - "bundle_column_error.error.title": "NĂ¡ habair!", + "bundle_column_error.error.title": "Ă“, nĂ­l sĂ© sin go maith!", "bundle_column_error.network.body": "Tharla earrĂ¡id agus an leathanach Ă¡ lĂ³dĂ¡il. Seans gur mar gheall ar fhadhb shealadach le do nasc idirlĂ­n nĂ³ i ndĂ¡il leis an bhfreastalaĂ­ seo atĂ¡ sĂ©.", "bundle_column_error.network.title": "EarrĂ¡id lĂ­onra", "bundle_column_error.retry": "Bain triail as arĂ­s", @@ -95,8 +119,11 @@ "column.blocks": "Cuntais choiscthe", "column.bookmarks": "Leabharmharcanna", "column.community": "AmlĂ­ne Ă¡itiĂºil", + "column.direct": "Luann prĂ­obhĂ¡ideach", "column.directory": "BrabhsĂ¡il prĂ³ifĂ­lĂ­", "column.domain_blocks": "Fearainn bhactha", + "column.favourites": "CeanĂ¡in", + "column.firehose": "FothaĂ­ beo", "column.follow_requests": "Iarratais leanĂºnaĂ­", "column.home": "Baile", "column.lists": "LiostaĂ­", @@ -108,15 +135,18 @@ "column_header.hide_settings": "Folaigh socruithe", "column_header.moveLeft_settings": "Bog an colĂºn ar chlĂ©", "column_header.moveRight_settings": "Bog an colĂºn ar dheis", - "column_header.pin": "Greamaigh", + "column_header.pin": "Pionna", "column_header.show_settings": "TaispeĂ¡in socruithe", - "column_header.unpin": "DĂ­ghreamaigh", + "column_header.unpin": "Bain pionna", "column_subheading.settings": "Socruithe", "community.column_settings.local_only": "ĂitiĂºil amhĂ¡in", "community.column_settings.media_only": "MeĂ¡in AmhĂ¡in", "community.column_settings.remote_only": "Cian amhĂ¡in", "compose.language.change": "Athraigh teanga", "compose.language.search": "Cuardaigh teangacha...", + "compose.published.body": "Post foilsithe.", + "compose.published.open": "Oscail", + "compose.saved.body": "PostĂ¡il sĂ¡bhĂ¡ilte.", "compose_form.direct_message_warning_learn_more": "Tuilleadh eolais", "compose_form.encryption_warning": "NĂ­ criptiĂº taobh-go-taobh dĂ©anta ar theachtaireachtaĂ­ ar Mhastodon. NĂ¡ roinn eolas Ă­ogair ar Mhastodon.", "compose_form.hashtag_warning": "NĂ­ Ă¡ireofar an teachtaireacht seo faoi haischlib ar bith mar nĂ­l sĂ­ ar fĂ¡il don phobal. NĂ­ fĂ©idir ach teachtaireachtaĂ­ poiblĂ­ a chuardach de rĂ©ir haischlib.", @@ -124,11 +154,19 @@ "compose_form.lock_disclaimer.lock": "faoi ghlas", "compose_form.placeholder": "Cad atĂ¡ ag tarlĂº?", "compose_form.poll.duration": "Achar suirbhĂ©anna", + "compose_form.poll.multiple": "Ilrogha", + "compose_form.poll.option_placeholder": "Rogha {number}", + "compose_form.poll.single": "Roghnaigh ceann amhĂ¡in", "compose_form.poll.switch_to_multiple": "Athraigh suirbhĂ© chun cead a thabhairt do ilrogha", "compose_form.poll.switch_to_single": "Athraigh suirbhĂ© chun cead a thabhairt do rogha amhĂ¡in", - "compose_form.publish_form": "Foilsigh\n", + "compose_form.poll.type": "StĂ­l", + "compose_form.publish": "PostĂ¡il", + "compose_form.publish_form": "Post nua", + "compose_form.reply": "Freagra", + "compose_form.save_changes": "NuashonrĂº", "compose_form.spoiler.marked": "Bain rabhadh Ă¡bhair", "compose_form.spoiler.unmarked": "Cuir rabhadh Ă¡bhair", + "compose_form.spoiler_placeholder": "Rabhadh Ă¡bhair (roghnach)", "confirmation_modal.cancel": "Cealaigh", "confirmations.block.confirm": "Bac", "confirmations.cancel_follow_request.confirm": "Éirigh as iarratas", @@ -139,11 +177,15 @@ "confirmations.delete_list.message": "An bhfuil tĂº cinnte gur mhaith leat an liosta seo a scriosadh go buan?", "confirmations.discard_edit_media.confirm": "Faigh rĂ©idh de", "confirmations.discard_edit_media.message": "TĂ¡ athruithe neamhshlĂ¡naithe don tuarascĂ¡il gnĂ© nĂ³ rĂ©amhamharc agat, faigh rĂ©idh dĂ³ibh ar aon nĂ³s?", + "confirmations.domain_block.confirm": "Bloc freastalaĂ­", "confirmations.domain_block.message": "An bhfuil tĂº iontach cinnte gur mhaith leat bac an t-ainm fearainn {domain} in iomlĂ¡n? I bhformhĂ³r na gcĂ¡sanna, is leor agus is fearr cĂºpla baic a cur i bhfeidhm nĂ³ cĂºpla ĂºsĂ¡ideoirĂ­ a balbhĂº. NĂ­ fheicfidh tĂº Ă¡bhair Ă³n t-ainm fearainn sin in amlĂ­ne ar bith, nĂ³ i d'fhĂ³graĂ­. Scaoilfear do leantĂ³irĂ­ Ă³n ainm fearainn sin.", + "confirmations.edit.confirm": "Eagar", + "confirmations.edit.message": "MĂ¡ dhĂ©anann tĂº eagarthĂ³ireacht anois, dĂ©anfar an teachtaireacht atĂ¡ Ă¡ cumadh agat faoi lĂ¡thair a fhorscrĂ­obh. An bhfuil tĂº cinnte gur mhaith leat leanĂºint ar aghaidh?", "confirmations.logout.confirm": "LogĂ¡il amach", "confirmations.logout.message": "An bhfuil tĂº cinnte gur mhaith leat logĂ¡il amach?", "confirmations.mute.confirm": "Balbhaigh", "confirmations.redraft.confirm": "Scrios â athdhrĂ©achtaigh", + "confirmations.redraft.message": "An bhfuil tĂº cinnte gur mhaith leat an postĂ¡il seo a scriosadh agus Ă© a athdhrĂ©achtĂº? Caillfear ceanĂ¡in agus treisithe, agus dĂ­lleachtaĂ­ freagraĂ­ ar an mbunphostĂ¡la.", "confirmations.reply.confirm": "Freagair", "confirmations.reply.message": "Scriosfaidh freagra lĂ¡ithreach an teachtaireacht atĂ¡ a chumadh anois agat. An bhfuil tĂº cinnte gur mhaith leat leanĂºint leat?", "confirmations.unfollow.confirm": "NĂ¡ lean", @@ -152,7 +194,9 @@ "conversation.mark_as_read": "MarcĂ¡il mar lĂ©ite", "conversation.open": "FĂ©ach ar comhrĂ¡", "conversation.with": "Le {names}", + "copy_icon_button.copied": "CĂ³ipeĂ¡ladh chuig an ngearrthaisce", "copypaste.copied": "CĂ³ipeĂ¡ilte", + "copypaste.copy_to_clipboard": "CĂ³ipeĂ¡il chuig an ngearrthaisce", "directory.federated": "Ă“ chomhchruinne aitheanta", "directory.local": "Ă“ {domain} amhĂ¡in", "directory.new_arrivals": "Daoine atĂ¡ tar Ă©is teacht", @@ -162,7 +206,30 @@ "dismissable_banner.community_timeline": "Seo iad na postĂ¡la is dĂ©anaĂ­ Ă³ dhaoine le cuntais ar {domain}.", "dismissable_banner.dismiss": "DiĂºltaigh", "dismissable_banner.explore_links": "TĂ¡ na scĂ©alta nuachta seo Ă¡ phlĂ© anseo agus ar fhreastalaithe eile ar an lĂ­onra dĂ­lĂ¡raithe faoi lĂ¡thair.", + "dismissable_banner.explore_statuses": "Is postĂ¡lacha iad seo Ă³ ar fud an ghrĂ©asĂ¡in shĂ³isialta atĂ¡ ag Ă©irĂ­ nĂ­os tarraingtĂ­ inniu. RangaĂ­tear poist nĂ­os nuaĂ­ le nĂ­os mĂ³ teanntĂ¡in agus ceanĂ¡in nĂ­os airde.", "dismissable_banner.explore_tags": "These hashtags are gaining traction among people on this and other servers of the decentralized network right now.", + "dismissable_banner.public_timeline": "Seo iad na postĂ¡lacha poiblĂ­ is dĂ©anaĂ­ Ă³ dhaoine ar an ngrĂ©asĂ¡n sĂ³isialta a leanann daoine ar {domain}.", + "domain_block_modal.block": "Bloc freastalaĂ­", + "domain_block_modal.block_account_instead": "Cuir bac ar @{name} ina ionad sin", + "domain_block_modal.they_can_interact_with_old_posts": "Is fĂ©idir le daoine Ă³n bhfreastalaĂ­ seo idirghnĂ­omhĂº le do sheanphoist.", + "domain_block_modal.they_cant_follow": "NĂ­ fĂ©idir le duine ar bith Ă³n bhfreastalaĂ­ seo tĂº a leanĂºint.", + "domain_block_modal.they_wont_know": "NĂ­ bheidh a fhios acu go bhfuil bac orthu.", + "domain_block_modal.title": "BlocĂ¡il fearann?", + "domain_block_modal.you_will_lose_followers": "Bainfear do leantĂ³irĂ­ go lĂ©ir Ă³n bhfreastalaĂ­ seo.", + "domain_block_modal.you_wont_see_posts": "NĂ­ fheicfidh tĂº postĂ¡lacha nĂ³ fĂ³graĂ­ Ă³ ĂºsĂ¡ideoirĂ­ ar an bhfreastalaĂ­ seo.", + "domain_pill.activitypub_lets_connect": "Ligeann sĂ© duit ceangal agus idirghnĂ­omhĂº le daoine, nĂ­ hamhĂ¡in ar Mastodon, ach thar aipeanna sĂ³isialta Ă©agsĂºla freisin.", + "domain_pill.activitypub_like_language": "TĂ¡ GnĂ­omhaĂ­ochtPub cosĂºil leis an teanga a labhraĂ­onn Mastodon le lĂ­onraĂ­ sĂ³isialta eile.", + "domain_pill.server": "FreastalaĂ­", + "domain_pill.their_handle": "A lĂ¡imhseĂ¡il:", + "domain_pill.their_server": "A dteach digiteach, Ă¡it a bhfuil a gcuid post go lĂ©ir ina gcĂ³naĂ­.", + "domain_pill.their_username": "AitheantĂ³ir uathĂºil ar a bhfreastalaĂ­. Is fĂ©idir teacht ar ĂºsĂ¡ideoirĂ­ leis an ainm ĂºsĂ¡ideora cĂ©anna ar fhreastalaithe Ă©agsĂºla.", + "domain_pill.username": "Ainm ĂºsĂ¡ideora", + "domain_pill.whats_in_a_handle": "Cad atĂ¡ i lĂ¡imhseĂ¡il?", + "domain_pill.who_they_are": "Ă“s rud Ă© go ndeir lĂ¡imhseĂ¡laithe cĂ© hĂ© duine agus cĂ¡ bhfuil siad, is fĂ©idir leat idirghnĂ­omhĂº le daoine ar fud an ghrĂ©asĂ¡in shĂ³isialta de .", + "domain_pill.who_you_are": "Toisc go ndeir do lĂ¡imhseĂ¡il cĂ© tĂº fĂ©in agus cĂ©n Ă¡it a bhfuil tĂº, is fĂ©idir le daoine idirghnĂ­omhĂº leat ar fud an ghrĂ©asĂ¡in shĂ³isialta de .", + "domain_pill.your_handle": "Do lĂ¡imhseĂ¡il:", + "domain_pill.your_server": "Do theach digiteach, Ă¡it a bhfuil do phoist go lĂ©ir ina gcĂ³naĂ­. Nach maith leat an ceann seo? Aistrigh freastalaithe am ar bith agus tabhair leat do leantĂ³irĂ­ freisin.", + "domain_pill.your_username": "D'aitheantĂ³ir uathĂºil ar an bhfreastalaĂ­ seo. Is fĂ©idir teacht ar ĂºsĂ¡ideoirĂ­ leis an ainm ĂºsĂ¡ideora cĂ©anna ar fhreastalaithe Ă©agsĂºla.", "embed.instructions": "Embed this status on your website by copying the code below.", "embed.preview": "Seo an chuma a bheidh air:", "emoji_button.activity": "GnĂ­omhaĂ­ocht", @@ -180,49 +247,81 @@ "emoji_button.search_results": "TorthaĂ­ cuardaigh", "emoji_button.symbols": "ComharthaĂ­", "emoji_button.travel": "Taisteal â Ăiteanna", + "empty_column.account_hides_collections": "Roghnaigh an t-ĂºsĂ¡ideoir seo gan an fhaisnĂ©is seo a chur ar fĂ¡il", "empty_column.account_suspended": "Cuntas ar fionraĂ­", "empty_column.account_timeline": "NĂ­l postĂ¡lacha ar bith anseo!", "empty_column.account_unavailable": "NĂ­l an phrĂ³ifĂ­l ar fĂ¡il", "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.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.domain_blocks": "NĂ­l aon fearainn bhactha ann go fĂ³ill.", "empty_column.explore_statuses": "NĂ­l rud ar bith ag treochtĂ¡il faoi lĂ¡thair. Tar ar ais ar ball!", + "empty_column.favourited_statuses": "NĂ­l aon postĂ¡lacha is fearr leat fĂ³s. Nuair is fearr leat ceann, beidh sĂ© le feiceĂ¡il anseo.", + "empty_column.favourites": "NĂ­or thaitin an post seo le haon duine go fĂ³ill. Nuair a dhĂ©anann duine, taispeĂ¡nfaidh siad suas anseo.", "empty_column.follow_requests": "NĂ­l aon phostĂ¡il leabharmharcaithe agat fĂ³s. Nuair a dhĂ©anann tĂº leabharmharc, feicfear anseo Ă©.", + "empty_column.followed_tags": "NĂ­or lean tĂº aon hashtags fĂ³s. Nuair a dhĂ©anann tĂº, beidh siad a thaispeĂ¡int suas anseo.", "empty_column.hashtag": "NĂ­l rud ar bith faoin haischlib seo go fĂ³ill.", "empty_column.home": "TĂ¡ d'amlĂ­ne baile folamh! B'fhiĂº duit cĂºpla duine eile a leanĂºint lena lĂ­onadh! {suggestions}", "empty_column.list": "There is nothing in this list yet. When members of this list post new statuses, they will appear here.", "empty_column.lists": "NĂ­l aon liostaĂ­ fĂ³s agat. Nuair a chruthaĂ­onn tĂº ceann, feicfear anseo Ă©.", "empty_column.mutes": "NĂ­l aon ĂºsĂ¡ideoir balbhaithe agat fĂ³s.", + "empty_column.notification_requests": "Gach soilĂ©ir! NĂ­l aon rud anseo. Nuair a gheobhaidh tĂº fĂ³graĂ­ nua, beidh siad le feiceĂ¡il anseo de rĂ©ir do shocruithe.", "empty_column.notifications": "NĂ­l aon fĂ³graĂ­ agat fĂ³s. Nuair a dhĂ©anann daoine eile idirghnĂ­omhĂº leat, feicfear anseo Ă©.", "empty_column.public": "Faic anseo! ScrĂ­obh rud Ă©igin go poiblĂ­, nĂ³ lean ĂºsĂ¡ideoirĂ­ ar fhreastalaithe eile chun Ă© a lĂ­onadh", "error.unexpected_crash.explanation": "De bharr fabht inĂ¡r gcĂ³d, nĂ³ fadhb le chomhoiriĂºnacht brabhsĂ¡laĂ­, nĂ­orbh fhĂ©adfadh an leathanach seo a lĂ©iriĂº i gceart.", "error.unexpected_crash.explanation_addons": "NĂ­ taispeĂ¡ntar an leathanach seo mar is ceart. Is dĂ³cha go gcruthaĂ­onn breiseĂ¡n brabhsĂ¡laĂ­ nĂ³ uirlisĂ­ uathaistriĂºchĂ¡in an fhadhb seo.", + "error.unexpected_crash.next_steps": "Bain triail as an leathanach a athnuachan. Mura gcabhraĂ­onn sĂ© sin, seans go mbeidh tĂº fĂ³s in ann Mastodon a ĂºsĂ¡id trĂ­ bhrabhsĂ¡laĂ­ nĂ³ aip dhĂºchais eile.", + "error.unexpected_crash.next_steps_addons": "DĂ©an iarracht iad a dhĂ­chumasĂº agus an leathanach a athnuachan. Mura gcabhraĂ­onn sĂ© sin, seans go mbeidh tĂº fĂ³s in ann Mastodon a ĂºsĂ¡id trĂ­ bhrabhsĂ¡laĂ­ nĂ³ aip dhĂºchais eile.", + "errors.unexpected_crash.copy_stacktrace": "CĂ³ipeĂ¡il rian cruachta go dtĂ­ an ghearrthaisce", "errors.unexpected_crash.report_issue": "Tuairiscigh deacracht", "explore.search_results": "TorthaĂ­ cuardaigh", + "explore.suggested_follows": "Daoine", "explore.title": "FĂ©ach thart", "explore.trending_links": "Nuacht", "explore.trending_statuses": "PostĂ¡lacha", "explore.trending_tags": "Haischlibeanna", + "filter_modal.added.context_mismatch_explanation": "NĂ­ bhaineann an chatagĂ³ir scagaire seo leis an gcomhthĂ©acs ina bhfuair tĂº rochtain ar an bpostĂ¡il seo. MĂ¡s mian leat an postĂ¡il a scagadh sa chomhthĂ©acs seo freisin, beidh ort an scagaire a chur in eagar.", + "filter_modal.added.context_mismatch_title": "NeamhrĂ©ir comhthĂ©acs!", + "filter_modal.added.expired_explanation": "TĂ¡ an chatagĂ³ir scagaire seo imithe in Ă©ag, beidh ort an dĂ¡ta Ă©aga a athrĂº chun Ă© a chur i bhfeidhm.", "filter_modal.added.expired_title": "Scagaire as feidhm!", + "filter_modal.added.review_and_configure": "Chun an chatagĂ³ir scagaire seo a athbhreithniĂº agus a chumrĂº tuilleadh, tĂ©igh chuig {settings_link}.", "filter_modal.added.review_and_configure_title": "Socruithe scagtha", "filter_modal.added.settings_link": "leathan socruithe", + "filter_modal.added.short_explanation": "Cuireadh an postĂ¡il seo leis an gcatagĂ³ir scagaire seo a leanas: {title}.", "filter_modal.added.title": "Scagaire curtha leis!", "filter_modal.select_filter.context_mismatch": "nĂ­ bhaineann sĂ© leis an gcomhthĂ©acs seo", - "filter_modal.select_filter.expired": "as feidhm", + "filter_modal.select_filter.expired": "imithe in Ă©ag", "filter_modal.select_filter.prompt_new": "CatagĂ³ir nua: {name}", "filter_modal.select_filter.search": "Cuardaigh nĂ³ cruthaigh", "filter_modal.select_filter.subtitle": "Bain ĂºsĂ¡id as catagĂ³ir reatha nĂ³ cruthaigh ceann nua", "filter_modal.select_filter.title": "DĂ©an scagadh ar an bpostĂ¡il seo", "filter_modal.title.status": "DĂ©an scagadh ar phostĂ¡il", + "filtered_notifications_banner.mentions": "{count, plural, one {tagairt} other {tagairtĂ­}}", + "filtered_notifications_banner.pending_requests": "FĂ³graĂ­ Ă³ {count, plural, =0 {nĂ­l Ă©inne} one {duine amhĂ¡in} two {# daoine} few {# daoine} many {# daoine} other {# daoine}} b'fhĂ©idir go mbeadh a fhios agat", + "filtered_notifications_banner.title": "FĂ³graĂ­ scagtha", + "firehose.all": "Gach", + "firehose.local": "An freastalaĂ­ seo", + "firehose.remote": "Freastalaithe eile", "follow_request.authorize": "Ceadaigh", "follow_request.reject": "DiĂºltaigh", "follow_requests.unlocked_explanation": "CĂ© nach bhfuil do chuntas faoi ghlas, cheap foireann {domain} gur mhaith leat sĂºil siar ar iarratais leanĂºnaĂ­ as na cuntais seo.", + "follow_suggestions.curated_suggestion": "Pioc foirne", "follow_suggestions.dismiss": "NĂ¡ taispeĂ¡in arĂ­s", + "follow_suggestions.featured_longer": "LĂ¡mh-roghnaithe ag an bhfoireann {domain}", + "follow_suggestions.friends_of_friends_longer": "Coitianta i measc na ndaoine a leanann tĂº", + "follow_suggestions.hints.featured": "TĂ¡ an phrĂ³ifĂ­l seo roghnaithe de lĂ¡imh ag foireann {domain}.", + "follow_suggestions.hints.friends_of_friends": "TĂ¡ an-tĂ³ir ar an bprĂ³ifĂ­l seo i measc na ndaoine a leanann tĂº.", + "follow_suggestions.hints.most_followed": "TĂ¡ an phrĂ³ifĂ­l seo ar cheann de na cinn is mĂ³ a leantar ar {domain}.", + "follow_suggestions.hints.most_interactions": "TĂ¡ an phrĂ³ifĂ­l seo ag tarraingt go leor airde ar {domain} le dĂ©anaĂ­.", + "follow_suggestions.hints.similar_to_recently_followed": "TĂ¡ an phrĂ³ifĂ­l seo cosĂºil leis na prĂ³ifĂ­lĂ­ a lean tĂº le dĂ©anaĂ­.", "follow_suggestions.personalized_suggestion": "Nod pearsantaithe", "follow_suggestions.popular_suggestion": "Nod coiteann", + "follow_suggestions.popular_suggestion_longer": "TĂ¡ an-tĂ³ir ar {domain}", + "follow_suggestions.similar_to_recently_followed_longer": "CosĂºil le prĂ³ifĂ­lĂ­ a lean tĂº le dĂ©anaĂ­", "follow_suggestions.view_all": "FĂ©ach uile", "follow_suggestions.who_to_follow": "CĂ© le leanĂºint", + "followed_tags": "Hashtags le leanĂºint", "footer.about": "Maidir le", "footer.directory": "Eolaire prĂ³ifĂ­lĂ­", "footer.get_app": "Faigh an aip", @@ -230,6 +329,7 @@ "footer.keyboard_shortcuts": "AicearraĂ­ mĂ©archlĂ¡ir", "footer.privacy_policy": "PolasaĂ­ prĂ­obhĂ¡ideachais", "footer.source_code": "FĂ©ach ar an gcĂ³d foinseach", + "footer.status": "StĂ¡das", "generic.saved": "SĂ¡bhĂ¡ilte", "getting_started.heading": "Ag tosĂº amach", "hashtag.column_header.tag_mode.all": "agus {additional}", @@ -238,15 +338,34 @@ "hashtag.column_settings.select.no_options_message": "MoltaĂ­ ar bith faighte", "hashtag.column_settings.select.placeholder": "IontrĂ¡il haischlibeanna…", "hashtag.column_settings.tag_mode.all": "Iad seo go lĂ©ir", + "hashtag.column_settings.tag_mode.any": "Aon cheann dĂ­obh seo", + "hashtag.column_settings.tag_mode.none": "NĂ­l aon cheann dĂ­obh seo", "hashtag.column_settings.tag_toggle": "Include additional tags in this column", + "hashtag.counter_by_accounts": "{count, plural, one {{counter} rannphĂ¡irtĂ­} two {{counter} rannphĂ¡irtĂ­} few {{counter} rannphĂ¡irtĂ­} many {{counter} rannphĂ¡irtĂ­} other {{counter} rannphĂ¡irtĂ­}}", + "hashtag.counter_by_uses": "{count, plural, one {{counter} post} two {{counter} post} few {{counter} post} many {{counter} post} other {{counter} poist}}", + "hashtag.counter_by_uses_today": "{count, plural, one {{counter} post inniu} other {{counter} poist inniu}} inniu", "hashtag.follow": "Lean haischlib", "hashtag.unfollow": "NĂ¡ lean haischlib", + "hashtags.and_other": "agus {count, plural, one {} two {# nĂ­os} few {# nĂ­os} many {# nĂ­os} other {# nĂ­os}}", "home.column_settings.show_reblogs": "TaispeĂ¡in moltaĂ­", "home.column_settings.show_replies": "TaispeĂ¡n freagraĂ­", "home.hide_announcements": "Cuir fĂ³graĂ­ i bhfolach", + "home.pending_critical_update.body": "Nuashonraigh do fhreastalaĂ­ Mastodon chomh luath agus is fĂ©idir!", + "home.pending_critical_update.link": "FĂ©ach nuashonruithe", + "home.pending_critical_update.title": "NuashonrĂº slĂ¡ndĂ¡la rĂ­thĂ¡bhachtach ar fĂ¡il!", "home.show_announcements": "TaispeĂ¡in fĂ³graĂ­", + "interaction_modal.description.favourite": "Le cuntas ar Mastodon, is fearr leat an postĂ¡il seo chun a chur in iĂºl don Ăºdar go bhfuil meas agat air agus Ă© a shĂ¡bhĂ¡il ar feadh nĂ­os dĂ©anaĂ­.", + "interaction_modal.description.follow": "Le cuntas ar Mastodon, is fĂ©idir leat {name} a leanĂºint chun a gcuid postĂ¡lacha a fhĂ¡il i do fhotha baile.", + "interaction_modal.description.reblog": "Le cuntas ar Mastodon, is fĂ©idir leat an postĂ¡il seo a threisiĂº chun Ă© a roinnt le do leantĂ³irĂ­ fĂ©in.", + "interaction_modal.description.reply": "Le cuntas ar Mastodon, is fĂ©idir leat freagra a thabhairt ar an bpostĂ¡il seo.", + "interaction_modal.login.action": "Thabhairt dom abhaile", + "interaction_modal.login.prompt": "Fearann ​​do fhreastalaĂ­ baile, e.g. mastodon.sĂ³isialta", + "interaction_modal.no_account_yet": "NĂ­ ar Mastodon?", "interaction_modal.on_another_server": "Ar freastalaĂ­ eile", "interaction_modal.on_this_server": "Ar an freastalaĂ­ seo", + "interaction_modal.sign_in": "NĂ­l tĂº logĂ¡ilte isteach ar an bhfreastalaĂ­ seo. CĂ¡ bhfuil do chuntas Ă¡ Ă³stĂ¡il?", + "interaction_modal.sign_in_hint": "Leid: Sin Ă© an suĂ­omh GrĂ©asĂ¡in inar chlĂ¡raigh tĂº. Mura cuimhin leat, lorg an rĂ­omhphost fĂ¡ilte i do bhosca isteach. Is fĂ©idir leat d'ainm ĂºsĂ¡ideora iomlĂ¡n a chur isteach freisin! (m.sh. @Mastodon@mastodon.social)", + "interaction_modal.title.favourite": "An postĂ¡il {name} is fearr leat", "interaction_modal.title.follow": "Lean {name}", "interaction_modal.title.reblog": "Mol postĂ¡il de chuid {name}", "interaction_modal.title.reply": "Freagair postĂ¡il {name}", @@ -258,10 +377,12 @@ "keyboard_shortcuts.boost": "Treisigh postĂ¡il", "keyboard_shortcuts.column": "to focus a status in one of the columns", "keyboard_shortcuts.compose": "to focus the compose textarea", - "keyboard_shortcuts.description": "Cuntas", + "keyboard_shortcuts.description": "Cur sĂ­os", "keyboard_shortcuts.direct": "to open direct messages column", "keyboard_shortcuts.down": "Bog sĂ­os ar an liosta", "keyboard_shortcuts.enter": "Oscail postĂ¡il", + "keyboard_shortcuts.favourite": "PostĂ¡il is fearr leat", + "keyboard_shortcuts.favourites": "Oscail liosta ceanĂ¡in", "keyboard_shortcuts.federated": "Oscail amlĂ­ne cĂ³naidhmithe", "keyboard_shortcuts.heading": "AicearraĂ­ mĂ©archlĂ¡ir", "keyboard_shortcuts.home": "Oscail amlĂ­ne bhaile", @@ -273,28 +394,34 @@ "keyboard_shortcuts.my_profile": "Oscail do phrĂ³ifĂ­l", "keyboard_shortcuts.notifications": "to open notifications column", "keyboard_shortcuts.open_media": "Oscail meĂ¡in", - "keyboard_shortcuts.pinned": "to open pinned posts list", + "keyboard_shortcuts.pinned": "Oscail liosta postĂ¡lacha pinn", "keyboard_shortcuts.profile": "Oscail prĂ³ifĂ­l an t-Ăºdar", "keyboard_shortcuts.reply": "Freagair ar phostĂ¡il", "keyboard_shortcuts.requests": "Oscail liosta iarratas leanĂºnaĂ­", - "keyboard_shortcuts.search": "to focus search", - "keyboard_shortcuts.spoilers": "to show/hide CW field", - "keyboard_shortcuts.start": "to open \"get started\" column", - "keyboard_shortcuts.toggle_hidden": "to show/hide text behind CW", + "keyboard_shortcuts.search": "DĂ­riĂº ar an mbosca cuardaigh", + "keyboard_shortcuts.spoilers": "TaispeĂ¡in / folaigh rĂ©imse CW", + "keyboard_shortcuts.start": "Oscail an colĂºn “tosaighâ€", + "keyboard_shortcuts.toggle_hidden": "TaispeĂ¡in/folaigh an tĂ©acs taobh thiar de CW", "keyboard_shortcuts.toggle_sensitivity": "TaispeĂ¡in / cuir i bhfolach meĂ¡in", "keyboard_shortcuts.toot": "Cuir tĂºs le postĂ¡il nua", - "keyboard_shortcuts.unfocus": "to un-focus compose textarea/search", + "keyboard_shortcuts.unfocus": "Unfocus cum textarea/search", "keyboard_shortcuts.up": "Bog suas ar an liosta", "lightbox.close": "DĂºn", + "lightbox.compress": "ComhbhrĂºigh an bosca amhairc Ă­omhĂ¡", + "lightbox.expand": "Leathnaigh an bosca amhairc Ă­omhĂ¡", "lightbox.next": "An cĂ©ad eile", "lightbox.previous": "Roimhe seo", "limited_account_hint.action": "TaispeĂ¡in an phrĂ³ifĂ­l ar aon nĂ³s", "limited_account_hint.title": "TĂ¡ an phrĂ³ifĂ­l seo curtha i bhfolach ag na modhnĂ³ra {domain}.", + "link_preview.author": "Le {name}", + "link_preview.more_from_author": "Tuilleadh Ă³ {name}", + "link_preview.shares": "{count, plural, one {{counter} post} other {{counter} poist}}", "lists.account.add": "Cuir leis an liosta", "lists.account.remove": "Scrios as an liosta", "lists.delete": "Scrios liosta", "lists.edit": "Cuir an liosta in eagar", "lists.edit.submit": "Athraigh teideal", + "lists.exclusive": "Folaigh na poist seo Ă³n mbaile", "lists.new.create": "Cruthaigh liosta", "lists.new.title_placeholder": "Teideal liosta nua", "lists.replies_policy.followed": "ĂsĂ¡ideoir ar bith atĂ¡ Ă¡ leanĂºint", @@ -303,20 +430,38 @@ "lists.replies_policy.title": "TaispeĂ¡in freagraĂ­:", "lists.search": "Cuardaigh i measc daoine atĂ¡ Ă¡ leanĂºint agat", "lists.subheading": "Do liostaĂ­", + "load_pending": "{count, plural, one {# mĂ­r nua} two {# mĂ­r nua} few {# mĂ­r nua} many {# mĂ­r nua} other {# mĂ­r nua}}", + "loading_indicator.label": "Ă lĂ³dĂ¡il…", + "media_gallery.toggle_visible": "{number, plural, one {Folaigh Ă­omhĂ¡} two {Folaigh Ă­omhĂ¡nna} few {Folaigh Ă­omhĂ¡nna} many {Folaigh Ă­omhĂ¡nna} other {Folaigh Ă­omhĂ¡nna}}", + "moved_to_account_banner.text": "TĂ¡ do chuntas {disabledAccount} dĂ­chumasaithe faoi lĂ¡thair toisc gur bhog tĂº go {movedToAccount}.", + "mute_modal.hide_from_notifications": "Folaigh Ă³ fhĂ³graĂ­", + "mute_modal.hide_options": "Folaigh roghanna", + "mute_modal.indefinite": "Go dtĂ­ go ndĂ­bhalfaidh mĂ© iad", + "mute_modal.show_options": "TaispeĂ¡in roghanna", + "mute_modal.they_can_mention_and_follow": "Is fĂ©idir leo tĂº a lua agus a leanĂºint, ach nĂ­ fheicfidh tĂº iad.", + "mute_modal.they_wont_know": "NĂ­ bheidh a fhios acu go bhfuil balbhĂº orthu.", + "mute_modal.title": "An bhfuil fonn ort ĂºsĂ¡ideoir a bhalbhĂº?", + "mute_modal.you_wont_see_mentions": "NĂ­ fheicfidh tĂº postĂ¡lacha a luann iad.", + "mute_modal.you_wont_see_posts": "Is fĂ©idir leo do phoist a fheiceĂ¡il go fĂ³ill, ach nĂ­ fheicfidh tĂº a gcuid postanna.", "navigation_bar.about": "Maidir le", + "navigation_bar.advanced_interface": "Oscail i gcomhĂ©adan grĂ©asĂ¡in chun cinn", "navigation_bar.blocks": "Cuntais bhactha", "navigation_bar.bookmarks": "Leabharmharcanna", "navigation_bar.community_timeline": "AmlĂ­ne Ă¡itiĂºil", "navigation_bar.compose": "Cum postĂ¡il nua", + "navigation_bar.direct": "Luann prĂ­obhĂ¡ideach", "navigation_bar.discover": "Faigh amach", "navigation_bar.domain_blocks": "Fearainn bhactha", "navigation_bar.explore": "FĂ©ach thart", + "navigation_bar.favourites": "CeanĂ¡in", "navigation_bar.filters": "Focail bhalbhaithe", "navigation_bar.follow_requests": "Iarratais leanĂºnaĂ­", + "navigation_bar.followed_tags": "Haischlibeanna ina dhiaidh", "navigation_bar.follows_and_followers": "Ag leanĂºint agus do do leanĂºint", "navigation_bar.lists": "LiostaĂ­", "navigation_bar.logout": "LogĂ¡il Amach", "navigation_bar.mutes": "ĂsĂ¡ideoirĂ­ balbhaithe", + "navigation_bar.opened_in_classic_interface": "OsclaĂ­tear poist, cuntais agus leathanaigh shonracha eile de rĂ©ir rĂ©amhshocraithe sa chomhĂ©adan grĂ©asĂ¡in clasaiceach.", "navigation_bar.personal": "Pearsanta", "navigation_bar.pins": "PostĂ¡lacha pionnĂ¡ilte", "navigation_bar.preferences": "Sainroghanna pearsanta", @@ -326,17 +471,41 @@ "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", "notification.admin.report": "Tuairiscigh {name} {target}", "notification.admin.sign_up": "ChlĂ¡raigh {name}", + "notification.favourite": "Is fearr le {name} do phostĂ¡il", "notification.follow": "Lean {name} thĂº", "notification.follow_request": "D'iarr {name} ort do chuntas a leanĂºint", "notification.mention": "Luaigh {name} tĂº", + "notification.moderation-warning.learn_more": "Foghlaim nĂ­os mĂ³", + "notification.moderation_warning": "TĂ¡ rabhadh modhnĂ³ireachta faighte agat", + "notification.moderation_warning.action_delete_statuses": "Baineadh cuid de do phostĂ¡lacha.", + "notification.moderation_warning.action_disable": "DĂ­chumasaĂ­odh do chuntas.", + "notification.moderation_warning.action_mark_statuses_as_sensitive": "TĂ¡ cuid de do phostĂ¡lacha marcĂ¡ilte mar Ă­ogair.", + "notification.moderation_warning.action_none": "TĂ¡ rabhadh modhnĂ³ireachta faighte ag do chuntas.", + "notification.moderation_warning.action_sensitive": "DĂ©anfar do phostĂ¡lacha a mharcĂ¡il mar Ă­ogair as seo amach.", + "notification.moderation_warning.action_silence": "TĂ¡ do chuntas teoranta.", + "notification.moderation_warning.action_suspend": "Cuireadh do chuntas ar fionraĂ­.", "notification.own_poll": "TĂ¡ do suirbhĂ© crĂ­ochnaithe", "notification.poll": "TĂ¡ suirbhĂ© inar vĂ³tĂ¡il tĂº tar Ă©is crĂ­ochnĂº", "notification.reblog": "Mhol {name} do phostĂ¡il", + "notification.relationships_severance_event": "Cailleadh naisc le {name}", + "notification.relationships_severance_event.account_suspension": "Chuir riarthĂ³ir Ă³ {from} {target} ar fionraĂ­, rud a chiallaĂ­onn nach fĂ©idir leat nuashonruithe a fhĂ¡il uathu a thuilleadh nĂ¡ idirghnĂ­omhĂº leo.", + "notification.relationships_severance_event.domain_block": "Chuir riarthĂ³ir Ă³ {from} bac ar {target}, lena n-Ă¡irĂ­tear {followersCount} de do leantĂ³irĂ­ agus {followingCount, plural, one {#cuntas} other {#cuntas}} leanann tĂº.", + "notification.relationships_severance_event.learn_more": "Foghlaim nĂ­os mĂ³", + "notification.relationships_severance_event.user_domain_block": "Chuir tĂº bac ar {target}, bhain tĂº {followersCount} de do leantĂ³irĂ­ agus {followingCount, plural, one {# cuntas} other {# cuntais}} a leanann tĂº.", "notification.status": "PhostĂ¡il {name} dĂ­reach", "notification.update": "Chuir {name} postĂ¡il in eagar", + "notification_requests.accept": "Glac", + "notification_requests.dismiss": "DĂ­bhe", + "notification_requests.notifications_from": "FĂ³graĂ­ Ă³ {name}", + "notification_requests.title": "FĂ³graĂ­ scagtha", "notifications.clear": "Glan fĂ³graĂ­", + "notifications.clear_confirmation": "An bhfuil tĂº cinnte gur mhaith leat d'fhĂ³graĂ­ go lĂ©ir a ghlanadh go buan?", "notifications.column_settings.admin.report": "TuairiscĂ­ nua:", + "notifications.column_settings.admin.sign_up": "ClĂ¡rĂºchĂ¡in nua:", "notifications.column_settings.alert": "FĂ³graĂ­ deisce", + "notifications.column_settings.favourite": "CeanĂ¡in:", + "notifications.column_settings.filter_bar.advanced": "TaispeĂ¡in gach catagĂ³ir", + "notifications.column_settings.filter_bar.category": "Barra scagairĂ­ tapa", "notifications.column_settings.follow": "LeantĂ³irĂ­ nua:", "notifications.column_settings.follow_request": "Iarratais leanĂºnaĂ­ nua:", "notifications.column_settings.mention": "TrĂ¡chtanna:", @@ -347,33 +516,77 @@ "notifications.column_settings.sound": "Seinn an fhuaim", "notifications.column_settings.status": "PostĂ¡lacha nua:", "notifications.column_settings.unread_notifications.category": "BrĂºfhĂ³graĂ­ neamhlĂ©ite", + "notifications.column_settings.unread_notifications.highlight": "Aibhsigh fĂ³graĂ­ neamhlĂ©ite", "notifications.column_settings.update": "Eagair:", "notifications.filter.all": "Uile", "notifications.filter.boosts": "Treisithe", + "notifications.filter.favourites": "CeanĂ¡in", "notifications.filter.follows": "Ag leanĂºint", "notifications.filter.mentions": "TrĂ¡chtanna", "notifications.filter.polls": "TorthaĂ­ suirbhĂ©anna", "notifications.filter.statuses": "Nuashonruithe Ă³ dhaoine a leanann tĂº", "notifications.grant_permission": "Tabhair cead.", "notifications.group": "{count} fĂ³graĂ­", + "notifications.mark_as_read": "MarcĂ¡il gach fĂ³gra mar atĂ¡ lĂ©ite", + "notifications.permission_denied": "NĂ­l fĂ³graĂ­ deisce ar fĂ¡il mar gheall ar iarratas ar chead brabhsĂ¡laĂ­ a diĂºltaĂ­odh roimhe seo", + "notifications.permission_denied_alert": "NĂ­ fĂ©idir fĂ³graĂ­ deisce a chumasĂº, mar gur diĂºltaĂ­odh cead brabhsĂ¡laĂ­ roimhe seo", + "notifications.permission_required": "NĂ­l fĂ³graĂ­ deisce ar fĂ¡il toisc nĂ¡r tugadh an cead riachtanach.", + "notifications.policy.filter_new_accounts.hint": "Cruthaithe laistigh den {days, plural, one {lae amhĂ¡in} two {# lĂ¡} few {# lĂ¡} many {# lĂ¡} other {# lĂ¡}}", + "notifications.policy.filter_new_accounts_title": "Cuntais nua", + "notifications.policy.filter_not_followers_hint": "Agus daoine a bhfuil siad ag leanĂºint ort le nĂ­os lĂº nĂ¡ {days, plural, one {lae amhĂ¡in} two {# lĂ¡} few {# lĂ¡} many {# lĂ¡} other {# lĂ¡}}", + "notifications.policy.filter_not_followers_title": "Daoine nach leanann tĂº", + "notifications.policy.filter_not_following_hint": "Go dtĂ­ go gceadaĂ­onn tĂº iad de lĂ¡imh", + "notifications.policy.filter_not_following_title": "Daoine nach leanann tĂº", + "notifications.policy.filter_private_mentions_hint": "Scagtha mura bhfuil sĂ© mar fhreagra ar do lua fĂ©in nĂ³ mĂ¡ leanann tĂº an seoltĂ³ir", + "notifications.policy.filter_private_mentions_title": "TagairtĂ­ prĂ­obhĂ¡ideacha gan iarraidh", + "notifications.policy.title": "Scag fĂ³graĂ­ Ă³â€¦", "notifications_permission_banner.enable": "Ceadaigh fĂ³graĂ­ ar an deasc", + "notifications_permission_banner.how_to_control": "Chun fĂ³graĂ­ a fhĂ¡il nuair nach bhfuil Mastodon oscailte, cumasaigh fĂ³graĂ­ deisce. Is fĂ©idir leat a rialĂº go beacht cĂ© na cineĂ¡lacha idirghnĂ­omhaĂ­ochtaĂ­ a ghineann fĂ³graĂ­ deisce trĂ­d an gcnaipe {icon} thuas nuair a bhĂ­onn siad cumasaithe.", "notifications_permission_banner.title": "NĂ¡ caill aon rud go deo", - "onboarding.actions.go_to_explore": "See what's trending", - "onboarding.actions.go_to_home": "Go to your home feed", - "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", - "onboarding.follows.title": "Popular on Mastodon", - "onboarding.start.lead": "Your new Mastodon account is ready to go. Here's how you can make the most of it:", - "onboarding.start.skip": "Want to skip right ahead?", - "onboarding.steps.follow_people.body": "You curate your own feed. Lets fill it with interesting people.", - "onboarding.steps.follow_people.title": "Follow {count, plural, one {one person} other {# people}}", - "onboarding.steps.publish_status.body": "Say hello to the world.", - "onboarding.steps.setup_profile.body": "Others are more likely to interact with you with a filled out profile.", - "onboarding.steps.setup_profile.title": "Customize your profile", - "onboarding.steps.share_profile.body": "Let your friends know how to find you on Mastodon!", - "onboarding.steps.share_profile.title": "Share your profile", + "onboarding.action.back": "TĂ³g ar ais mĂ©", + "onboarding.actions.back": "TĂ³g ar ais mĂ©", + "onboarding.actions.go_to_explore": "TĂ³g mĂ© chun trending", + "onboarding.actions.go_to_home": "TĂ³g go dtĂ­ mo bheathĂº baile mĂ©", + "onboarding.compose.template": "Dia duit #Mastodon!", + "onboarding.follows.empty": "Ar an drochuair, nĂ­ fĂ©idir aon torthaĂ­ a thaispeĂ¡int faoi lĂ¡thair. Is fĂ©idir leat triail a bhaint as cuardach nĂ³ brabhsĂ¡il ar an leathanach taiscĂ©alaĂ­ochta chun teacht ar dhaoine le leanĂºint, nĂ³ bain triail eile as nĂ­os dĂ©anaĂ­.", + "onboarding.follows.lead": "Is Ă© do bheathĂº baile an prĂ­omhbhealach chun taithĂ­ a fhĂ¡il ar Mastodon. DĂ¡ mhĂ©ad daoine a leanann tĂº, is ea is gnĂ­omhaĂ­ agus is suimiĂºla a bheidh sĂ©. Chun tĂº a chur ar bun, seo roinnt moltaĂ­:", + "onboarding.follows.title": "Cuir do chuid fotha baile in oiriĂºint duit fĂ©in", + "onboarding.profile.discoverable": "DĂ©an mo phrĂ³ifĂ­l a fhĂ¡il amach", + "onboarding.profile.discoverable_hint": "Nuair a roghnaĂ­onn tĂº infhionnachtana ar Mastodon, d’fhĂ©adfadh do phoist a bheith le feiceĂ¡il i dtorthaĂ­ cuardaigh agus treochtaĂ­, agus d’fhĂ©adfaĂ­ do phrĂ³ifĂ­l a mholadh do dhaoine a bhfuil na leasanna cĂ©anna acu leat.", + "onboarding.profile.display_name": "Ainm taispeĂ¡na", + "onboarding.profile.display_name_hint": "D’ainm iomlĂ¡n nĂ³ d’ainm spraĂ­Ăºil…", + "onboarding.profile.lead": "Is fĂ©idir leat Ă© seo a chomhlĂ¡nĂº i gcĂ³naĂ­ nĂ­os dĂ©anaĂ­ sna socruithe, Ă¡it a bhfuil nĂ­os mĂ³ roghanna saincheaptha ar fĂ¡il.", + "onboarding.profile.note": "Bith", + "onboarding.profile.note_hint": "Is fĂ©idir leat @ daoine eile a lua nĂ³ #hashtags…", + "onboarding.profile.save_and_continue": "SĂ¡bhĂ¡il agus lean ar aghaidh", + "onboarding.profile.title": "SocrĂº prĂ³ifĂ­le", + "onboarding.profile.upload_avatar": "Ăosluchtaigh pictiĂºr prĂ³ifĂ­l", + "onboarding.profile.upload_header": "ĂoslĂ³dĂ¡il an ceanntĂ¡sca prĂ³ifĂ­l", + "onboarding.share.lead": "Cuir in iĂºl do dhaoine conas is fĂ©idir leo tĂº a aimsiĂº ar Mastodon!", + "onboarding.share.message": "Is {username} mĂ© ar #Mastodon! Tar lean mĂ© ag {url}", + "onboarding.share.next_steps": "Na chĂ©ad chĂ©imeanna eile is fĂ©idir:", + "onboarding.share.title": "Roinn do phrĂ³ifĂ­l", + "onboarding.start.lead": "TĂ¡ tĂº mar chuid de Mastodon anois, ardĂ¡n meĂ¡n sĂ³isialta dĂ­lĂ¡raithe uathĂºil ina ndĂ©anann tĂº - nĂ­ algartam - do thaithĂ­ fĂ©in a choimeĂ¡d. Cuirimis tĂºs leat ar an teorainn shĂ³isialta nua seo:", + "onboarding.start.skip": "Nach bhfuil cabhair uait le tosĂº?", + "onboarding.start.title": "TĂ¡ sĂ© dĂ©anta agat!", + "onboarding.steps.follow_people.body": "Is Ă©ard atĂ¡ i gceist le daoine suimiĂºla a leanĂºint nĂ¡ Mastodon.", + "onboarding.steps.follow_people.title": "Cuir do chuid fotha baile in oiriĂºint duit fĂ©in", + "onboarding.steps.publish_status.body": "Abair heileo leis an domhan le tĂ©acs, grianghraif, fĂ­seĂ¡in nĂ³ pobalbhreith {emoji}", + "onboarding.steps.publish_status.title": "DĂ©an do chĂ©ad phostĂ¡il", + "onboarding.steps.setup_profile.body": "Cuir le d'idirghnĂ­omhaĂ­ochtaĂ­ trĂ­ phrĂ³ifĂ­l chuimsitheach a bheith agat.", + "onboarding.steps.setup_profile.title": "DĂ©an do phrĂ³ifĂ­l a phearsantĂº", + "onboarding.steps.share_profile.body": "Cuir in iĂºl do do chairde conas tĂº a aimsiĂº ar Mastodon", + "onboarding.steps.share_profile.title": "Roinn do phrĂ³ifĂ­l Mastodon", + "onboarding.tips.2fa": "An raibh a fhios agat? Is fĂ©idir leat do chuntas a dhĂ©anamh slĂ¡n trĂ­ fhĂ­ordheimhniĂº dhĂ¡ fhachtĂ³ir a shocrĂº i socruithe do chuntais. OibrĂ­onn sĂ© le haon aip TOTP de do rogha fĂ©in, nĂ­l aon uimhir theileafĂ³in riachtanach!", + "onboarding.tips.accounts_from_other_servers": "An raibh a fhios agat? Ă“s rud Ă© go bhfuil Mastodon dĂ­lĂ¡raithe, dĂ©anfar roinnt prĂ³ifĂ­lĂ­ a dtagann tĂº trasna orthu a Ă³stĂ¡il ar fhreastalaithe seachas do fhreastalaithe. Agus fĂ³s is fĂ©idir leat idirghnĂ­omhĂº leo gan uaim! TĂ¡ an freastalaĂ­ acu sa dara leath dĂ¡ n-ainm ĂºsĂ¡ideora!", + "onboarding.tips.migration": "An raibh a fhios agat? MĂ¡s dĂ³igh leat nach rogha freastalaĂ­ iontach Ă© {domain} amach anseo, is fĂ©idir leat bogadh go freastalaĂ­ Mastodon eile gan do leantĂ³irĂ­ a chailliĂºint. Is fĂ©idir leat do fhreastalaĂ­ fĂ©in a Ă³stĂ¡il fiĂº!", + "onboarding.tips.verification": "An raibh a fhios agat? Is fĂ©idir leat do chuntas a fhĂ­orĂº trĂ­ nasc a chur le do phrĂ³ifĂ­l Mastodon ar do shuĂ­omh GrĂ©asĂ¡in fĂ©in agus an suĂ­omh GrĂ©asĂ¡in a chur le do phrĂ³ifĂ­l. NĂ­l aon tĂ¡illĂ­ nĂ³ doicimĂ©id riachtanach!", + "password_confirmation.exceeds_maxlength": "SĂ¡raĂ­onn dearbhĂº pasfhocail uasfhad an phasfhocail", + "password_confirmation.mismatching": "NĂ­ hionann dearbhĂº pasfhocail", "picture_in_picture.restore": "Cuir Ă© ar ais", "poll.closed": "DĂºnta", "poll.refresh": "Athnuaigh", + "poll.reveal": "FĂ©ach torthaĂ­", "poll.total_people": "{count, plural, one {# duine} other {# duine}}", "poll.total_votes": "{count, plural, one {# vĂ³ta} other {# vĂ³ta}}", "poll.vote": "VĂ³tĂ¡il", @@ -381,11 +594,22 @@ "poll.votes": "{votes, plural, one {# vĂ³ta} other {# vĂ³ta}}", "poll_button.add_poll": "Cruthaigh suirbhĂ©", "poll_button.remove_poll": "Bain suirbhĂ©", - "privacy.change": "Adjust status privacy", + "privacy.change": "Athraigh prĂ­obhĂ¡ideacht postĂ¡la", + "privacy.direct.long": "Luaigh gach duine sa phost", + "privacy.direct.short": "Daoine ar leith", + "privacy.private.long": "Do leanĂºna amhĂ¡in", + "privacy.private.short": "LeantĂ³irĂ­", + "privacy.public.long": "Duine ar bith ar agus amach Mastodon", "privacy.public.short": "PoiblĂ­", + "privacy.unlisted.additional": "IompraĂ­onn sĂ© seo dĂ­reach mar a bheadh ​​poiblĂ­, ach amhĂ¡in nĂ­ bheidh an postĂ¡il le feiceĂ¡il i bhfothaĂ­ beo nĂ³ i hashtags, in iniĂºchadh nĂ³ i gcuardach Mastodon, fiĂº mĂ¡ tĂ¡ tĂº liostĂ¡ilte ar fud an chuntais.", + "privacy.unlisted.long": "NĂ­os lĂº fanfarraĂ­ algarthacha", + "privacy.unlisted.short": "PoiblĂ­ ciĂºin", + "privacy_policy.last_updated": "Nuashonraithe {date}", "privacy_policy.title": "PolasaĂ­ prĂ­obhĂ¡ideachais", + "recommended": "Molta", "refresh": "Athnuaigh", "regeneration_indicator.label": "Ag lĂ³dĂ¡il…", + "regeneration_indicator.sublabel": "TĂ¡ do bheathĂº baile Ă¡ ullmhĂº!", "relative_time.days": "{number}l", "relative_time.full.days": "{number, plural, one {# lĂ¡} other {# lĂ¡}} Ă³ shin", "relative_time.full.hours": "{number, plural, one {# uair} other {# uair}} Ă³ shin", @@ -397,77 +621,131 @@ "relative_time.minutes": "{number}n", "relative_time.seconds": "{number}s", "relative_time.today": "inniu", + "reply_indicator.attachments": "{count, plural, one {# alĂ¡n} two {# alĂ¡in} few {# alĂ¡in} many {# alĂ¡in} other {# alĂ¡in}}", "reply_indicator.cancel": "Cealaigh", + "reply_indicator.poll": "VĂ³taĂ­ocht", "report.block": "Bac", "report.block_explanation": "NĂ­ fheicfidh tĂº a c(h)Ăºid postĂ¡lacha. NĂ­ bheidh sĂ©/sĂ­ in ann do chuid postĂ¡lacha a fheiceĂ¡il nĂ¡ tĂº fĂ©in a leanĂºint. Beidh sĂ©/sĂ­ in ann a dhĂ©anamh amach go bhfuil sĂ©/sĂ­ bactha.", + "report.categories.legal": "DlĂ­thiĂºil", "report.categories.other": "Eile", "report.categories.spam": "Turscar", "report.categories.violation": "SĂ¡raĂ­onn Ă¡bhar riail freastalaĂ­ amhĂ¡in nĂ³ nĂ­os mĂ³", "report.category.subtitle": "Roghnaigh an toradh is fearr", + "report.category.title": "Inis dĂºinn cad atĂ¡ ar siĂºl leis an {type} seo", "report.category.title_account": "prĂ³ifĂ­l", "report.category.title_status": "postĂ¡il", "report.close": "DĂ©anta", + "report.comment.title": "An bhfuil aon rud eile ba chĂ³ir dĂºinn a fhios agat, dar leat?", "report.forward": "Seol ar aghaidh chun {target}", + "report.forward_hint": "Is Ă³ fhreastalaĂ­ eile an cuntas. Cuir cĂ³ip gan ainm den tuarascĂ¡il ansin freisin?", "report.mute": "Balbhaigh", "report.mute_explanation": "NĂ­ fheicfidh tĂº a postĂ¡lacha. Is fĂ©idir an tĂ© seo tĂº a leanĂºint agus do phostĂ¡lacha a fheiceĂ¡il, agus nĂ­ fhios go bhfuil iad balbhaithe.", "report.next": "An cĂ©ad eile", "report.placeholder": "RĂ¡itis bhreise", "report.reasons.dislike": "NĂ­ maith liom Ă©", + "report.reasons.dislike_description": "NĂ­ rud Ă© ba mhaith leat a fheiceĂ¡il", + "report.reasons.legal": "TĂ¡ sĂ© mĂ­dhleathach", + "report.reasons.legal_description": "Creideann tĂº go sĂ¡raĂ­onn sĂ© dlĂ­ do thĂ­re nĂ³ do thĂ­r an fhreastalaĂ­", "report.reasons.other": "Is rud eile Ă©", + "report.reasons.other_description": "NĂ­ luĂ­onn an cheist le catagĂ³irĂ­ eile", "report.reasons.spam": "Is turscar Ă©", + "report.reasons.spam_description": "Naisc mhailĂ­seacha, rannphĂ¡irtĂ­ocht bhrĂ©ige, nĂ³ freagraĂ­ athchleachtach", "report.reasons.violation": "SĂ¡raĂ­onn sĂ© rialacha an fhreastalaĂ­", "report.reasons.violation_description": "TĂ¡ a fhios agat go sĂ¡raĂ­onn sĂ© rialacha ar leith", "report.rules.subtitle": "Roghnaigh gach atĂ¡ i bhfeidhm", "report.rules.title": "CĂ©n rialacha atĂ¡ Ă¡ sĂ¡rĂº?", "report.statuses.subtitle": "Roghnaigh gach atĂ¡ i bhfeidhm", + "report.statuses.title": "An bhfuil aon phoist a thacaĂ­onn leis an tuarascĂ¡il seo?", "report.submit": "Cuir isteach", "report.target": "Ag tuairisciĂº {target}", + "report.thanks.take_action": "Seo do roghanna chun an mĂ©id a fheiceann tĂº ar Mastodon a rialĂº:", + "report.thanks.take_action_actionable": "Agus Ă© seo Ă¡ athbhreithniĂº againn, is fĂ©idir leat caingean a dhĂ©anamh in aghaidh @{name}:", + "report.thanks.title": "NĂ¡ bĂ­ ag iarraidh Ă© seo a fheiceĂ¡il?", + "report.thanks.title_actionable": "Go raibh maith agat as tuairisc a thabhairt, scrĂºdĂ³imid Ă© seo.", "report.unfollow": "NĂ¡ lean @{name}", + "report.unfollow_explanation": "TĂ¡ tĂº ag leanĂºint an chuntais seo. Chun nach bhfeicfidh tĂº a bpoist i do fhotha baile a thuilleadh, dĂ­lean ​​iad.", "report_notification.attached_statuses": "{count, plural, one {# post} other {# posts}} attached", + "report_notification.categories.legal": "DlĂ­thiĂºil", "report_notification.categories.other": "Eile", "report_notification.categories.spam": "Turscar", "report_notification.categories.violation": "SĂ¡rĂº rialach", "report_notification.open": "Oscail tuairisc", + "search.no_recent_searches": "NĂ­l aon chuardach le dĂ©anaĂ­", "search.placeholder": "Cuardaigh", + "search.quick_action.account_search": "PrĂ³ifĂ­lĂ­ a mheaitseĂ¡lann {x}", + "search.quick_action.go_to_account": "TĂ©igh go prĂ³ifĂ­l {x}", + "search.quick_action.go_to_hashtag": "TĂ©igh chuig hashtag {x}", + "search.quick_action.open_url": "Oscail URL i Mastodon", + "search.quick_action.status_search": "PostĂ¡lacha a mheaitseĂ¡lann {x}", "search.search_or_paste": "Cuardaigh nĂ³ cuir URL isteach", - "search_results.all": "Uile", - "search_results.hashtags": "Haischlibeanna", + "search_popout.full_text_search_disabled_message": "NĂ­l sĂ© ar fĂ¡il ar {domain}.", + "search_popout.full_text_search_logged_out_message": "Ar fĂ¡il ach amhĂ¡in nuair atĂ¡ tĂº logĂ¡ilte isteach.", + "search_popout.language_code": "CĂ³d teanga ISO", + "search_popout.options": "Roghanna cuardaigh", + "search_popout.quick_actions": "GnĂ­omhartha tapa", + "search_popout.recent": "Cuardach le dĂ©anaĂ­", + "search_popout.specific_date": "dĂ¡ta ar leith", + "search_popout.user": "ĂºsĂ¡ideoir", + "search_results.accounts": "PrĂ³ifĂ­lĂ­", + "search_results.all": "Gach", + "search_results.hashtags": "Haischlib", + "search_results.nothing_found": "NĂ­orbh fhĂ©idir aon rud a aimsiĂº do na tĂ©armaĂ­ cuardaigh seo", + "search_results.see_all": "Gach rud a fheicĂ¡il", "search_results.statuses": "PostĂ¡lacha", "search_results.title": "Cuardaigh ar thĂ³ir {q}", + "server_banner.about_active_users": "Daoine a ĂºsĂ¡ideann an freastalaĂ­ seo le 30 lĂ¡ anuas (ĂsĂ¡ideoirĂ­ GnĂ­omhacha MĂ­osĂºla)", "server_banner.active_users": "ĂºsĂ¡ideoirĂ­ gnĂ­omhacha", + "server_banner.administered_by": "Arna riar ag:", + "server_banner.is_one_of_many": "TĂ¡ {domain} ar cheann de na freastalaithe Mastodon neamhspleĂ¡cha go leor is fĂ©idir leat a ĂºsĂ¡id chun pĂ¡irt a ghlacadh sa feiliĂºnach.", "server_banner.server_stats": "StaitisticĂ­ freastalaĂ­:", "sign_in_banner.create_account": "Cruthaigh cuntas", + "sign_in_banner.follow_anyone": "Lean aon duine ar fud an fhealsĂºnachta agus fĂ©ach ar fad in ord croineolaĂ­och. Gan algartam, fĂ³graĂ­, nĂ³ clickbait i radharc.", + "sign_in_banner.mastodon_is": "Is Ă© Mastodon an bealach is fearr le coinneĂ¡il suas lena bhfuil ag tarlĂº.", "sign_in_banner.sign_in": "Sinigh isteach", - "status.admin_status": "Open this status in the moderation interface", + "sign_in_banner.sso_redirect": "LogĂ¡il isteach nĂ³ ClĂ¡raigh", + "status.admin_account": "Oscail comhĂ©adan modhnĂ³ireachta do @{name}", + "status.admin_domain": "Oscail comhĂ©adan modhnĂ³ireachta le haghaidh {domain}", + "status.admin_status": "Oscail an postĂ¡il seo sa chomhĂ©adan modhnĂ³ireachta", "status.block": "Bac @{name}", "status.bookmark": "Leabharmharcanna", "status.cancel_reblog_private": "DĂ­mhol", "status.cannot_reblog": "NĂ­ fĂ©idir an phostĂ¡il seo a mholadh", - "status.copy": "Copy link to status", + "status.copy": "CĂ³ipeĂ¡il an nasc chuig an bpostĂ¡il", "status.delete": "Scrios", + "status.detailed_status": "Amharc comhrĂ¡ mionsonraithe", + "status.direct": "Luaigh @{name} go prĂ­obhĂ¡ideach", + "status.direct_indicator": "Lua prĂ­obhĂ¡ideach", "status.edit": "Cuir in eagar", + "status.edited": "Arna chuir in eagar anuas {date}", "status.edited_x_times": "Curtha in eagar {count, plural, one {{count} uair amhĂ¡in} two {{count} uair} few {{count} uair} many {{count} uair} other {{count} uair}}", "status.embed": "Leabaigh", + "status.favourite": "Is fearr leat", + "status.favourites": "{count, plural, one {a bhfuil grĂ¡ agat do} two {grĂ¡ite} few {grĂ¡ite} many {grĂ¡ite} other {grĂ¡ite}}", "status.filter": "DĂ©an scagadh ar an bpostĂ¡il seo", "status.filtered": "Scagtha", "status.hide": "Cuir postĂ¡il i bhfolach", "status.history.created": "Chruthaigh {name} {date}", "status.history.edited": "Curtha in eagar ag {name} in {date}", "status.load_more": "LĂ³dĂ¡il a thuilleadh", + "status.media.open": "CliceĂ¡il chun oscailt", + "status.media.show": "CliceĂ¡il chun a thaispeĂ¡int", "status.media_hidden": "Cuirtear meĂ¡in i bhfolach", "status.mention": "Luaigh @{name}", "status.more": "Tuilleadh", "status.mute": "Balbhaigh @{name}", "status.mute_conversation": "Balbhaigh comhrĂ¡", - "status.open": "Expand this status", + "status.open": "Leathnaigh an post seo", "status.pin": "PionnĂ¡il ar do phrĂ³ifĂ­l", "status.pinned": "PostĂ¡il pionnĂ¡ilte", "status.read_more": "LĂ©an a thuilleadh", - "status.reblog": "Mol", + "status.reblog": "TreisiĂº", "status.reblog_private": "Mol le lĂ©argas bunĂºsach", "status.reblogged_by": "Mhol {name}", + "status.reblogs": "{count, plural, one {buaic} other {buaic}}", "status.reblogs.empty": "NĂ­or mhol Ă©inne an phostĂ¡il seo fĂ³s. Nuair a mholfaidh duine Ă©igin Ă­, taispeĂ¡nfar anseo Ă© sin.", "status.redraft": "Scrios â athdhrĂ©achtaigh", + "status.remove_bookmark": "Bain leabharmharc", + "status.replied_to": "D'fhreagair {name}", "status.reply": "Freagair", "status.replyAll": "Freagair le snĂ¡ithe", "status.report": "Tuairiscigh @{name}", @@ -479,41 +757,57 @@ "status.show_more": "TaispeĂ¡in nĂ­os mĂ³", "status.show_more_all": "TaispeĂ¡in nĂ­os mĂ³ d'uile", "status.show_original": "TaispeĂ¡in bunchĂ³ip", - "status.title.with_attachments": "{user} posted {attachmentCount, plural, one {an attachment} other {# attachments}}", + "status.title.with_attachments": "{user} a sheol {attachmentCount, plural, one {ceangal} two {{attachmentCount} ceangal} few {{attachmentCount} ceangail} many {{attachmentCount} ceangal} other {{attachmentCount} ceangal}}", "status.translate": "Aistrigh", "status.translated_from_with": "D'Aistrigh Ă³n {lang} ag ĂºsĂ¡id {provider}", + "status.uncached_media_warning": "NĂ­l an rĂ©amhamharc ar fĂ¡il", "status.unmute_conversation": "DĂ­bhalbhaigh comhrĂ¡", "status.unpin": "DĂ­phionnĂ¡il de do phrĂ³ifĂ­l", + "subscribed_languages.lead": "NĂ­ bheidh ach postĂ¡lacha i dteangacha roghnaithe le feiceĂ¡il ar do bhaile agus liostaĂ­ amlĂ­nte tar Ă©is an athraithe. Roghnaigh ceann ar bith chun postĂ¡lacha a fhĂ¡il i ngach teanga.", "subscribed_languages.save": "SĂ¡bhĂ¡il athruithe", + "subscribed_languages.target": "Athraigh teangacha suibscrĂ­ofa le haghaidh {target}", "tabs_bar.home": "Baile", "tabs_bar.notifications": "FĂ³graĂ­", "time_remaining.days": "{number, plural, one {# lĂ¡} other {# lĂ¡}} fĂ¡gtha", "time_remaining.hours": "{number, plural, one {# uair} other {# uair}} fĂ¡gtha", "time_remaining.minutes": "{number, plural, one {# nĂ³imĂ©ad} other {# nĂ³imĂ©ad}} fĂ¡gtha", + "time_remaining.moments": "ChuimhneachĂ¡in fĂ¡gtha", "time_remaining.seconds": "{number, plural, one {# soicind} other {# soicind}} fĂ¡gtha", + "timeline_hint.remote_resource_not_displayed": "NĂ­l {resource} Ă³ fhreastalaithe eile ar taispeĂ¡int.", "timeline_hint.resources.followers": "LeantĂ³irĂ­", "timeline_hint.resources.follows": "Cuntais leanta", "timeline_hint.resources.statuses": "PostĂ¡ilĂ­ nĂ­os sine", "trends.counter_by_accounts": "{count, plural, one {{counter} duine} other {{counter} duine}} le {days, plural, one {lĂ¡} other {{days} lĂ¡}} anuas", "trends.trending_now": "Ag treochtĂ¡il anois", + "ui.beforeunload": "Caillfear do dhrĂ©acht mĂ¡ fhĂ¡gann tĂº Mastodon.", "units.short.billion": "{count}B", "units.short.million": "{count}M", "units.short.thousand": "{count}k", "upload_area.title": "Tarraing â scaoil chun uaslĂ³dĂ¡il", + "upload_button.label": "Cuir Ă­omhĂ¡nna, fĂ­seĂ¡n nĂ³ comhad fuaime leis", + "upload_error.limit": "SĂ¡raĂ­odh an teorainn uaslĂ³dĂ¡la comhaid.", + "upload_error.poll": "NĂ­ cheadaĂ­tear uaslĂ³dĂ¡il comhad le pobalbhreith.", "upload_form.audio_description": "Describe for people with hearing loss", "upload_form.description": "Describe for the visually impaired", "upload_form.edit": "Cuir in eagar", + "upload_form.thumbnail": "Athraigh mionsamhail", "upload_form.video_description": "Describe for people with hearing loss or visual impairment", "upload_modal.analyzing_picture": "Ag anailĂ­siĂº Ă­omhĂ¡â€¦", "upload_modal.apply": "Cuir i bhFeidhm", "upload_modal.applying": "Ă gcur i bhfeidhm…", "upload_modal.choose_image": "Roghnaigh Ă­omhĂ¡", "upload_modal.description_placeholder": "Chuaigh bĂ© mhĂ³rsĂ¡ch le dlĂºthspĂ¡d fĂ­orfhinn trĂ­ hata mo dhea-phorcĂ¡in bhig", + "upload_modal.detect_text": "Braith tĂ©acs Ă³ phictiĂºr", "upload_modal.edit_media": "Cuir gnĂ© in eagar", + "upload_modal.hint": "CliceĂ¡il nĂ³ tarraing an ciorcal ar an rĂ©amhamharc chun an pointe fĂ³casach a roghnĂº a bheidh le feiceĂ¡il i gcĂ³naĂ­ ar na mionsamhlacha go lĂ©ir.", + "upload_modal.preparing_ocr": "OCR Ă¡ ullmhĂºâ€¦", + "upload_modal.preview_label": "RĂ©amhamharc ({ratio})", "upload_progress.label": "Ag uaslĂ³dĂ¡il...", "upload_progress.processing": "Ag prĂ³iseĂ¡il…", + "username.taken": "Glactar leis an ainm ĂºsĂ¡ideora sin. Bain triail eile as", "video.close": "DĂºn fĂ­seĂ¡n", "video.download": "ĂoslĂ³dĂ¡il comhad", + "video.exit_fullscreen": "Scoir scĂ¡ileĂ¡n iomlĂ¡n", "video.expand": "Leath fĂ­seĂ¡n", "video.fullscreen": "LĂ¡nscĂ¡ileĂ¡n", "video.hide": "Cuir fĂ­seĂ¡n i bhfolach", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 03287c7e5224bc..c1e0f97f804764 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -92,7 +92,7 @@ "block_modal.remote_users_caveat": "Ămoslle pedir ao servidor {domain} que respecte a tĂºa decisiĂ³n. Emporiso, non hai garantĂ­a de que atenda a peticiĂ³n xa que os servidores xestionan os bloqueos de formas diferentes. As publicaciĂ³ns pĂºblicas poderĂ­an aĂ­nda ser visibles para usuarias que non iniciaron sesiĂ³n.", "block_modal.show_less": "Mostrar menos", "block_modal.show_more": "Mostrar mĂ¡is", - "block_modal.they_cant_mention": "Non te poden seguir nin mencionar.", + "block_modal.they_cant_mention": "Non te pode seguir nin mencionar.", "block_modal.they_cant_see_posts": "Non pode ver as tĂºas publicaciĂ³ns nin ti as de ela.", "block_modal.they_will_know": "Pode ver que a bloqueaches.", "block_modal.title": "Bloquear usuaria?", @@ -216,7 +216,7 @@ "domain_block_modal.they_wont_know": "Non saberĂ¡ que a bloqueaches.", "domain_block_modal.title": "Bloquear dominio?", "domain_block_modal.you_will_lose_followers": "Vanse eliminar todas as tĂºas seguidoras deste servidor.", - "domain_block_modal.you_wont_see_posts": "Non verĂ¡s publicaciĂ³ns ou notificaciĂ³n das usuarias neste servidor.", + "domain_block_modal.you_wont_see_posts": "Non verĂ¡s publicaciĂ³ns ou notificaciĂ³ns das usuarias deste servidor.", "domain_pill.activitypub_lets_connect": "PermĂ­teche conectar e interactuar con persoas non sĂ³ de Mastodon, se non tamĂ©n con outras apps sociais.", "domain_pill.activitypub_like_language": "ActivityPub Ă© algo asĂ­ como o idioma que Mastodon fala con outras redes sociais.", "domain_pill.server": "Servidor", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index 575c68de038955..36974c76026ecc 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -35,7 +35,9 @@ "account.follow_back": "ăƒ•ă‚©ăƒ­ăƒ¼ăƒăƒƒă‚¯", "account.followers": "ăƒ•ă‚©ăƒ­ăƒ¯ăƒ¼", "account.followers.empty": "ă¾ă èª°ă‚‚ăƒ•ă‚©ăƒ­ăƒ¼ă—ă¦ă„ă¾ă›ă‚“。", + "account.followers_counter": "{count, plural, other {{counter} ăƒ•ă‚©ăƒ­ăƒ¯ăƒ¼}}", "account.following": "ăƒ•ă‚©ăƒ­ăƒ¼ä¸­", + "account.following_counter": "{count, plural, other {{counter} ăƒ•ă‚©ăƒ­ăƒ¼}}", "account.follows.empty": "ă¾ă èª°ă‚‚ăƒ•ă‚©ăƒ­ăƒ¼ă—ă¦ă„ă¾ă›ă‚“。", "account.go_to_profile": "ăƒ—ăƒ­ăƒ•ă‚£ăƒ¼ăƒ«ăƒăƒ¼ă‚¸ă¸", "account.hide_reblogs": "@{name}ă•ă‚“ă‹ă‚‰ă®ăƒ–ăƒ¼ă‚¹ăƒˆă‚’é表示", @@ -61,6 +63,7 @@ "account.requested_follow": "{name}ă•ă‚“ăŒă‚ăªăŸă«ăƒ•ă‚©ăƒ­ăƒ¼ăƒªă‚¯ă‚¨ă‚¹ăƒˆă—ă¾ă—ăŸ", "account.share": "@{name}ă•ă‚“ă®ăƒ—ăƒ­ăƒ•ă‚£ăƒ¼ăƒ«ă‚’å…±æœ‰ă™ă‚‹", "account.show_reblogs": "@{name}ă•ă‚“ă‹ă‚‰ă®ăƒ–ăƒ¼ă‚¹ăƒˆă‚’è¡¨ç¤º", + "account.statuses_counter": "{count, plural, other {{counter} æ•ç¨¿}}", "account.unblock": "@{name}ă•ă‚“ă®ăƒ–ăƒ­ăƒƒă‚¯ă‚’è§£é™¤", "account.unblock_domain": "{domain}ă®ăƒ–ăƒ­ăƒƒă‚¯ă‚’è§£é™¤", "account.unblock_short": "ăƒ–ăƒ­ăƒƒă‚¯è§£é™¤", @@ -411,6 +414,8 @@ "limited_account_hint.action": "構ă‚ă表示ă™ă‚‹", "limited_account_hint.title": "ă“ă®ăƒ—ăƒ­ăƒ•ă‚£ăƒ¼ăƒ«ă¯{domain}ă®ăƒ¢ăƒ‡ăƒ¬ăƒ¼ă‚¿ăƒ¼ă«ă‚ˆă£ă¦é表示ă«ă•ă‚Œă¦ă„ă¾ă™ă€‚", "link_preview.author": "{name}", + "link_preview.more_from_author": "{name}ă•ă‚“ă®æ•ç¨¿ă‚’ă‚‚ă£ă¨èª­ă‚€", + "link_preview.shares": "{count, plural, other {{counter}件ă®æ•ç¨¿}}", "lists.account.add": "ăƒªă‚¹ăƒˆă«è¿½å ", "lists.account.remove": "ăƒªă‚¹ăƒˆă‹ă‚‰å¤–ă™", "lists.delete": "ăƒªă‚¹ăƒˆă‚’å‰é™¤", @@ -691,8 +696,11 @@ "server_banner.about_active_users": "éå»30日間ă«ă“ă®ă‚µăƒ¼ăƒăƒ¼ă‚’使用ă—ă¦ă„ă‚‹äºº (æœˆé–“ă‚¢ă‚¯ăƒ†ă‚£ăƒ–ăƒ¦ăƒ¼ă‚¶ăƒ¼)", "server_banner.active_users": "人ă®ă‚¢ă‚¯ăƒ†ă‚£ăƒ–ăƒ¦ăƒ¼ă‚¶ăƒ¼", "server_banner.administered_by": "管ç†è€…", + "server_banner.is_one_of_many": "{domain} ă¯ă€æ•°ă€…ă®ç‹¬ç«‹ă—ăŸMastodonă‚µăƒ¼ăƒăƒ¼ă®ă†ă¡ă®ă²ă¨ă¤ă§ă™ă€‚ă‚µăƒ¼ăƒăƒ¼ă«ç™»éŒ²ă—ă¦Fediverseă®ă‚³ăƒŸăƒ¥ăƒ‹ăƒ†ă‚£ă«å ă‚ă£ă¦ă¿ă¾ă›ă‚“ă‹ă€‚", "server_banner.server_stats": "ă‚µăƒ¼ăƒăƒ¼ă®æƒ…å ±", "sign_in_banner.create_account": "ă‚¢ă‚«ă‚¦ăƒ³ăƒˆä½œæˆ", + "sign_in_banner.follow_anyone": "連åˆå†…ă®èª°ă§ă‚‚ăƒ•ă‚©ăƒ­ăƒ¼ă—ă¦æ•ç¨¿ă‚’時系列ă§è¦‹ă‚‹ă“ă¨ăŒă§ăă¾ă™ă€‚ă‚¢ăƒ«ă‚´ăƒªă‚ºăƒ ă€åºƒå‘ă€ă‚¯ăƒªăƒƒă‚¯ăƒ™ă‚¤ăƒˆă¯ă‚ă‚ă¾ă›ă‚“。", + "sign_in_banner.mastodon_is": "Mastodonă«å‚å ă—ă¦ă€ä¸–ç•Œă§èµ·ăă¦ă„ă‚‹ă“ă¨ă‚’見ă¤ă‘ă‚ˆă†ă€‚", "sign_in_banner.sign_in": "ăƒ­ă‚°ă‚¤ăƒ³", "sign_in_banner.sso_redirect": "ăƒ­ă‚°ă‚¤ăƒ³ă¾ăŸă¯ç™»éŒ²", "status.admin_account": "@{name}ă•ă‚“ă®ăƒ¢ăƒ‡ăƒ¬ăƒ¼ă‚·ăƒ§ăƒ³ç”»é¢ă‚’é–‹ă", diff --git a/app/javascript/mastodon/locales/kab.json b/app/javascript/mastodon/locales/kab.json index de866cc1bc4c33..ab0a6ce22bdba0 100644 --- a/app/javascript/mastodon/locales/kab.json +++ b/app/javascript/mastodon/locales/kab.json @@ -1,6 +1,10 @@ { + "about.blocks": "Ulac agbur", "about.contact": "Anermis:", "about.disclaimer": "Mastodon d aseɣẓan ilelli, d aseɣẓan n uÉ£balu yeldin, d tnezzut n Mastodon gGmbH.", + "about.domain_blocks.preamble": "Maṣṭudun s umata yeá¸men-ak ad teẓreḠagbur, ad tesdemreḠakked yimseqdacen-nniá¸en seg yal aqeddac deg fedivers. Ha-tent-an É£ur-k tsuraf i yellan deg uqeddac-agi.", + "about.domain_blocks.silenced.title": "Æ”ur-s talast", + "about.domain_blocks.suspended.title": "Yeḥbes", "about.not_available": "TalÉ£ut-a ur tettwabder ara deg uqeddac-a.", "about.powered_by": "Azeá¹­á¹­a inmetti yettwasÉ£elsen sÉ£ur {mastodon}", "about.rules": "Ilugan n uqeddac", @@ -24,13 +28,17 @@ "account.featured_tags.last_status_at": "TasuffeÉ£t taneggarut ass n {date}", "account.featured_tags.last_status_never": "Ulac tisuffaÉ£", "account.follow": "Ḍfer", + "account.follow_back": "Ḍfer-it ula d keÄÄ·mm", "account.followers": "Imeá¸faren", "account.followers.empty": "Ar tura, ulac yiwen i yeá¹­á¹­afaá¹›en amseqdac-agi.", + "account.followers_counter": "{count, plural, one {{counter} n umá¸far} other {{counter} n yimeá¸faren}}", "account.following": "Yeá¹­á¹­afaá¹›", + "account.following_counter": "{count, plural, one {{counter} yettwaá¸faren} other {{counter} yettwaá¸faren}}", "account.follows.empty": "Ar tura, amseqdac-agi ur yeá¹­á¹­afaá¹› yiwen.", "account.go_to_profile": "Ddu É£er umaÉ£nu", "account.hide_reblogs": "Ffer ayen i ibeá¹­á¹­u @{name}", "account.joined_short": "Izeddi da seg ass n", + "account.languages": "Beddel tutlayin yettwajerden", "account.link_verified_on": "TaÉ£ara n useÉ£wen-a tettwasenqed ass n {date}", "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", @@ -49,6 +57,7 @@ "account.requested_follow": "{name} yessuter ad k·m-yeá¸fer", "account.share": "Bá¸u amaÉ£nu n @{name}", "account.show_reblogs": "Ssken-d inebá¸a n @{name}", + "account.statuses_counter": "{count, plural, one {{counter} n tsuffeÉ£t} other {{counter} n tsuffaÉ£}}", "account.unblock": "Serreḥ i @{name}", "account.unblock_domain": "Ssken-d {domain}", "account.unblock_short": "Serreḥ", @@ -166,6 +175,7 @@ "dismissable_banner.explore_tags": "D wiyi i d ihacá¹­agen i d-yettawin tamyigawt deg web anmetti ass-a. Ihacá¹­agen i sseqdacen ugar n medden, εlayit d imezwura.", "domain_block_modal.block": "Sewḥel aqeddac", "domain_block_modal.they_cant_follow": "Yiwen ur yezmir ad k·m-id-yeá¸fer seg uqeddac-a.", + "domain_block_modal.title": "Sewḥel taÉ£ult?", "domain_pill.activitypub_like_language": "ActivityPub am tutlayt yettmeslay Mastodon d izeá¸wan inmettiyen nniá¸en.", "domain_pill.server": "Aqeddac", "domain_pill.username": "Isem n useqdac", @@ -214,6 +224,7 @@ "filter_modal.added.review_and_configure_title": "IÉ£ewwaá¹›en n imzizdig", "filter_modal.added.settings_link": "asebter n yiÉ£ewwaá¹›en", "filter_modal.added.short_explanation": "TasuffeÉ£t-a tettwarna É£er taggayt-a n yimsizdegen: {title}.", + "filter_modal.added.title": "Yettwarna umsizdeg!", "filter_modal.select_filter.expired": "yemmut", "filter_modal.select_filter.prompt_new": "Taggayt tamaynutt : {name}", "filter_modal.select_filter.search": "Nadi neÉ£ snulfu-d", @@ -224,9 +235,10 @@ "firehose.remote": "Iqeddacen nniá¸en", "follow_request.authorize": "Ssireg", "follow_request.reject": "Agi", - "follow_suggestions.dismiss": "Ur ttÉ›awad ara ad t-id-sekneá¹­", + "follow_suggestions.dismiss": "Dayen ur t-id-skan ara", + "follow_suggestions.popular_suggestion_longer": "Yettwassen deg {domain}", "follow_suggestions.view_all": "Wali-ten akk", - "follow_suggestions.who_to_follow": "Menhu ara á¸efá¹›eá¸", + "follow_suggestions.who_to_follow": "Ad tá¸efreá¸?", "followed_tags": "Ihacá¹­agen yettwaá¸faren", "footer.about": "Æ”ef", "footer.directory": "Akaram n imeÉ£na", @@ -235,6 +247,7 @@ "footer.keyboard_shortcuts": "Inegzumen n unasiw", "footer.privacy_policy": "Tasertit tabaá¸nit", "footer.source_code": "Wali tangalt taÉ£balut", + "footer.status": "N tsuffeÉ£t", "generic.saved": "Yettwasekles", "getting_started.heading": "Bdu", "hashtag.column_header.tag_mode.all": "d {additional}", @@ -313,11 +326,14 @@ "lightbox.previous": "Æ”er deffir", "limited_account_hint.action": "Wali amaÉ£nu akken yebÉ£u yili", "link_preview.author": "S-É£ur {name}", + "link_preview.more_from_author": "Ugar sÉ£ur {name}", + "link_preview.shares": "{count, plural, one {{counter} post} other {{counter} posts}}", "lists.account.add": "Rnu É£er tebdart", "lists.account.remove": "Kkes seg tebdart", "lists.delete": "Kkes tabdart", "lists.edit": "Ẓreg tabdart", "lists.edit.submit": "Beddel azwel", + "lists.exclusive": "Ffer tisuffaÉ£-a seg ugejdan", "lists.new.create": "Rnu tabdart", "lists.new.title_placeholder": "Azwel amaynut n tebdart", "lists.replies_policy.followed": "Kra n useqdac i yettwaá¸efren", @@ -338,6 +354,7 @@ "navigation_bar.bookmarks": "Ticraá¸", "navigation_bar.community_timeline": "Tasuddemt tadigant", "navigation_bar.compose": "Aru tajewwiqt tamaynut", + "navigation_bar.direct": "Tibdarin tusligin", "navigation_bar.discover": "Ẓer", "navigation_bar.domain_blocks": "TiÉ£ula yeffren", "navigation_bar.explore": "Snirem", @@ -357,9 +374,14 @@ "navigation_bar.search": "Nadi", "navigation_bar.security": "TaÉ£ellist", "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.", + "notification.admin.report": "Yemla-t-id {name} {target}", + "notification.admin.sign_up": "Ijerred {name}", + "notification.favourite": "{name} yesmenyaf addad-ik·im", "notification.follow": "iá¹­á¹­afar-ik·em-id {name}", "notification.follow_request": "{name} yessuter-d ad k·m-yeá¸feá¹›", "notification.mention": "{name} yebder-ik-id", + "notification.moderation-warning.learn_more": "Issin ugar", + "notification.moderation_warning.action_suspend": "Yettwaseḥbes umiá¸an-ik.", "notification.own_poll": "Tafrant-ik·im tfuk", "notification.poll": "Tfukk tefrant ideg tettekkaá¸", "notification.reblog": "{name} yebá¸a tajewwiqt-ik i tikelt-nniá¸en", @@ -370,6 +392,7 @@ "notification_requests.notifications_from": "IlÉ£a sÉ£ur {name}", "notifications.clear": "SfeḠtilÉ£a", "notifications.clear_confirmation": "TebÉ£iḠs tidet ad tekkseḠakk tilÉ£a-inek·em i lebda?", + "notifications.column_settings.admin.report": "Ineqqisen imaynuten:", "notifications.column_settings.alert": "TilÉ£a n tnarit", "notifications.column_settings.favourite": "Imenyafen:", "notifications.column_settings.filter_bar.advanced": "Sken-d akk taggayin", @@ -384,6 +407,7 @@ "notifications.column_settings.sound": "Rmed imesli", "notifications.column_settings.status": "TisuffaÉ£ timaynutin :", "notifications.column_settings.unread_notifications.category": "IlÉ£a ur nettwaÉ£ra", + "notifications.column_settings.update": "Iẓreg:", "notifications.filter.all": "Akk", "notifications.filter.boosts": "Seǧhed", "notifications.filter.favourites": "Imenyafen", @@ -413,6 +437,7 @@ "onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!", "onboarding.follows.title": "Ttwassnen deg Mastodon", "onboarding.profile.display_name": "Isem ara d-yettwaskanen", + "onboarding.profile.display_name_hint": "Isem-ik·im ummid neÉ£ isem-ik·im n uqeṣṣer…", "onboarding.profile.note": "Tameddurt", "onboarding.profile.note_hint": "TzemreḠad d-@tbedreḠimdanen niá¸en neÉ£ #ihacá¹­agen …", "onboarding.profile.save_and_continue": "Sekles, tkemmleá¸", @@ -441,6 +466,7 @@ "poll.total_votes": "{count, plural, one {# n udÉ£aá¹›} other {# n yedÉ£aá¹›en}}", "poll.vote": "DÉ£eá¹›", "poll.voted": "TdeɣṛeḠɣef tririt-ayi", + "poll.votes": "{votes, plural, one {# n udÉ£aá¹›} other {# n yedÉ£aá¹›en}}", "poll_button.add_poll": "Rnu asenqed", "poll_button.remove_poll": "Kkes asenqed", "privacy.change": "Seggem tabaá¸nit n yizen", @@ -465,9 +491,12 @@ "relative_time.seconds": "{number}tas", "relative_time.today": "assa", "reply_indicator.cancel": "Sefsex", + "reply_indicator.poll": "Afmiá¸i", "report.block": "Sewḥel", + "report.categories.legal": "Azerfan", "report.categories.other": "Tiyyaá¸", "report.categories.spam": "Aspam", + "report.category.subtitle": "Fren amá¹£ada akk ufrin", "report.category.title_account": "ameÉ£nu", "report.category.title_status": "tasuffeÉ£t", "report.close": "Immed", @@ -476,13 +505,25 @@ "report.next": "Uá¸fiá¹›", "report.placeholder": "Iwenniten-nniá¸en", "report.reasons.dislike": "Ur t-ḥemmleÉ£ ara", + "report.reasons.dislike_description": "D ayen akk ur bÉ£iÉ£ ara ad waliÉ£", "report.reasons.other": "D ayen nniá¸en", + "report.reasons.other_description": "Ugur ur yemá¹£ada ara akk d taggayin-nniá¸en", "report.reasons.spam": "D aspam", + "report.reasons.spam_description": "Yir iseÉ£wan, yir agman d tririyin i d-yettuÉ£alen", + "report.reasons.violation": "Truẓi n yilugan n uqeddac", + "report.reasons.violation_description": "TeẓriḠy·tettruẓu kra n yilugan", + "report.rules.subtitle": "Fren ayen akk yemá¹£adan", + "report.rules.title": "Acu n yilugan i yettwarẓan?", + "report.statuses.subtitle": "Fren ayen akk yemá¹£adan", + "report.statuses.title": "Llant tsuffaÉ£ ara isdemren aneqqis-a?", "report.submit": "Azen", "report.target": "Mmel {target}", + "report.thanks.take_action_actionable": "Ideg nekkni nessenqad tuttra-inek•inem, tzemreḠad tḥadreḠmgal @{name}:", "report.thanks.title": "Ur tebÉ£iḠara ad twaliḠaya?", + "report.thanks.title_actionable": "Tanemmirt É£ef uneqqis, ad nwali deg waya.", "report.unfollow": "Seḥbes aá¸far n @{name}", "report_notification.attached_statuses": "{count, plural, one {# post} other {# posts}} attached", + "report_notification.categories.legal": "Azerfan", "report_notification.categories.other": "Ayen nniá¸en", "report_notification.categories.spam": "Aspam", "report_notification.open": "Ldi aneqqis", @@ -497,6 +538,7 @@ "search_popout.full_text_search_disabled_message": "Ur yelli ara deg {domain}.", "search_popout.language_code": "Tangalt ISO n tutlayt", "search_popout.options": "Iwellihen n unadi", + "search_popout.quick_actions": "Tigawin tiruradin", "search_popout.recent": "Inadiyen ineggura", "search_popout.user": "amseqdac", "search_results.accounts": "ImeÉ£na", @@ -505,7 +547,9 @@ "search_results.see_all": "Wali-ten akk", "search_results.statuses": "TisuffaÉ£", "search_results.title": "Anadi É£ef {q}", + "server_banner.active_users": "iseqdacen urmiden", "server_banner.administered_by": "Yettwadbel sÉ£ur :", + "server_banner.server_stats": "Tidaddanin n uqeddac:", "sign_in_banner.create_account": "Snulfu-d amiá¸an", "sign_in_banner.sign_in": "Qqen", "sign_in_banner.sso_redirect": "Qqen neÉ£ jerred", @@ -516,13 +560,21 @@ "status.cannot_reblog": "TasuffeÉ£t-a ur tezmir ara ad tettwabá¸u tikelt-nniá¸en", "status.copy": "NÉ£el assaÉ£ É£er tasuffeÉ£t", "status.delete": "Kkes", + "status.direct": "Bder-d @{name} weḥd-s", + "status.direct_indicator": "Abdar uslig", "status.edit": "Ẓreg", "status.edited_x_times": "Tettwaẓreg {count, plural, one {{count} n tikkelt} other {{count} n tikkal}}", "status.embed": "Seddu", + "status.favourite": "Amenyaf", + "status.favourites": "{count, plural, one {n usmenyaf} other {n ismenyafen}}", "status.filter": "Sizdeg tassufeÉ£t-a", "status.filtered": "Yettwasizdeg", "status.hide": "Ffer tasuffeÉ£t", + "status.history.created": "Yerna-t {name} {date}", + "status.history.edited": "Ibeddel-it {name} {date}", "status.load_more": "Sali ugar", + "status.media.open": "Sit i ulday", + "status.media.show": "Sit i uskan", "status.media_hidden": "Amidya yettwaffer", "status.mention": "Bder-d @{name}", "status.more": "Ugar", @@ -530,10 +582,11 @@ "status.mute_conversation": "Sgugem adiwenni", "status.open": "SemÉ£eá¹› tasuffeÉ£t-ayi", "status.pin": "Senteá¸-itt deg umaÉ£nu", - "status.pinned": "Tijewwiqin yettwasentá¸en", + "status.pinned": "TisuffaÉ£ yettwasentá¸en", "status.read_more": "Issin ugar", "status.reblog": "Bá¸u", "status.reblogged_by": "Yebá¸a-tt {name}", + "status.reblogs": "{count, plural, one {n usnerni} other {n yisnernuyen}}", "status.reblogs.empty": "Ula yiwen ur yebá¸i tajewwiqt-agi ar tura. Ticki yebá¸a-tt yiwen, ad d-iban da.", "status.redraft": "Kkes tÉ›iwdeḠtira", "status.remove_bookmark": "Kkes tacreá¸t", @@ -548,6 +601,7 @@ "status.show_less_all": "Semẓi akk tisuffÉ£in", "status.show_more": "Ssken-d ugar", "status.show_more_all": "Ẓerr ugar lebda", + "status.show_original": "Sken aÉ£balu", "status.title.with_attachments": "{user} posted {attachmentCount, plural, one {an attachment} other {# attachments}}", "status.translate": "Suqel", "status.translated_from_with": "Yettwasuqel seg {lang} s {provider}", @@ -582,6 +636,7 @@ "upload_form.video_description": "Glem-d i yemdanen i yesÉ›an ugur deg tmesliwt neÉ£ deg yiẓri", "upload_modal.analyzing_picture": "Tasleá¸t n tugna tetteddu…", "upload_modal.apply": "Snes", + "upload_modal.applying": "Asnas…", "upload_modal.choose_image": "Fren tugna", "upload_modal.description_placeholder": "AberraÉ£ arurad ineggez nnig n uqjun amuá¹­á¹­is", "upload_modal.detect_text": "Sefru-d aá¸ris seg tugna", @@ -589,6 +644,7 @@ "upload_modal.preparing_ocr": "Aheyyi n OCR…", "upload_modal.preview_label": "Taskant ({ratio})", "upload_progress.label": "Asali iteddu...", + "upload_progress.processing": "Asesfer…", "username.taken": "Yettwaá¹­á¹­ef yisem-a n useqdac. ÆreḠwayeá¸", "video.close": "Mdel tabidyutt", "video.download": "Sidered afaylu", diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index bb69b733997bd1..258e8ce08e92f3 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -1,6 +1,6 @@ { "about.blocks": "PrižiÅ«rimi serveriai", - "about.contact": "Kontaktai:", + "about.contact": "Kontaktuoti:", "about.disclaimer": "â€Mastodon“ – tai nemokama atvirojo kodo programinÄ— įranga ir â€Mastodon“ gGmbH prekÄ—s ženklas.", "about.domain_blocks.no_reason_available": "Priežastis nepateikta", "about.domain_blocks.preamble": "â€Mastodon“ paprastai leidžia peržiÅ«rÄ—ti turinį ir bendrauti su naudotojais iÅ¡ bet kurio kito fediverse esanÄio serverio. Å ios yra iÅ¡imtys, kurios buvo padarytos Å¡iame konkreÄiame serveryje.", @@ -230,7 +230,7 @@ "domain_pill.your_handle": "Tavo socialinis medijos vardas:", "domain_pill.your_server": "Tavo skaitmeniniai namai, kuriuose saugomi visi tavo įraÅ¡ai. Nepatinka Å¡is? Bet kada perkelk serverius ir atsivesk ir savo sekÄ—jus.", "domain_pill.your_username": "Tavo unikalus identifikatorius Å¡iame serveryje. Skirtinguose serveriuose galima rasti naudotojų su tuo paÄiu naudotojo vardu.", - "embed.instructions": "Ä®terpk šį įraÅ¡Ä… į savo svetainÄ™ nukopijavus (-usi) toliau pateiktÄ… kodÄ….", + "embed.instructions": "Ä®terpk šį įraÅ¡Ä… į savo svetainÄ™ nukopijuojant toliau pateiktÄ… kodÄ….", "embed.preview": "Å tai kaip tai atrodys:", "emoji_button.activity": "Veikla", "emoji_button.clear": "IÅ¡valyti", diff --git a/app/javascript/mastodon/locales/lv.json b/app/javascript/mastodon/locales/lv.json index 041072c6adecef..701569fa05ce1c 100644 --- a/app/javascript/mastodon/locales/lv.json +++ b/app/javascript/mastodon/locales/lv.json @@ -35,6 +35,7 @@ "account.follow_back": "Sekot atpakaļ", "account.followers": "SekotÄji", "account.followers.empty": "Å im lietotÄjam vÄ“l nav sekotÄju.", + "account.followers_counter": "{count, plural, zero {{count} sekotÄju} one {{count} sekotÄjs} other {{count} sekotÄji}}", "account.following": "Seko", "account.follows.empty": "Å is lietotÄjs pagaidÄm nevienam neseko.", "account.go_to_profile": "Doties uz profilu", @@ -312,9 +313,9 @@ "home.column_settings.show_reblogs": "RÄdÄ«t pastiprinÄtos ierakstus", "home.column_settings.show_replies": "RÄdÄ«t atbildes", "home.hide_announcements": "SlÄ“pt paziņojumus", - "home.pending_critical_update.body": "LÅ«dzu, pÄ“c iespÄ“jas ÄtrÄk atjaunini savu Mastodon serveri!", + "home.pending_critical_update.body": "LÅ«gums pÄ“c iespÄ“jas drÄ«zÄk atjauninÄt savu Mastodon serveri.", "home.pending_critical_update.link": "SkatÄ«t jauninÄjumus", - "home.pending_critical_update.title": "Pieejams kritisks droÅ¡Ä«bas jauninÄjums!", + "home.pending_critical_update.title": "Ir pieejams bÅ«tisks droÅ¡Ä«bas atjauninÄjums.", "home.show_announcements": "RÄdÄ«t paziņojumus", "interaction_modal.description.favourite": "Ar Mastodon kontu tu vari pievienot Å¡o ziņu izlasei, lai informÄ“tu autoru, ka to novÄ“rtÄ“, un saglabÄtu to vÄ“lÄkai lasÄ«Å¡anai.", "interaction_modal.description.follow": "Ar Mastodon kontu Tu vari sekot {name}, lai saņemtu lietotÄja ierakstus savÄ mÄjas plÅ«smÄ.", diff --git a/app/javascript/mastodon/locales/ry.json b/app/javascript/mastodon/locales/ry.json index 67aad910054010..4f2e2410eff4a2 100644 --- a/app/javascript/mastodon/locales/ry.json +++ b/app/javascript/mastodon/locales/ry.json @@ -3,6 +3,8 @@ "about.contact": "ĐĐ¾Đ½Ñ‚Đ°ĐºÑ‚:", "about.disclaimer": "Mastodon Ñ” Đ·Đ°Đ´Đ°Ñ€ÑŒĐ½Đ¾Đ² Đ¿Ñ€Đ¾̉‘Ñ€Đ°Đ¼Đ¾Đ² из ÑƒĐ´Đ¿ĐµÑ€Ñ‚Ñ‹Đ¼ ĐºĐ¾Đ´Đ¾Đ¼ Ñ‚Đ°Đ¹ Ñ‚Đ¾Ñ€Đ³Đ¾Đ²Đ¾Đ² Đ·Đ½Đ°Ñ‡ĐºĐ¾Đ² 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": "Đ—Đ°Đ±Đ»Đ¾ĐºĐ¾Đ²Đ°Đ½Đ¾", @@ -20,6 +22,7 @@ "account.browse_more_on_origin_server": "ĐŸĐ¾Đ·Đ¸Ñ€Đ°Đ¹Ñ‚Đµ Đ±ÑƒĐ»ÑŒÑˆĐµ Đ½Đ° Đ¾Ñ€Đ¸̉‘Ñ–Đ½Đ°Đ»Đ½ÑƒĐ¼ Đ¿Ñ€Đ¾Ñ„Ñ–Đ»Ñ", "account.cancel_follow_request": "Đ£Đ´Đ¼Ñ–Đ½Đ¸Ñ‚Đ¸ Đ¿ÑƒĐ´Đ¿Đ¸ÑĐºÑƒ", "account.copy": "Đ—ĐºĐ¾Đ¿Ñ–Ñ€Đ¾Đ²Đ°Ñ‚Đ¸ ÑƒĐ´ĐºĐ»Đ¸ĐºĐ¾Đ²Đ°Đ½Ñ Đ½Đ° Đ¿Ñ€Đ¾Ñ„Ñ–Đ»", + "account.direct": "ĐŸĐ¾ÑˆĐµĐ¿Ñ‚Đ°Ñ‚Đ¸ @{name}", "account.disable_notifications": "Đ‘ÑƒĐ»ÑŒÑˆĐµ Đ½Đµ ÑĐ¿Đ¾Đ²Ñ–Ñ‰Đ°Ñ‚Đ¸ Đ¼Đ¸ ĐºĐ¾Đ»Đ¸ {name} Đ¿Đ¸ÑˆĐµ", "account.domain_blocked": "Đ”Đ¾Đ¼ĐµĐ½ Đ·Đ°Đ±Đ»Đ¾ĐºĐ¾Đ²Đ°Đ½Ñ‹Đ¹", "account.edit_profile": "Đ£Đ¿Ñ€Đ°Đ²Đ¸Ñ‚Đ¸ Đ¿Ñ€Đ¾Ñ„Ñ–Đ»", @@ -39,8 +42,10 @@ "account.joined_short": "Đ”Đ°Ñ‚ÑƒĐ¼ Đ¿Ñ€Đ¸ĐºĐ°Đ¿Ñ‡Đ¾Đ²Đ°Đ½Ñ", "account.languages": "ĐŸĐ¾Đ¼Ñ–Đ½ÑÑ‚Đ¸ ÑƒĐ±Ñ€Đ°Đ½Ñ– ÑĐ·Ñ‹ĐºÑ‹", "account.link_verified_on": "ВлаÑÑ‚Đ½Đ¾ÑÑ‚ÑŒ ÑÑŒĐ¾Đ³Đ¾ ÑƒĐ´ĐºĐ»Đ¸ĐºĐ¾Đ²Đ°Đ½Ñ Đ±Ñ‹Đ»Đ¾ Đ·Đ²Ñ–Ñ€ĐµĐ½Đ¾ {date}", + "account.locked_info": "Đ¡Đ¸ÑÑŒ Đ¿Ñ€Đ¾Ñ„Ñ–Đ» Ñ” Đ·Đ°Đ¼ĐºĐ½ÑƒÑ‚Ñ‹Đ¹. ̉Đ°Đ·Đ´Đ° Đ°ĐºĐ°ÑƒĐ½Ñ‚Đ° Đ±ÑƒĐ´Đµ Ñ€ÑƒÑ‡Đ½Đ¾ Đ¿Ñ€Đ¾Đ²Ñ–Ñ€ÑÑ‚Đ¸ Ñ‚ĐºĐ¾ Đ³Đ¾ Đ¼Đ¾Đ¶Đµ Đ·Đ°Ñ„Đ¾Đ»Đ¾Đ²Đ¸Ñ‚Đ¸.", "account.media": "ĐœĐµĐ´Ñ–Đ°", - "account.moved_to": "Đ¥Đ¾ÑĐ½Đ¾Đ²Đ°Ñ‡ {name} ÑƒĐºĐ°Đ·Đ°Đ², Đ¾Đ¶ Đ½Đ¾Đ²Ñ‹Đ¹ Đ¿Ñ€Đ¾Ñ„Ñ–Đ» Đ¹Đ¸Đ¼ Ñ”:", + "account.mention": "Đ¡Đ¿Đ¾Đ¼ÑĐ½ÑƒÑ‚Đ¸ @{name}", + "account.moved_to": "Đ¥Đ¾ÑĐ½Đ¾Đ²Đ°Ñ‡ {name} ÑƒĐºĐ°Đ·Đ°Đ², Đ¾Đ¶ Đ½Đ¾Đ²Ñ‹Đ¹ Đ¿Ñ€Đ¾Ñ„Ñ–Đ» Đ¼Ñƒ Ñ”:", "account.mute": "Đ¡Ñ‚Đ¸ÑˆĐ¸Ñ‚Đ¸ {name}", "account.mute_notifications_short": "Đ¡Ñ‚Đ¸ÑˆĐ¸Ñ‚Đ¸ Đ³Đ¾Đ»Đ¾ÑˆÑ–Đ½Ñ", "account.mute_short": "Đ¡Ñ‚Đ¸ÑˆĐ¸Ñ‚Đ¸", @@ -60,9 +65,12 @@ "account.unblock_short": "Đ Đ¾Đ·Đ±Đ»Đ¾ĐºĐ¾Đ²Đ°Ñ‚Đ¸", "account.unendorse": "Đе ÑƒĐºĐ°Đ·Đ¾Đ²Đ°Ñ‚Đ¸ Đ½Đ° Đ¿Ñ€Đ¾Ñ„Ñ–Đ»Đ¾Đ²Đ¸", "account.unfollow": "Đ£Đ´Đ¿Đ¸ÑĐ°Ñ‚Đ¸ ÑÑ", + "account.unmute": "Đ£ĐºĐ°Đ·Đ¾Đ²Đ°Ñ‚Đ¸ {name}", "account.unmute_notifications_short": "Đ£ĐºĐ°Đ·Đ¾Đ²Đ°Ñ‚Đ¸ Đ³Đ¾Đ»Đ¾ÑˆÑ–Đ½Ñ", "account.unmute_short": "Đ£ĐºĐ°Đ·Đ¾Đ²Đ°Ñ‚Đ¸", "account_note.placeholder": "ĐĐ»Đ¾Đ¿ĐºĐ½Ñ–Ñ‚ Đ¾Đ±Ñ‹ Đ´Đ¾Đ´Đ°Ñ‚Đ¸ Đ¿Ñ€Đ¸Đ¼Ñ–Ñ‚ĐºÑƒ", + "admin.dashboard.retention.average": "Đ¡ĐµÑ€ĐµĐ´Đ½ÑŒĐ¾Ñ”", + "admin.dashboard.retention.cohort": "ĐœÑ–ÑÑць Đ¿Ñ€Đ¸ĐºĐ°Đ¿Ñ‡Đ¾Đ²Đ°Đ½Ñ", "admin.dashboard.retention.cohort_size": "ĐĐ¾Đ²Ñ– Ñ…Đ¾ÑĐ½Đ¾Đ²Đ°Ñ‡Ñ–", "admin.impact_report.instance_accounts": "ĐŸÑ€Đ¾Ñ„Ñ–Đ»Ñ– из Đ°ĐºĐ°ÑƒĐ½Ñ‚ÑƒĐ², ĐºĐ¾Ñ‚Ñ€Ñ– ÑÑ ÑƒĐ´Đ°Đ»ÑÑ‚", "admin.impact_report.instance_followers": "ĐŸÑƒĐ´Đ¿Đ¸ÑĐ½Đ¸ĐºÑ‹, ĐºĐ¾Ñ‚Ñ€Ñ‹Ñ… ÑÑ‚Ñ€Đ°Ñ‚ÑÑ‚ Đ½Đ°ÑˆÑ– Ñ…Đ¾ÑĐ½Đ¾Đ²Đ°Ñ‡Ñ–", @@ -70,11 +78,77 @@ "admin.impact_report.title": "Đ’Đ¿Đ»Ñ‹Đ² Ñ†Ñ–Đ»ĐºĐ¾Đ¼", "alert.rate_limited.message": "ĐŸĐ¾Đ¿Ñ€Đ¾Đ±ÑƒĐ¹Ñ‚Đµ Đ·Đ°ÑÑŒ Đ¿Đ¾ {retry_time, time, medium}.", "alert.rate_limited.title": "ЧаÑÑ‚Đ¾Ñ‚Đ° Đ¾Đ±Đ¼ĐµĐ¶ĐµĐ½Đ°", + "alert.unexpected.message": "Đ¡Ñ‚Đ°Đ»Đ° ÑÑ Đ½ĐµÑ‡ĐµĐºĐ°Đ½Đ° Ñ…Ñ‹Đ±Đ°.", + "alert.unexpected.title": "Đ˜Đ¹Đ¾Đ¹!", + "announcement.announcement": "Đ“Đ¾Đ»Đ¾ÑˆÑ–Đ½Ñ", + "audio.hide": "Đ—Đ¿Ñ€ÑÑ‚Đ°Ñ‚Đ¸ Đ·Đ²ÑƒĐº", + "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} Đ´Ñ€ÑƒĐ³Ñ‹Đ¹ Ñ€Đ°Đ· Đ¾Đ±Ñ‹ ÑеÑе Đ¿Ñ€Đ¾Đ¿ÑƒÑÑ‚Đ¸Ñ‚Đ¸", + "bundle_column_error.copy_stacktrace": "Đ£ĐºĐ¾Đ¿Ñ–Ñ€Đ¾Đ²Đ°Ñ‚Đ¸ Đ·Đ²Ñ–Ñ‚ Đ·Đ° Ñ…Ñ‹Đ±Ñƒ", + "bundle_column_error.error.body": "Đе Đ³Đ¾Đ´Đ½Đ¸ ÑÑŒĐ¼Đµ ÑƒĐºĐ°Đ·Đ°Ñ‚Đ¸ Đ·Đ°Đ¶Đ°Đ´Đ°Đ½Ñƒ ÑÑ‚Đ¾Ñ€ÑƒĐ½ĐºÑƒ. Đ“Đ¾Đ´Đ½Đ¾ Đ±Ñ‹Ñ‚Đ¸ ÑĐ¿Đ¾Đ·Đ°Đ´ Ñ…Ñ‹Đ±Ñ‹ у Đ½Đ°ÑˆÑƒĐ¼ ÑÑ–ÑÑ‚ĐµĐ¼Ñ–, Đ°Đ²Đ°Đ´ÑŒ Đ¿Ñ€Đ¾Đ±Đ»ĐµĐ¼Ñ‹ Đ·ÑƒĐ¼Ñ–ÑĐ½Đ¾ÑÑ‚Đ¸ Đ±Ñ€Đ°Đ²Đ·ĐµÑ€Đ°.", + "bundle_column_error.error.title": "Đ˜Đ¹Đ¾Đ¹!", + "bundle_column_error.network.body": "Đ¡Ñ‚Đ°Đ»Đ° ÑÑ Ñ…Ñ‹Đ±Đ° ÑĐº ÑÑŒĐ¼Đµ Đ¿Ñ€Đ¾Đ±Đ¾Đ²Đ°Đ»Đ¸ Đ½Đ°Đ¿Đ°Ñ€Đ¾Đ²Đ°Ñ‚Đ¸ ÑÑ‚Đ¾Ñ€ÑƒĐ½ĐºÑƒ. Đ“Đ¾Đ´Đ½Đ¾ ÑÑ Đ¹Ñе Đ±Ñ‹Đ»Đ¾ ÑÑ‚Đ°Ñ‚Đ¸ ÑĐ¿Đ¾Đ·Đ°Đ´ ÑĐ»Đ°Đ±Đ¾Đ³Đ¾ ÑĐ¿Đ¾Ñ”Đ½Ñ Đ²Đ°ÑˆĐ¾Đ³Đ¾ Ñ–Đ½Ñ‚ĐµÑ€Đ½ĐµÑ‚Đ°, Đ°Đ²Đ°Đ´ÑŒ ÑĐµÑ€Đ²ĐµÑ€Đ°.", + "bundle_column_error.network.title": "Đ¥Ñ‹Đ±Đ° ÑĐ¿Đ¾Ñ”Đ½Ñ", + "bundle_column_error.retry": "ĐŸĐ¾Đ¿Ñ€Đ¾Đ±ÑƒĐ¹Ñ‚Đµ Đ·Đ°ÑÑŒ", "bundle_column_error.return": "Đ’ĐµÑ€Đ½ÑƒÑ‚Đ¸ ÑÑ Đ½Đ° Đ³Đ¾Đ»Đ¾Đ²Đ½Ñƒ", "bundle_column_error.routing.body": "Đе Đ¼Đ¾Đ¶ĐµĐ¼Đµ Đ½Đ°Đ¹Ñ‚Đ¸ ÑÑĐºÑƒ ÑÑ‚Đ¾Ñ€ÑƒĐ½ĐºÑƒ. Đ‘Đ¸Đ·ÑƒĐ²Đ½Ñ– ÑÑŒÑ‚Đµ, Đ¾Đ¶ URL у Đ°Đ´Ñ€ĐµÑĐ½Đ¾Đ¼Ñƒ ÑˆĐ¾Ñ€Đ¸ĐºĐ¾Đ²Đ¸ Ñ” Đ´Đ¾Đ±Ñ€Ñ‹Đ¹?", "bundle_column_error.routing.title": "404", "bundle_modal_error.close": "Đ—Đ°Đ¿ĐµÑ€Ñ‚Đ¸", "bundle_modal_error.message": "Đ¨Ñ‚Đ¾ÑÑŒ ÑÑ Đ¿Đ¾ĐºĐ°Đ·Đ¸Đ»Đ¾, Đ·Đ°ĐºĐ¸Đ´ÑŒ ÑÑŒĐ¼Đµ Đ»Đ°Đ´Đ¾Đ²Đ°Đ»Đ¸ ÑиÑÑŒ ĐºĐ¾Đ¼Đ¿Đ¾Đ½ĐµĐ½Ñ‚.", "bundle_modal_error.retry": "ĐŸĐ¾Đ¿Ñ€Đ¾Đ±Đ¾Đ²Đ°Ñ‚Đ¸ Đ·Đ°ÑÑŒ", - "closed_registrations.other_server_instructions": "Mastodon Ñ” Đ´ĐµÑ†ĐµĐ½Ñ‚Ñ€Đ°Đ»Ñ–Đ·Đ¾Đ²Đ°Đ½Đ¾Đ² Đ¿Đ»Đ°Ñ‚Ñ„Đ¾Ñ€Đ¼Đ¾Đ², Đ¼Đ¾Đ¶ĐµÑ‚Đµ Ñи ÑƒÑ‡Đ¸Đ½Đ¸Ñ‚Đ¸ Đ¿Ñ€Đ¾Ñ„Ñ–Đ» и Đ½Đ° Đ´Ñ€ÑƒĐ³Đ¾Đ¼Ñƒ ÑĐµÑ€Đ²ĐµÑ€Đ¾Đ²Đ¸ Ñ‚Đ°Đ¹ ĐºĐ¾Đ¼ÑƒĐ½Ñ–ĐºĐ¾Đ²Đ°Ñ‚Đ¸ из ÑĐ¸Đ¼." + "closed_registrations.other_server_instructions": "Mastodon Ñ” Đ´ĐµÑ†ĐµĐ½Ñ‚Ñ€Đ°Đ»Ñ–Đ·Đ¾Đ²Đ°Đ½Đ¾Đ² Đ¿Đ»Đ°Ñ‚Ñ„Đ¾Ñ€Đ¼Đ¾Đ², Đ¼Đ¾Đ¶ĐµÑ‚Đµ Ñи ÑƒÑ‡Đ¸Đ½Đ¸Ñ‚Đ¸ Đ¿Ñ€Đ¾Ñ„Ñ–Đ» и Đ½Đ° Đ´Ñ€ÑƒĐ³Đ¾Đ¼Ñƒ ÑĐµÑ€Đ²ĐµÑ€Đ¾Đ²Đ¸ Ñ‚Đ°Đ¹ ĐºĐ¾Đ¼ÑƒĐ½Ñ–ĐºĐ¾Đ²Đ°Ñ‚Đ¸ из ÑĐ¸Đ¼.", + "closed_registrations_modal.description": "Đ Đ°Đ· Đ½Đµ Đ¼Đ¾Đ¶ ÑƒÑ‡Đ¸Đ½Đ¸Ñ‚Đ¸ Đ¿Ñ€Đ¾Ñ„Ñ–Đ» Đ½Đ° {domain}, Đ°Đ¹Đ±Đ¾ Đ½Đµ Đ¼ÑƒÑĐ¸Ñ‚Đµ Đ¼Đ°Ñ‚Đ¸ Đ¿Ñ€Đ¾Ñ„Ñ–Đ» Đ¸Đ¿ĐµĐ½ Đ½Đ° ÑĐµÑ€Đ²ĐµÑ€Đ¾Đ²Đ¸ {domain} Đ¾Đ±Ñ‹ Ñ…Đ¾ÑĐ½Đ¾Đ²Đ°Ñ‚Đ¸ Mastodon.", + "closed_registrations_modal.find_another_server": "ĐĐ°Đ¹Ñ‚Đ¸ Đ´Ñ€ÑƒĐ³Ñ‹Đ¹ ÑĐµÑ€Đ²ĐµÑ€", + "column.about": "Đ—Đ° ÑĐ°Đ¹Ñ‚", + "column.blocks": "Đ—Đ°Đ±Đ»Đ¾ĐºĐ¾Đ²Đ°Đ½Ñ– Ñ…Đ¾ÑĐ½Đ¾Đ²Đ°Ñ‡Ñ–", + "column.bookmarks": "Đ£ÑĐ¾ĐºĐ¾Ñ‡ĐµĐ½Đ¾Ñ”", + "column.direct": "Đ¨ĐµĐ¿Ñ‚Đ°Đ½Ñ", + "column.directory": "ĐĐ¸ĐºĐ°Ñ‚Đ¸ Đ¿Ñ€Đ¾Ñ„Ñ–Đ»Ñ–", + "column.domain_blocks": "Đ—Đ°Đ±Đ»Đ¾ĐºĐ¾Đ²Đ°Đ½Ñ– Đ´Đ¾Đ¼ĐµĐ½Ñ‹", + "column.favourites": "Đ£Đ±Ñ€Đ°Đ½Đ¾Ñ”", + "column.follow_requests": "Đ—Đ°Đ¿Ñ€Đ¾ÑÑ‹ Đ½Đ° Đ¿ÑƒĐ´Đ¿Đ¸ÑĐºÑƒ", + "column.lists": "Đ˜ÑĐ¿Đ¸ÑÑ‹", + "column.mutes": "Đ¡Ñ‚Đ¸ÑˆĐµĐ½Ñ– Ñ…Đ¾ÑĐ½Đ¾Đ²Đ°Ñ‡Ñ–", + "column.notifications": "Đ£Đ±Đ²Ñ–Ñ‰ĐµĐ½Ñ", + "column.pins": "Đ—Đ°ĐºÑ€Ñ–Đ¿Đ»ĐµĐ½Ñ– Đ¿ÑƒĐ±Đ»Đ¸ĐºĐ°Ñ†Ñ–Ñ—", + "column_back_button.label": "ĐĐ°Đ·Đ°Đ´", + "column_header.hide_settings": "Đ¡Đ¿Ñ€ÑÑ‚Đ°Ñ‚Đ¸ ÑˆÑ‚Ñ–Đ¼Đ¾Đ²Đ°Đ½Ñ", + "column_header.moveLeft_settings": "ĐŸĐ¾ÑÑƒĐ½ÑƒÑ‚Đ¸ ĐºĐ¾Đ»Đ¾Đ½ĐºÑƒ Đ´Đ¾ Đ»Ñ–Đ²Đ°", + "column_header.moveRight_settings": "ĐŸĐ¾ÑÑƒĐ½ÑƒÑ‚Đ¸ ĐºĐ¾Đ»Đ¾Đ½ĐºÑƒ Đ´Đ¾ Đ¿Ñ€Đ°Đ²Đ°", + "column_header.pin": "Đ—Đ°ĐºÑ€Ñ–Đ¿Đ¸Ñ‚Đ¸", + "column_header.show_settings": "Đ£ĐºĐ°Đ·Đ°Ñ‚Đ¸ ÑˆÑ‚Ñ–Đ¼Đ¾Đ²Đ°Đ½Ñ", + "column_header.unpin": "Đ£Đ´ĐºÑ€Ñ–Đ¿Đ¸Ñ‚Đ¸", + "column_subheading.settings": "Đ¨Ñ‚Ñ–Đ¼Đ¾Đ²Đ°Đ½Ñ", + "compose.language.change": "ĐŸĐ¾Đ¼Ñ–Đ½ÑÑ‚Đ¸ ÑĐ·Ñ‹Đº", + "compose.language.search": "Đ“Đ»ÑĐ´Đ°Ñ‚Đ¸ ÑĐ·Ñ‹ĐºÑ‹...", + "compose.published.body": "ĐŸĐ¾ÑÑ‚ Đ¾Đ¿ÑƒĐ±Đ»Đ¸ĐºĐ¾Đ²Đ°Đ½Ñ‹Đ¹.", + "compose.saved.body": "ĐŸĐ¾ÑÑ‚ уÑĐ¾ĐºĐ¾Ñ‡ĐµĐ½Ñ‹Đ¹.", + "compose_form.direct_message_warning_learn_more": "Đ§Đ¸Ñ‚Đ°Đ¹Ñ‚Đµ Đ±ÑƒĐ»ÑŒÑˆĐµ", + "compose_form.encryption_warning": "ĐŸÑƒĐ±Đ»Đ¸ĐºĐ°Ñ†Ñ–Ñ— Đ½Đ° Mastodon Đ½Đµ ÑˆÑ–Ñ„Ñ€ÑƒĐ²ÑƒÑ‚ ÑÑ. Đе ÑˆÑ‹Ñ€ÑŒÑ‚Đµ Ñ‡ÑƒÑ‚Đ»Đ¸Đ²Ñƒ Ñ–Đ½Ñ„Đ¾Ñ€Đ¼Đ°Ñ†Ñ–Ñ Ñ‡ĐµÑ€ĐµĐ· Mastodon.", + "compose_form.hashtag_warning": "Đ¡Đ¸ÑÑŒ Đ¿Đ¾ÑÑ‚ Đ½Đµ Đ±ÑƒĐ´Đµ ÑÑ Đ¿Đ¾ÑĐ²Đ»ÑÑ‚Đ¸ у иÑĐ¿Đ¸ÑĐ¾Đ²Đ¸ Đ¿Đ¾ Đ³ĐµÑˆÑ‚Đµ̉‘Đ¾Đ²Đ¸, Đ±Đ¾ Đ²ÑƒĐ½ Đ½Đµ Ñ” Đ¿ÑƒĐ±Đ»Đ¸Ñ‡Đ½Ñ‹Đ¹. Đ›Đ¸ÑˆĐµĐº Đ¿ÑƒĐ±Đ»Đ¸Ñ‡Đ½Ñ– Đ¿Đ¾ÑÑ‚Ñ‹ Đ±ÑƒĐ´Đµ Đ²Đ¸Đ´ĐºĐ¾ Đ·Đ° Đ³ĐµÑˆÑ‚Đµ̉‘Đ¾Đ¼.", + "compose_form.lock_disclaimer": "Đ’Đ°Ñˆ Đ¿Ñ€Đ¾Ñ„Ñ–Đ» Ñ” {locked}. Đ¥Đ¾Ñ‚ÑŒ-Ñ‚ĐºĐ¾ Đ¼Đ¾Đ¶Đµ ÑÑ Đ½Đ° Đ²Đ°Ñ Đ¿ÑƒĐ´Đ¿Đ¸ÑĐ°Ñ‚Đ¸, Đ¾Đ±Ñ‹ Đ²Đ¸Đ´Ñ—Ñ‚Đ¸ Đ²Đ°ÑˆÑ– ĐµĐºÑĐºĐ»ÑƒĐ·Ñ–Đ²Đ½Ñ– Đ¿Đ¾ÑÑ‚Ñ‹.", + "compose_form.lock_disclaimer.lock": "Đ·Đ°Đ¼ĐºĐ½ĐµĐ½Đ¾", + "compose_form.placeholder": "Đ¨Ñ‚Đ¾ Đ½Đ¾Đ²Đ¾Đ³Đ¾?", + "compose_form.poll.duration": "Đ¢Ñ€Ñ‹Đ²Đ°Đ»Đ¾ÑÑ‚ÑŒ ÑƒĐ±Đ·Đ²Ñ–Đ´Đ¾Đ²Đ°Đ½Ñ", + "compose_form.poll.multiple": "Đ”Đ°ĐºÑƒĐ»ÑŒĐºĐ¾ Đ²Đ°Ñ€Ñ–Đ°Đ½Ñ‚ÑƒĐ²", + "compose_form.poll.option_placeholder": "Đ’Đ°Ñ€Ñ–Đ°Đ½Ñ‚ {number}", + "compose_form.poll.single": "Đ£Đ±ĐµÑ€Ñ–Ñ‚ Ñ”Đ´ĐµĐ½", + "compose_form.poll.switch_to_multiple": "Đ—Đ¼Ñ–Đ½Đ¸Ñ‚Đ¸ ÑƒĐ±Đ·Đ²Ñ–Đ´Đ¾Đ²Đ°Đ½Ñ Đ¾Đ±Ñ‹ Đ¿Đ¾Đ²Đ¾Đ»Đ¸Ñ‚Đ¸ Đ´Đ°ĐºÑƒĐ»ÑŒĐºĐ¾ Đ²Đ°Ñ€Ñ–Đ°Đ½Ñ‚ÑƒĐ²", + "compose_form.poll.switch_to_single": "Đ—Đ¼Ñ–Đ½Đ¸Ñ‚Đ¸ ÑƒĐ±Đ·Đ²Ñ–Đ´Đ¾Đ²Đ°Đ½Ñ Đ¾Đ±Ñ‹ Đ¿Đ¾Đ²Đ¾Đ»Đ¸Ñ‚Đ¸ Đ»Đ¸ÑˆĐµĐº Ñ”Đ´ĐµĐ½ Đ²Đ°Ñ€Ñ–Đ°Đ½Ñ‚", + "compose_form.poll.type": "Đ¡Ñ‚Ñ–Đ»", + "compose_form.publish": "ĐŸÑƒĐ±Đ»Đ¸ĐºĐ°Ñ†Ñ–Ñ", + "compose_form.publish_form": "ĐĐ¾Đ²Đ° Đ¿ÑƒĐ±Đ»Đ¸ĐºĐ°Ñ†Ñ–Ñ", + "compose_form.reply": "Đ£Đ´Đ¿Đ¾Đ²Ñ–Đ´ÑŒ", + "copypaste.copy_to_clipboard": "ĐĐ¾Đ¿Ñ–Ñ€Đ¾Đ²Đ°Ñ‚Đ¸ у Đ¿Đ°Đ¼Đ½ÑÑ‚ÑŒ", + "directory.recently_active": "ĐĐµĐ´Đ°Đ²Đ½Đ¾ Đ°ĐºÑ‚Ñ–Đ²Đ½Ñ–", + "disabled_account_banner.account_settings": "Đ¨Ñ‚Ñ–Đ¼Đ¾Đ²Đ°Đ½Ñ Đ°ĐºĐ°ÑƒĐ½Ñ‚Đ°", + "disabled_account_banner.text": "Đ’Đ°Ñˆ Đ°ĐºĐ°ÑƒĐ½Ñ‚ {disabledAccount} Ñ€Đ°Đ· Ñ” Đ½ĐµĐ°ĐºÑ‚Ñ–Đ²Đ½Ñ‹Đ¹.", + "dismissable_banner.community_timeline": "Đ¢ÑƒĐ¹ Ñут Đ½ĐµĐ´Đ°Đ²Đ½Ñ– Đ¿ÑƒĐ±Đ»Đ¸ĐºĐ°Ñ†Ñ–Ñ— ÑƒĐ´ Đ¿Ñ€Đ¾Ñ„Ñ–Đ»ÑƒĐ² Đ½Đ° ÑĐµÑ€Đ²ĐµÑ€Đ¾Đ²Đ¸ {domain}." } diff --git a/app/javascript/mastodon/locales/si.json b/app/javascript/mastodon/locales/si.json index fbfdfaa659d131..3a67beed527a59 100644 --- a/app/javascript/mastodon/locales/si.json +++ b/app/javascript/mastodon/locales/si.json @@ -33,6 +33,7 @@ "account.mute": "@{name} නිහඬ à¶à¶»à¶±à·à¶±", "account.mute_short": "නිහඬ", "account.muted": "නිහඬ à¶à·…à·", + "account.open_original_page": "මුල෠පිටුව අරිනà·à¶±", "account.posts": "ලිපි", "account.posts_with_replies": "ලිපි සහ පිළිතුරු", "account.report": "@{name} à·€à·à¶»à·à¶­à· à¶à¶»à¶±à·à¶±", @@ -51,6 +52,10 @@ "alert.unexpected.title": "අපොයි!", "announcement.announcement": "නිවà·à¶¯à¶±à¶º", "audio.hide": "හඬපටය සඟවනà·à¶±", + "block_modal.show_less": "අඩුවෙන෠පෙනà·à·€à¶±à·à¶±", + "block_modal.show_more": "තව පෙනà·à·€à¶±à·à¶±", + "block_modal.they_will_know": "අවහිර à¶à·… බව දà¶à·’නු ඇත.", + "block_modal.title": "අවහිර à¶à¶»à¶±à·à¶±à¶¯?", "boost_modal.combo": "à¶à·…ඟ වතà·à·€à· මෙය මඟ à·„à·à¶»à·“මට {combo} එබීමට à·„à·à¶à·’ය", "bundle_column_error.copy_stacktrace": "දà·à·‚ à·€à·à¶»à·à¶­à·à·€à· පිටපතà¶à·", "bundle_column_error.error.title": "අපොයි!", @@ -100,10 +105,13 @@ "compose_form.lock_disclaimer.lock": "අගුළු දම෠ඇත", "compose_form.placeholder": "ඔබග෠සිතුවිලි මොනවà·à¶¯?", "compose_form.poll.duration": "මත විමසීම෠à¶à·à¶½à¶º", + "compose_form.poll.option_placeholder": "විà¶à¶½à·à¶´à¶º {number}", "compose_form.poll.switch_to_multiple": "තà·à¶»à·“ම෠à¶à·’හිපයà¶à¶§ මත විමසුම වෙනස෠à¶à¶»à¶±à·à¶±", "compose_form.poll.switch_to_single": "තනි තà·à¶»à·“මà¶à¶§ මත විමසුම වෙනස෠à¶à¶»à¶±à·à¶±", + "compose_form.poll.type": "à·à·›à¶½à·’ය", "compose_form.publish": "පà·â€à¶»à¶à·à·à¶±à¶º", "compose_form.publish_form": "නව ලිපිය", + "compose_form.reply": "පිළිතුරු", "compose_form.spoiler.marked": "අනà·à¶­à¶»à·à¶œà¶­ අවවà·à¶¯à¶º ඉවත෠à¶à¶»à¶±à·à¶±", "compose_form.spoiler.unmarked": "අනà·à¶­à¶»à·à¶œà¶­ අවවà·à¶¯à¶ºà¶à· එà¶à· à¶à¶»à¶±à·à¶±", "confirmation_modal.cancel": "අවලංගු", @@ -123,6 +131,7 @@ "conversation.mark_as_read": "à¶à·’යවූ බව යොදනà·à¶±", "conversation.open": "සංවà·à¶¯à¶º බලනà·à¶±", "conversation.with": "{names} සමඟ", + "copy_icon_button.copied": "පසුරුපුවරුවට පිටපත෠විය", "copypaste.copied": "පිටපත෠විය", "copypaste.copy_to_clipboard": "පසුරුපුවරුවට පිටපතà¶à·", "directory.federated": "දනà·à¶±à· ෆෙඩිවරà·à·ƒà· වෙතිනà·", @@ -130,6 +139,9 @@ "directory.new_arrivals": "නව පà·à¶¸à·’ණීමà·", "directory.recently_active": "මෑත දී à·ƒà¶à·â€à¶»à·’යයි", "disabled_account_banner.account_settings": "ගිණුම෠සà·à¶à·ƒà·”මà·", + "dismissable_banner.dismiss": "ඉවතලනà·à¶±", + "domain_pill.server": "à·ƒà·à·€à·à¶¯à·à¶ºà¶à¶º", + "domain_pill.username": "පරිà·à·â€à¶»à·“ලචනà·à¶¸à¶º", "embed.instructions": "පහත à¶à·à¶­à¶º පිටපත෠à¶à·’රීමෙන෠මෙම ලිපිය ඔබග෠අඩවියට à¶à·à·€à¶¯à·à¶¯à¶±à·à¶±.", "embed.preview": "මෙනà·à¶± එය පෙනෙන අනà·à¶¯à¶¸:", "emoji_button.activity": "à¶à·â€à¶»à·’යà·à¶à·à¶»à¶à¶¸", @@ -178,9 +190,13 @@ "filter_modal.select_filter.search": "සොයනà·à¶± à·„à· à·ƒà·à¶¯à¶±à·à¶±", "filter_modal.select_filter.title": "මෙම ලිපිය පෙරනà·à¶±", "filter_modal.title.status": "ලිපියà¶à· පෙරනà·à¶±", + "filtered_notifications_banner.title": "පෙරූ දà·à¶±à·”මà·à¶¯à·“මà·", + "firehose.all": "සියලà·à¶½", "firehose.local": "මෙම à·ƒà·à·€à·à¶¯à·à¶ºà¶à¶º", "firehose.remote": "වෙනත෠සà·à·€à·à¶¯à·à¶ºà¶", "follow_request.reject": "පà·â€à¶»à¶­à·’à¶à·â€à·‚à·à¶´", + "follow_suggestions.dismiss": "නà·à·€à¶­ පෙනà·à·€à¶±à·à¶± එපà·", + "follow_suggestions.view_all": "සියලà·à¶½ බලනà·à¶±", "footer.about": "පිළිබඳව", "footer.directory": "පà·à¶­à·’à¶à¶© නà·à¶¸à·à·€à¶½à·’ය", "footer.get_app": "යෙදුම ගනà·à¶±", @@ -202,6 +218,7 @@ "home.pending_critical_update.link": "යà·à·€à¶­à·à¶à·à¶½ බලනà·à¶±", "home.show_announcements": "නිවà·à¶¯à¶± පෙනà·à·€à¶±à·à¶±", "interaction_modal.login.action": "මුලට ගෙනයනà·à¶±", + "interaction_modal.on_another_server": "වෙනත෠සà·à·€à·à¶¯à·à¶ºà¶à¶ºà¶", "interaction_modal.on_this_server": "මෙම à·ƒà·à·€à·à¶¯à·à¶ºà¶à¶ºà·™à·„à·’", "interaction_modal.title.favourite": "{name}ග෠ලිපිය පà·â€à¶»à·’ය à¶à¶»à¶±à·à¶±", "interaction_modal.title.follow": "{name} අනුගමනය", diff --git a/app/javascript/mastodon/locales/tok.json b/app/javascript/mastodon/locales/tok.json index 80d412a20bc35a..fcdef5f32ce744 100644 --- a/app/javascript/mastodon/locales/tok.json +++ b/app/javascript/mastodon/locales/tok.json @@ -170,6 +170,8 @@ "domain_block_modal.block": "o weka e ma", "domain_block_modal.you_will_lose_followers": "ma ni la jan alasa ale sina li weka", "domain_block_modal.you_wont_see_posts": "sina ken ala lukin e toki tan jan pi ma ni", + "domain_pill.server": "ma", + "domain_pill.username": "nimi jan", "embed.preview": "ni li jo e sitelen ni:", "emoji_button.activity": "musi", "emoji_button.flags": "len ma", @@ -274,6 +276,7 @@ "load_pending": "{count, plural, other {ijo sin #}}", "loading_indicator.label": "ni li kama…", "media_gallery.toggle_visible": "{number, plural, other {o len e sitelen}}", + "mute_modal.title": "sina wile ala wile kute e jan ni?", "navigation_bar.about": "sona", "navigation_bar.blocks": "jan weka", "navigation_bar.compose": "o pali e toki sin", @@ -290,24 +293,33 @@ "notification.follow": " {name} li kute e sina", "notification.follow_request": "{name} li wile kute e sina", "notification.mention": "jan {name} li toki e sina", + "notification.moderation-warning.learn_more": "o kama sona e ijo ante", "notification.poll": "sina pana lon pana la pana ni li pini", "notification.reblog": "{name} li wawa e toki sina", "notification.status": "{name} li toki", "notification.update": "{name} li ante e toki", + "notification_requests.dismiss": "o weka", "notifications.column_settings.favourite": "ijo pona:", "notifications.column_settings.follow": "jan kute sin", "notifications.column_settings.poll": "pana lon pana ni:", "notifications.column_settings.reblog": "wawa:", + "notifications.column_settings.status": "toki sin:", "notifications.column_settings.update": "ante toki:", "notifications.filter.all": "ale", + "notifications.filter.boosts": "wawa", "notifications.filter.favourites": "ijo pona", + "notifications.filter.mentions": "toki pi toki sina", "notifications.filter.polls": "pana lon pana ni", + "onboarding.action.back": "o tawa monsi", + "onboarding.actions.back": "o tawa monsi", "onboarding.compose.template": "toki a, #Mastodon o!", "onboarding.profile.display_name": "nimi tawa jan ante", + "onboarding.profile.note": "sona sina", "onboarding.share.lead": "o toki lon nasin Masoton pi alasa sina tawa jan", "onboarding.share.message": "ilo #Mastodon la mi jan {username} a! o kute e mi lon ni: {url}", "onboarding.start.title": "sina o kama pona a!", "onboarding.tips.migration": "sina sona ala sona e ni? tenpo kama la sina pilin ike tawa ma {domain} la, sina ken tawa ma ante lon ilo Masoton. jan li kute e sina la jan ni li awen kute e sina. kin la sina ken lawa e ma pi sina taso a!", + "poll.closed": "ona li pini", "poll.total_people": "{count, plural, other {jan #}}", "poll.total_votes": "{count, plural, other {pana #}}", "poll.vote": "o pana", @@ -315,9 +327,15 @@ "poll.votes": "{votes, plural, other {pana #}}", "privacy.direct.long": "jan ale lon toki", "privacy.public.short": "tawa ale", + "regeneration_indicator.label": "ni li kama…", + "relative_time.days": "{number}d", "relative_time.full.just_now": "tenpo ni", + "relative_time.hours": "{number}h", "relative_time.just_now": "tenpo ni", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "relative_time.today": "tenpo suno ni", + "reply_indicator.cancel": "o ala", "report.block": "o weka e jan", "report.block_explanation": "sina kama lukin ala e toki ona. ona li kama ala ken lukin e toki sina li kama ala ken kute e sina. ona li ken sona e kama ni.", "report.categories.other": "ante", @@ -336,6 +354,7 @@ "report.thanks.title": "sina wile ala lukin e ni anu seme?", "report.unfollow": "o pini kute e {name}", "report_notification.categories.legal": "ike tawa nasin lawa", + "report_notification.categories.other": "ante", "search.placeholder": "o alasa", "search.quick_action.go_to_account": "o tawa lipu jan {x}", "search_popout.language_code": "nimi toki kepeken nasin ISO", @@ -343,6 +362,7 @@ "search_results.see_all": "ale", "search_results.statuses": "toki", "search_results.title": "o alasa e {q}", + "server_banner.administered_by": "jan lawa:", "status.block": "o weka e @{name}", "status.cancel_reblog_private": "o pini e pana", "status.delete": "o weka", @@ -356,12 +376,14 @@ "status.media.open": "o open", "status.media.show": "o lukin", "status.media_hidden": "sitelen li len", + "status.more": "kin", "status.mute": "o len e @{name}", "status.mute_conversation": "o kute ala e ijo pi toki ni", "status.pin": "o sewi lon lipu sina", "status.pinned": "toki sewi", "status.reblog": "o wawa", "status.share": "o pana tawa ante", + "status.show_filter_reason": "o lukin", "status.show_less": "o lili e ni", "status.show_less_all": "o lili e ale", "status.show_more": "o suli e ni", @@ -378,7 +400,9 @@ "timeline_hint.resources.follows": "jan lukin", "timeline_hint.resources.statuses": "ijo pi tenpo suli", "trends.trending_now": "jan mute li toki", + "units.short.billion": "{count}B", "units.short.million": "{count}AAA", + "units.short.thousand": "{count}K", "upload_button.label": "o pana e sitelen anu kalama", "upload_error.limit": "ilo li ken ala e suli pi ijo ni.", "upload_form.audio_description": "o toki e ijo kute tawa jan pi kute ala, tawa jan pi kute lili", @@ -386,6 +410,7 @@ "upload_form.edit": "o ante", "upload_form.thumbnail": "o ante e sitelen lili", "upload_form.video_description": "o toki e ijo kute tawa jan pi kute ala, tawa jan pi kute lili, e ijo lukin tawa jan pi lukin ala, tawa jan pi lukin lili", + "upload_modal.analyzing_picture": "ilo li lukin e sitelen...", "upload_modal.choose_image": "o wile e sitelen", "upload_modal.description_placeholder": "mi pu jaki tan soweli", "upload_modal.detect_text": "ilo o alasa e nimi tan sitelen", diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json index 150b808f894651..67ebb031aefcd0 100644 --- a/app/javascript/mastodon/locales/uk.json +++ b/app/javascript/mastodon/locales/uk.json @@ -32,7 +32,7 @@ "account.featured_tags.last_status_never": "ĐĐµĐ¼Đ°Ñ” Đ´Đ¾Đ¿Đ¸ÑÑ–Đ²", "account.featured_tags.title": "{name} Đ²Đ¸Đ´Ñ–Đ»ÑÑ” Ñ…ĐµÑˆÑ‚Đµ̉‘и", "account.follow": "ĐŸÑ–Đ´Đ¿Đ¸ÑĐ°Ñ‚Đ¸ÑÑ", - "account.follow_back": "ĐŸÑ–Đ´Đ¿Đ¸ÑĐ°Ñ‚Đ¸ÑÑ Đ²Đ·Đ°Ñ”Đ¼Đ½Đ¾", + "account.follow_back": "Đ¡Ñ‚ĐµĐ¶Đ¸Ñ‚Đ¸ Ñ‚Đ°ĐºĐ¾Đ¶", "account.followers": "ĐŸÑ–Đ´Đ¿Đ¸ÑĐ½Đ¸ĐºĐ¸", "account.followers.empty": "ĐÑ–Ñ…Ñ‚Đ¾ Ñ‰Đµ Đ½Đµ Đ¿Ñ–Đ´Đ¿Đ¸ÑĐ°Đ½Đ¸Đ¹ Đ½Đ° Ñ†ÑŒĐ¾Đ³Đ¾ ĐºĐ¾Ñ€Đ¸ÑÑ‚ÑƒĐ²Đ°Ñ‡Đ°.", "account.followers_counter": "{count, plural, one {{counter} Đ¿Ñ–Đ´Đ¿Đ¸ÑĐ½Đ¸Đº} few {{counter} Đ¿Ñ–Đ´Đ¿Đ¸ÑĐ½Đ¸ĐºĐ¸} many {{counter} Đ¿Ñ–Đ´Đ¿Đ¸ÑĐ½Đ¸ĐºÑ–Đ²} other {{counter} Đ¿Ñ–Đ´Đ¿Đ¸ÑĐ½Đ¸ĐºĐ¸}}", @@ -217,18 +217,18 @@ "domain_block_modal.title": "Đ—Đ°Đ±Đ»Đ¾ĐºÑƒĐ²Đ°Ñ‚Đ¸ Đ´Đ¾Đ¼ĐµĐ½?", "domain_block_modal.you_will_lose_followers": "Đ£ÑÑ–Ñ… Đ²Đ°ÑˆĐ¸Ñ… Đ¿Ñ–Đ´Đ¿Đ¸ÑĐ½Đ¸ĐºÑ–Đ² Đ· Ñ†ÑŒĐ¾Đ³Đ¾ ÑĐµÑ€Đ²ĐµÑ€Đ° Đ±ÑƒĐ´Đµ Đ²Đ¸Đ»ÑƒÑ‡ĐµĐ½Đ¾.", "domain_block_modal.you_wont_see_posts": "Ви Đ½Đµ Đ±Đ°Ñ‡Đ¸Ñ‚Đ¸Đ¼ĐµÑ‚Đµ Đ´Đ¾Đ¿Đ¸ÑÑ–Đ² Ñ– ÑĐ¿Đ¾Đ²Ñ–Ñ‰ĐµĐ½ÑŒ Đ²Ñ–Đ´ ĐºĐ¾Ñ€Đ¸ÑÑ‚ÑƒĐ²Đ°Ñ‡Ñ–Đ² Đ½Đ° Ñ†ÑŒĐ¾Đ¼Ñƒ ÑĐµÑ€Đ²ĐµÑ€Ñ–.", - "domain_pill.activitypub_lets_connect": "Це Đ´Đ¾Đ·Đ²Đ¾Đ»ÑÑ” Đ²Đ°Đ¼ ÑĐ¿Ñ–Đ»ĐºÑƒĐ²Đ°Ñ‚Đ¸ÑÑ Ñ‚Đ° Đ²Đ·Đ°Ñ”Đ¼Đ¾Đ´Ñ–ÑÑ‚Đ¸ Đ· Đ»ÑĐ´ÑŒĐ¼Đ¸ Đ½Đµ Đ»Đ¸ÑˆĐµ Đ½Đ° Mastodon, але Đ¹ у Ñ€Ñ–Đ·Đ½Đ¸Ñ… ÑĐ¾Ñ†Ñ–Đ°Đ»ÑŒĐ½Đ¸Ñ… Đ´Đ¾Đ´Đ°Ñ‚ĐºĐ°Ñ….", - "domain_pill.activitypub_like_language": "ActivityPub - Ñ†Đµ ÑĐº Đ¼Đ¾Đ²Đ°, ÑĐºĐ¾Ñ ĐœĐ°ÑÑ‚Đ¾Đ´Đ¾Đ½Ñ‚ Ñ€Đ¾Đ·Đ¼Đ¾Đ²Đ»ÑÑ” Đ· Ñ–Đ½ÑˆĐ¸Đ¼Đ¸ ÑĐ¾Ñ†Ñ–Đ°Đ»ÑŒĐ½Đ¸Đ¼Đ¸ Đ¼ĐµÑ€ĐµĐ¶Đ°Đ¼Đ¸.", + "domain_pill.activitypub_lets_connect": "Це Đ´Đ¾Đ·Đ²Đ¾Đ»ÑÑ” Đ²Đ°Đ¼ ÑĐ¿Ñ–Đ»ĐºÑƒĐ²Đ°Ñ‚Đ¸ÑÑ Ñ‚Đ° Đ²Đ·Đ°Ñ”Đ¼Đ¾Đ´Ñ–ÑÑ‚Đ¸ Đ· Đ»ÑĐ´ÑŒĐ¼Đ¸ Đ½Đµ Đ»Đ¸ÑˆĐµ Đ½Đ° Mastodon, але Đ¹ у Ñ€Ñ–Đ·Đ½Đ¸Ñ… ÑĐ¾Ñ†Ñ–Đ°Đ»ÑŒĐ½Đ¸Ñ… Đ·Đ°ÑÑ‚Đ¾ÑÑƒĐ½ĐºĐ°Ñ….", + "domain_pill.activitypub_like_language": "ActivityPub - Ñ†Đµ ÑĐº Đ¼Đ¾Đ²Đ°, ÑĐºĐ¾Ñ Mastodon Ñ€Đ¾Đ·Đ¼Đ¾Đ²Đ»ÑÑ” Đ· Ñ–Đ½ÑˆĐ¸Đ¼Đ¸ ÑĐ¾Ñ†Ñ–Đ°Đ»ÑŒĐ½Đ¸Đ¼Đ¸ Đ¼ĐµÑ€ĐµĐ¶Đ°Đ¼Đ¸.", "domain_pill.server": "Đ¡ĐµÑ€Đ²ĐµÑ€", "domain_pill.their_handle": "Đ‡Ñ…Đ½Ñ Đ°Đ´Ñ€ĐµÑĐ°:", - "domain_pill.their_server": "Đ‡Ñ…Đ½Ñ–Đ¹ Ñ†Đ¸Ñ„Ñ€Đ¾Đ²Đ¸Đ¹ Đ´Ñ–Đ¼, де Đ¶Đ¸Đ²ÑƒÑ‚ÑŒ уÑÑ– Ñ—Ñ…Đ½Ñ– Đ¿Đ¾ÑÑ‚Đ¸.", + "domain_pill.their_server": "Đ‡Ñ…Đ½Ñ–Đ¹ Ñ†Đ¸Ñ„Ñ€Đ¾Đ²Đ¸Đ¹ Đ´Ñ–Đ¼, де Đ¶Đ¸Đ²ÑƒÑ‚ÑŒ уÑÑ– Ñ—Ñ…Đ½Ñ– Đ´Đ¾Đ¿Đ¸Ñи.", "domain_pill.their_username": "Đ‡Ñ…Đ½Ñ–Đ¹ ÑƒĐ½Ñ–ĐºĐ°Đ»ÑŒĐ½Đ¸Đ¹ Ñ–Đ´ĐµĐ½Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚Đ¾Ñ€ Đ½Đ° Ñ—Ñ…Đ½ÑŒĐ¾Đ¼Ñƒ ÑĐµÑ€Đ²ĐµÑ€Ñ–. Ви Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ·Đ½Đ°Đ¹Ñ‚Đ¸ ĐºĐ¾Ñ€Đ¸ÑÑ‚ÑƒĐ²Đ°Ñ‡Ñ–Đ² Đ· Đ¾Đ´Đ½Đ°ĐºĐ¾Đ²Đ¸Đ¼Đ¸ Ñ–Đ¼ĐµĐ½Đ°Đ¼Đ¸ Đ½Đ° Ñ€Ñ–Đ·Đ½Đ¸Ñ… ÑĐµÑ€Đ²ĐµÑ€Đ°Ñ….", "domain_pill.username": "Đ†Đ¼'Ñ ĐºĐ¾Ñ€Đ¸ÑÑ‚ÑƒĐ²Đ°Ñ‡Đ°", "domain_pill.whats_in_a_handle": "Đ©Đ¾ Ñ” Đ² Đ°Đ´Ñ€ĐµÑÑ–?", "domain_pill.who_they_are": "ĐÑĐºÑ–Đ»ÑŒĐºĐ¸ деÑĐºÑ€Đ¸Đ¿Ñ‚Đ¾Ñ€Đ¸ Đ²ĐºĐ°Đ·ÑƒÑÑ‚ÑŒ, Ñ…Ñ‚Đ¾ Ñ†Đµ Ñ– де Đ²Ñ–Đ½ Đ·Đ½Đ°Ñ…Đ¾Đ´Đ¸Ñ‚ÑŒÑÑ, Đ²Đ¸ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ²Đ·Đ°Ñ”Đ¼Đ¾Đ´Ñ–ÑÑ‚Đ¸ Đ· Đ»ÑĐ´ÑŒĐ¼Đ¸ Ñ‡ĐµÑ€ĐµĐ· ÑĐ¾Ñ†Ñ–Đ°Đ»ÑŒĐ½Ñƒ Đ¼ĐµÑ€ĐµĐ¶Ñƒ Đ¿Đ»Đ°Ñ‚Ñ„Đ¾Ñ€Đ¼ Đ½Đ° Đ¾ÑĐ½Đ¾Đ²Ñ– .", "domain_pill.who_you_are": "ĐÑĐºÑ–Đ»ÑŒĐºĐ¸ Đ²Đ°Ñˆ Đ½Ñ–ĐºĐ½ĐµĐ¹Đ¼ Đ²ĐºĐ°Đ·ÑƒÑ”, Ñ…Ñ‚Đ¾ Đ²Đ¸ Ñ‚Đ° де Đ²Đ¸, Đ»Ñди Đ¼Đ¾Đ¶ÑƒÑ‚ÑŒ Đ²Đ·Đ°Ñ”Đ¼Đ¾Đ´Ñ–ÑÑ‚Đ¸ Đ· Đ²Đ°Đ¼Đ¸ Ñ‡ĐµÑ€ĐµĐ· ÑĐ¾Ñ†Ñ–Đ°Đ»ÑŒĐ½Ñƒ Đ¼ĐµÑ€ĐµĐ¶Ñƒ Đ¿Đ»Đ°Ñ‚Ñ„Đ¾Ñ€Đ¼ Đ½Đ° Đ¾ÑĐ½Đ¾Đ²Ñ– .", "domain_pill.your_handle": "Đ’Đ°ÑˆĐ° Đ°Đ´Ñ€ĐµÑĐ°:", - "domain_pill.your_server": "Đ’Đ°Ñˆ Ñ†Đ¸Ñ„Ñ€Đ¾Đ²Đ¸Đ¹ Đ´Ñ–Đ¼, де Đ¶Đ¸Đ²ÑƒÑ‚ÑŒ уÑÑ– Đ²Đ°ÑˆÑ– Đ¿ÑƒĐ±Đ»Ñ–ĐºĐ°Ñ†Ñ–Ñ—. Đе Đ¿Đ¾Đ´Đ¾Đ±Đ°Ñ”Ñ‚ÑŒÑÑ Ñ†ĐµĐ¹? ĐŸĐµÑ€ĐµĐ½ĐµÑÑ–Ñ‚ÑŒ ÑĐµÑ€Đ²ĐµÑ€Đ¸ Đ² Đ±ÑƒĐ´ÑŒ-ÑĐºĐ¸Đ¹ Ñ‡Đ°Ñ Ñ– Đ·Đ°Đ»ÑƒÑ‡Đ°Đ¹Ñ‚Đµ ÑĐ²Đ¾Ñ—Ñ… Đ¿Ñ–Đ´Đ¿Đ¸ÑĐ½Đ¸ĐºÑ–Đ².", + "domain_pill.your_server": "Đ’Đ°Ñˆ Ñ†Đ¸Ñ„Ñ€Đ¾Đ²Đ¸Đ¹ Đ´Ñ–Đ¼, де Đ¶Đ¸Đ²ÑƒÑ‚ÑŒ уÑÑ– Đ²Đ°ÑˆÑ– Đ´Đ¾Đ¿Đ¸Ñи. Đе Đ¿Đ¾Đ´Đ¾Đ±Đ°Ñ”Ñ‚ÑŒÑÑ Ñ†ĐµĐ¹? ĐŸĐµÑ€ĐµĐ½ĐµÑÑ–Ñ‚ÑŒ ÑĐµÑ€Đ²ĐµÑ€Đ¸ Đ² Đ±ÑƒĐ´ÑŒ-ÑĐºĐ¸Đ¹ Ñ‡Đ°Ñ Ñ– Đ·Đ°Đ»ÑƒÑ‡Đ°Đ¹Ñ‚Đµ ÑĐ²Đ¾Ñ—Ñ… Đ¿Ñ–Đ´Đ¿Đ¸ÑĐ½Đ¸ĐºÑ–Đ².", "domain_pill.your_username": "Đ’Đ°Ñˆ ÑƒĐ½Ñ–ĐºĐ°Đ»ÑŒĐ½Đ¸Đ¹ Ñ–Đ´ĐµĐ½Ñ‚Đ¸Ñ„Ñ–ĐºĐ°Ñ‚Đ¾Ñ€ Đ½Đ° Ñ†ÑŒĐ¾Đ¼Ñƒ ÑĐµÑ€Đ²ĐµÑ€Ñ–. Ви Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ·Đ½Đ°Đ¹Ñ‚Đ¸ ĐºĐ¾Ñ€Đ¸ÑÑ‚ÑƒĐ²Đ°Ñ‡Ñ–Đ² Đ· Đ¾Đ´Đ½Đ°ĐºĐ¾Đ²Đ¸Đ¼Đ¸ Ñ–Đ¼ĐµĐ½Đ°Đ¼Đ¸ Đ½Đ° Ñ€Ñ–Đ·Đ½Đ¸Ñ… ÑĐµÑ€Đ²ĐµÑ€Đ°Ñ….", "embed.instructions": "Đ’Đ±ÑƒĐ´ÑƒĐ¹Ñ‚Đµ Ñ†ĐµĐ¹ Đ´Đ¾Đ¿Đ¸Ñ Đ´Đ¾ Đ²Đ°ÑˆĐ¾Đ³Đ¾ Đ²ĐµĐ±ÑĐ°Đ¹Ñ‚Ñƒ, ÑĐºĐ¾Đ¿Ñ–ÑĐ²Đ°Đ²ÑˆĐ¸ ĐºĐ¾Đ´ Đ½Đ¸Đ¶Ñ‡Đµ.", "embed.preview": "ĐÑÑŒ ÑĐºĐ¸Đ¹ Đ²Đ¸Đ³Đ»ÑĐ´ Ñ†Đµ Đ¼Đ°Ñ‚Đ¸Đ¼Đµ:", @@ -489,9 +489,9 @@ "notification.reblog": "{name} Đ¿Đ¾ÑˆĐ¸Ñ€ÑÑ” Đ²Đ°Ñˆ Đ´Đ¾Đ¿Đ¸Ñ", "notification.relationships_severance_event": "Đ’Ñ‚Ñ€Đ°Ñ‡ĐµĐ½Đ¾ Đ·'Ñ”Đ´Đ½Đ°Đ½Đ½Ñ Đ· {name}", "notification.relationships_severance_event.account_suspension": "ĐĐ´Đ¼Ñ–Đ½Ñ–ÑÑ‚Ñ€Đ°Ñ‚Đ¾Ñ€ Đ· {from} Đ¿Ñ€Đ¸Đ·ÑƒĐ¿Đ¸Đ½Đ¸Đ² {target}, Ñ‰Đ¾ Đ¾Đ·Đ½Đ°Ñ‡Đ°Ñ”, Ñ‰Đ¾ Đ²Đ¸ Đ±Ñ–Đ»ÑŒÑˆĐµ Đ½Đµ Đ¼Đ¾Đ¶ĐµÑ‚Đµ Đ¾Ñ‚Ñ€Đ¸Đ¼ÑƒĐ²Đ°Ñ‚Đ¸ Đ¾Đ½Đ¾Đ²Đ»ĐµĐ½Đ½Ñ Đ²Ñ–Đ´ Đ½Đ¸Ñ… Đ°Đ±Đ¾ Đ²Đ·Đ°Ñ”Đ¼Đ¾Đ´Ñ–ÑÑ‚Đ¸ Đ· Đ½Đ¸Đ¼Đ¸.", - "notification.relationships_severance_event.domain_block": "ĐĐ´Đ¼Ñ–Đ½Ñ–ÑÑ‚Ñ€Đ°Ñ‚Đ¾Ñ€ Đ· {from} Đ·Đ°Đ±Đ»Đ¾ĐºÑƒĐ²Đ°Đ² {target}, Đ²ĐºĐ»ÑÑ‡Đ°ÑÑ‡Đ¸ {followersCount} Đ²Đ°ÑˆĐ¸Ñ… Đ¿Ñ–Đ´Đ¿Đ¸ÑĐ½Đ¸ĐºÑ–Đ² Ñ– {{followingCount, plural, one {# account} other {# accounts}}, Đ½Đ° ÑĐºÑ– Đ²Đ¸ Đ¿Ñ–Đ´Đ¿Đ¸ÑĐ°Đ½Ñ–.", - "notification.relationships_severance_event.learn_more": "Đ”Ñ–Đ·Đ½Đ°Ñ‚Đ¸ÑÑ Đ±Ñ–Đ»ÑŒÑˆĐµ", - "notification.relationships_severance_event.user_domain_block": "Ви Đ·Đ°Đ±Đ»Đ¾ĐºÑƒĐ²Đ°Đ»Đ¸ {target}, Đ²Đ¸Đ´Đ°Đ»Đ¸Đ²ÑˆĐ¸ {followersCount} Đ²Đ°ÑˆĐ¸Ñ… Đ¿Ñ–Đ´Đ¿Đ¸ÑĐ½Đ¸ĐºÑ–Đ² Ñ– {followingCount, plural, one {# account} other {# accounts}}, Đ·Đ° ÑĐºĐ¸Đ¼Đ¸ Đ²Đ¸ ÑÑ‚ĐµĐ¶Đ¸Ñ‚Đµ.", + "notification.relationships_severance_event.domain_block": "ĐĐ´Đ¼Ñ–Đ½Ñ–ÑÑ‚Ñ€Đ°Ñ‚Đ¾Ñ€ Đ· {from} Đ·Đ°Đ±Đ»Đ¾ĐºÑƒĐ²Đ°Đ² {target}, Đ²ĐºĐ»ÑÑ‡Đ°ÑÑ‡Đ¸ {followersCount} Đ²Đ°ÑˆĐ¸Ñ… Đ¿Ñ–Đ´Đ¿Đ¸ÑĐ½Đ¸ĐºÑ–Đ² Ñ– {followingCount , plural, one {# Đ¾Đ±Đ»Ñ–ĐºĐ¾Đ²Đ¸Đ¹ Đ·Đ°Đ¿Đ¸Ñ} few {# Đ¾Đ±Đ»Ñ–ĐºĐ¾Đ²Ñ– Đ·Đ°Đ¿Đ¸Ñи} many {# Đ¾Đ±Đ»Ñ–ĐºĐ¾Đ²Đ¸Ñ… Đ·Đ°Đ¿Đ¸ÑÑ–Đ²} other {# Đ¾Đ±Đ»Ñ–ĐºĐ¾Đ²Đ¸Đ¹ Đ·Đ°Đ¿Đ¸Ñ}}, Đ½Đ° ÑĐºÑ– Đ²Đ¸ Đ¿Ñ–Đ´Đ¿Đ¸ÑĐ°Đ½Ñ–.", + "notification.relationships_severance_event.learn_more": "Đ”Đ¾ĐºĐ»Đ°Đ´Đ½Ñ–ÑˆĐµ", + "notification.relationships_severance_event.user_domain_block": "Ви Đ·Đ°Đ±Đ»Đ¾ĐºÑƒĐ²Đ°Đ»Đ¸ {target}, Đ²Đ¸Đ´Đ°Đ»Đ¸Đ²ÑˆĐ¸ {followersCount} Đ²Đ°ÑˆĐ¸Ñ… Đ¿Ñ–Đ´Đ¿Đ¸ÑĐ½Đ¸ĐºÑ–Đ² Ñ– {followingCount, plural, one {# Đ¾Đ±Đ»Ñ–ĐºĐ¾Đ²Đ¸Đ¹ Đ·Đ°Đ¿Đ¸Ñ} few {# Đ¾Đ±Đ»Ñ–ĐºĐ¾Đ²Ñ– Đ·Đ°Đ¿Đ¸Ñи} many {# Đ¾Đ±Đ»Ñ–ĐºĐ¾Đ²Đ¸Ñ… Đ·Đ°Đ¿Đ¸ÑÑ–Đ²} other {# Đ¾Đ±Đ»Ñ–ĐºĐ¾Đ²Đ¸Đ¹ Đ·Đ°Đ¿Đ¸Ñ}}, Đ·Đ° ÑĐºĐ¸Đ¼Đ¸ Đ²Đ¸ ÑÑ‚ĐµĐ¶Đ¸Ñ‚Đµ.", "notification.status": "{name} Ñ‰Đ¾Đ¹Đ½Đ¾ Đ´Đ¾Đ¿Đ¸Ñує", "notification.update": "{name} Đ·Đ¼Ñ–Đ½ÑÑ” Đ´Đ¾Đ¿Đ¸Ñ", "notification_requests.accept": "ĐŸÑ€Đ¸Đ¹Đ½ÑÑ‚Đ¸", diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index 04469a971d5cbf..b9a5fc071468ca 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -113,7 +113,7 @@ "closed_registrations.other_server_instructions": "因為 Mastodon 是å»ä¸­å¿ƒåŒ–ç„,所以您也能於其他伺æœå™¨ä¸å»ºç«‹å¸³è™Ÿï¼Œä¸¦ä»ç„¶èˆ‡é€™å€‹ä¼ºæœå™¨äº’å‹•ă€‚", "closed_registrations_modal.description": "ç›®å‰ç„¡æ³•æ–¼ {domain} 建立新帳號,但也請別忘了,您並ä¸ä¸€å®éœ€è¦æœ‰ {domain} 伺æœå™¨ç„帳號,也能使用 Mastodon。", "closed_registrations_modal.find_another_server": "尋找å¦ä¸€å€‹ä¼ºæœå™¨", - "closed_registrations_modal.preamble": "Mastodon 是å»ä¸­å¿ƒåŒ–ç„,所以無論您於哪個伺æœå™¨æ–°å¢å¸³è™Ÿï¼Œéƒ½å¯ä»¥èˆ‡æ­¤ä¼ºæœå™¨ä¸ç„任何人跟é¨åäº’å‹•ă€‚æ‚¨ç”至能自行æ¶è¨­ä¸€å€‹è‡ªå·±ç„伺æœå™¨ï¼", + "closed_registrations_modal.preamble": "Mastodon 是å»ä¸­å¿ƒåŒ–ç„,所以無論您於哪個伺æœå™¨æ–°å¢å¸³è™Ÿï¼Œéƒ½å¯ä»¥èˆ‡æ­¤ä¼ºæœå™¨ä¸ç„任何人跟é¨åäº’å‹•ă€‚æ‚¨ç”至能自行æ¶è¨­è‡ªå·±ç„伺æœå™¨ï¼", "closed_registrations_modal.title": "è¨»å† Mastodon", "column.about": "關於", "column.blocks": "å·²å°é–ç„使用者", @@ -271,7 +271,7 @@ "empty_column.public": "這裡什麼都沒有ï¼å˜—試寫些公開ç„嘟文,或者跟é¨å…¶ä»–伺æœå™¨ç„使用者後,就會有嘟文出ç¾äº†", "error.unexpected_crash.explanation": "由於發生系統故éœæˆ–ç€è¦½å™¨ç›¸å®¹æ€§å•é¡Œï¼Œç„¡æ³•æ­£å¸¸é¡¯ç¤ºæ­¤é é¢ă€‚", "error.unexpected_crash.explanation_addons": "æ­¤é é¢ç„¡æ³•è¢«æ­£å¸¸é¡¯ç¤ºï¼Œé€™å¯èƒ½æ˜¯ç”±ç€è¦½å™¨é™„å å…ƒä»¶æˆ–網é è‡ªå‹•ç¿»è­¯å·¥å…·é€ æˆç„。", - "error.unexpected_crash.next_steps": "請嘗試é‡æ–°æ•´ç†é é¢ă€‚如æœç‹€æ³æ²’有改善,您å¯ä»¥ä½¿ç”¨ä¸åŒç„ç€è¦½å™¨æˆ–應用程å¼ä¾†æª¢è¦–來使用 Mastodon。", + "error.unexpected_crash.next_steps": "請嘗試é‡æ–°æ•´ç†é é¢ă€‚如æœç‹€æ³æ²’有改善,您å¯ä»¥ä½¿ç”¨ä¸åŒç„ç€è¦½å™¨æˆ–應用程å¼ä»¥æª¢è¦–來使用 Mastodon。", "error.unexpected_crash.next_steps_addons": "請嘗試關閉它們然後é‡æ–°æ•´ç†é é¢ă€‚如æœç‹€æ³æ²’有改善,您å¯ä»¥ä½¿ç”¨ä¸åŒç„ç€è¦½å™¨æˆ–應用程å¼ä¾†æª¢è¦–來使用 Mastodon。", "errors.unexpected_crash.copy_stacktrace": "複製 stacktrace 到剪貼簿", "errors.unexpected_crash.report_issue": "å›å ±å•é¡Œ", @@ -356,7 +356,7 @@ "home.show_announcements": "顯示公å‘", "interaction_modal.description.favourite": "若於 Mastodon ä¸æœ‰å€‹å¸³è™Ÿï¼Œæ‚¨å¯ä»¥å°‡æ­¤å˜Ÿæ–‡å å…¥æœ€æ„›ä½¿ä½œè€…知é“您欣è³å®ƒä¸”å°‡å®ƒå„²å­˜ä¸‹ä¾†ă€‚", "interaction_modal.description.follow": "若於 Mastodon ä¸æœ‰å€‹å¸³è™Ÿï¼Œæ‚¨å¯ä»¥è·Ÿé¨ {name} 以於首é æ™‚間軸æ¥æ”¶ä»–們ç„å˜Ÿæ–‡ă€‚", - "interaction_modal.description.reblog": "若於 Mastodon ä¸æœ‰å€‹å¸³è™Ÿï¼Œæ‚¨å¯ä»¥è½‰å˜Ÿæ­¤å˜Ÿæ–‡ä»¥åˆ†äº«çµ¦æ‚¨ç„è·Ÿé¨è€…å€‘ă€‚", + "interaction_modal.description.reblog": "若於 Mastodon ä¸æœ‰å€‹å¸³è™Ÿï¼Œæ‚¨å¯ä»¥è½‰å˜Ÿæ­¤å˜Ÿæ–‡ä»¥å‘您ç„è·Ÿé¨è€…å€‘åˆ†äº«ă€‚", "interaction_modal.description.reply": "若於 Mastodon ä¸æœ‰å€‹å¸³è™Ÿï¼Œæ‚¨å¯ä»¥å›è¦†æ­¤å˜Ÿæ–‡ă€‚", "interaction_modal.login.action": "è¿”å›é¦–é ", "interaction_modal.login.prompt": "您帳號所屬伺æœå™¨ä¹‹ç¶²åŸŸï¼Œä¾‹å¦‚ï¼mastodon.social", @@ -552,7 +552,7 @@ "onboarding.follows.lead": "您ç„首é æ™‚間軸是 Mastodon ç„æ ¸å¿ƒé«”é©—ă€‚è‹¥æ‚¨è·Ÿé¨æ›´å¤äººï¼Œå®ƒå°‡æœƒè®å¾—æ›´æ´»èºæœ‰è¶£ă€‚這些個人檔案也許是個好起é»ï¼Œæ‚¨å¯ä»¥é¨æ™‚å–消跟é¨ä»–們ï¼", "onboarding.follows.title": "客製化您ç„首é æ™‚間軸", "onboarding.profile.discoverable": "使我ç„個人檔案å¯ä»¥è¢«æ‰¾åˆ°", - "onboarding.profile.discoverable_hint": "當您於 Mastodon ä¸é¸æ“‡å å…¥å¯ç™¼ç¾æ€§æ™‚,您ç„嘟文å¯èƒ½æœƒé¡¯ç¤ºæ–¼æœå°‹çµæœèˆ‡è¶¨å‹¢ä¸­ă€‚您ç„個人檔案å¯èƒ½æœƒè¢«æ¨è–¦çµ¦èˆ‡æ‚¨å¿—趣相æ•ç„äººă€‚", + "onboarding.profile.discoverable_hint": "當您於 Mastodon ä¸é¸æ“‡å å…¥å¯ç™¼ç¾æ€§æ™‚,您ç„嘟文å¯èƒ½æœƒé¡¯ç¤ºæ–¼æœå°‹çµæœèˆ‡è¶¨å‹¢ä¸­ă€‚您ç„個人檔案å¯èƒ½æœƒè¢«æ¨è–¦è‡³èˆ‡æ‚¨å¿—趣相æ•ç„äººă€‚", "onboarding.profile.display_name": "顯示å稱", "onboarding.profile.display_name_hint": "完整å稱或æ±ç¨±...", "onboarding.profile.lead": "您é¨æ™‚å¯ä»¥ç¨å€™æ–¼è¨­å®ä¸­å®Œæˆæ­¤æ“作,將有更å¤è‡ªè¨‚é¸é …å¯ä½¿ç”¨ă€‚", @@ -797,7 +797,7 @@ "upload_modal.applying": "正在套用...", "upload_modal.choose_image": "é¸æ“‡åœ–片", "upload_modal.description_placeholder": "我能å下ç»ç’ƒè€Œä¸å‚·èº«é«”", - "upload_modal.detect_text": "å¾åœ–片中åµæ¸¬æ–‡å­—", + "upload_modal.detect_text": "自圖片中åµæ¸¬æ–‡å­—", "upload_modal.edit_media": "編輯媒體", "upload_modal.hint": "æ–¼é è¦½ä¸­é»æ“或拖曳圓圈以é¸æ“‡å°‡æ–¼æ‰€æœ‰ç¸®åœ–中顯示ç„焦é»ă€‚", "upload_modal.preparing_ocr": "準備 OCR 中……", diff --git a/app/javascript/mastodon/models/notification_group.ts b/app/javascript/mastodon/models/notification_group.ts new file mode 100644 index 00000000000000..5fe1e6f2e43dee --- /dev/null +++ b/app/javascript/mastodon/models/notification_group.ts @@ -0,0 +1,207 @@ +import type { + ApiAccountRelationshipSeveranceEventJSON, + ApiAccountWarningJSON, + BaseNotificationGroupJSON, + ApiNotificationGroupJSON, + ApiNotificationJSON, + NotificationType, + NotificationWithStatusType, +} from 'mastodon/api_types/notifications'; +import type { ApiReportJSON } from 'mastodon/api_types/reports'; + +// Maximum number of avatars displayed in a notification group +// This corresponds to the max lenght of `group.sampleAccountIds` +export const NOTIFICATIONS_GROUP_MAX_AVATARS = 8; + +interface BaseNotificationGroup + extends Omit { + sampleAccountIds: string[]; +} + +interface BaseNotificationWithStatus + extends BaseNotificationGroup { + type: Type; + statusId: string; +} + +interface BaseNotification + extends BaseNotificationGroup { + type: Type; +} + +export type NotificationGroupFavourite = + BaseNotificationWithStatus<'favourite'>; +export type NotificationGroupReblog = BaseNotificationWithStatus<'reblog'>; +export type NotificationGroupStatus = BaseNotificationWithStatus<'status'>; +export type NotificationGroupMention = BaseNotificationWithStatus<'mention'>; +export type NotificationGroupPoll = BaseNotificationWithStatus<'poll'>; +export type NotificationGroupUpdate = BaseNotificationWithStatus<'update'>; +export type NotificationGroupFollow = BaseNotification<'follow'>; +export type NotificationGroupFollowRequest = BaseNotification<'follow_request'>; +export type NotificationGroupAdminSignUp = BaseNotification<'admin.sign_up'>; + +export type AccountWarningAction = + | 'none' + | 'disable' + | 'mark_statuses_as_sensitive' + | 'delete_statuses' + | 'sensitive' + | 'silence' + | 'suspend'; +export interface AccountWarning + extends Omit { + targetAccountId: string; +} + +export interface NotificationGroupModerationWarning + extends BaseNotification<'moderation_warning'> { + moderationWarning: AccountWarning; +} + +type AccountRelationshipSeveranceEvent = + ApiAccountRelationshipSeveranceEventJSON; +export interface NotificationGroupSeveredRelationships + extends BaseNotification<'severed_relationships'> { + event: AccountRelationshipSeveranceEvent; +} + +interface Report extends Omit { + targetAccountId: string; +} + +export interface NotificationGroupAdminReport + extends BaseNotification<'admin.report'> { + report: Report; +} + +export type NotificationGroup = + | NotificationGroupFavourite + | NotificationGroupReblog + | NotificationGroupStatus + | NotificationGroupMention + | NotificationGroupPoll + | NotificationGroupUpdate + | NotificationGroupFollow + | NotificationGroupFollowRequest + | NotificationGroupModerationWarning + | NotificationGroupSeveredRelationships + | NotificationGroupAdminSignUp + | NotificationGroupAdminReport; + +function createReportFromJSON(reportJSON: ApiReportJSON): Report { + const { target_account, ...report } = reportJSON; + return { + targetAccountId: target_account.id, + ...report, + }; +} + +function createAccountWarningFromJSON( + warningJSON: ApiAccountWarningJSON, +): AccountWarning { + const { target_account, ...warning } = warningJSON; + return { + targetAccountId: target_account.id, + ...warning, + }; +} + +function createAccountRelationshipSeveranceEventFromJSON( + eventJson: ApiAccountRelationshipSeveranceEventJSON, +): AccountRelationshipSeveranceEvent { + return eventJson; +} + +export function createNotificationGroupFromJSON( + groupJson: ApiNotificationGroupJSON, +): NotificationGroup { + const { sample_accounts, ...group } = groupJson; + const sampleAccountIds = sample_accounts.map((account) => account.id); + + switch (group.type) { + case 'favourite': + case 'reblog': + case 'status': + case 'mention': + case 'poll': + case 'update': { + const { status, ...groupWithoutStatus } = group; + return { + statusId: status.id, + sampleAccountIds, + ...groupWithoutStatus, + }; + } + case 'admin.report': { + const { report, ...groupWithoutTargetAccount } = group; + return { + report: createReportFromJSON(report), + sampleAccountIds, + ...groupWithoutTargetAccount, + }; + } + case 'severed_relationships': + return { + ...group, + event: createAccountRelationshipSeveranceEventFromJSON(group.event), + sampleAccountIds, + }; + + case 'moderation_warning': { + const { moderation_warning, ...groupWithoutModerationWarning } = group; + return { + ...groupWithoutModerationWarning, + moderationWarning: createAccountWarningFromJSON(moderation_warning), + sampleAccountIds, + }; + } + default: + return { + sampleAccountIds, + ...group, + }; + } +} + +export function createNotificationGroupFromNotificationJSON( + notification: ApiNotificationJSON, +) { + const group = { + sampleAccountIds: [notification.account.id], + group_key: notification.group_key, + notifications_count: 1, + type: notification.type, + most_recent_notification_id: notification.id, + page_min_id: notification.id, + page_max_id: notification.id, + latest_page_notification_at: notification.created_at, + } as NotificationGroup; + + switch (notification.type) { + case 'favourite': + case 'reblog': + case 'status': + case 'mention': + case 'poll': + case 'update': + return { ...group, statusId: notification.status.id }; + case 'admin.report': + return { ...group, report: createReportFromJSON(notification.report) }; + case 'severed_relationships': + return { + ...group, + event: createAccountRelationshipSeveranceEventFromJSON( + notification.event, + ), + }; + case 'moderation_warning': + return { + ...group, + moderationWarning: createAccountWarningFromJSON( + notification.moderation_warning, + ), + }; + default: + return group; + } +} diff --git a/app/javascript/mastodon/reducers/index.ts b/app/javascript/mastodon/reducers/index.ts index 6296ef202690a0..b92de0dbcda766 100644 --- a/app/javascript/mastodon/reducers/index.ts +++ b/app/javascript/mastodon/reducers/index.ts @@ -24,6 +24,7 @@ import { markersReducer } from './markers'; import media_attachments from './media_attachments'; import meta from './meta'; import { modalReducer } from './modal'; +import { notificationGroupsReducer } from './notification_groups'; import { notificationPolicyReducer } from './notification_policy'; import { notificationRequestsReducer } from './notification_requests'; import notifications from './notifications'; @@ -65,6 +66,7 @@ const reducers = { search, media_attachments, notifications, + notificationGroups: notificationGroupsReducer, height_cache, custom_emojis, lists, diff --git a/app/javascript/mastodon/reducers/markers.ts b/app/javascript/mastodon/reducers/markers.ts index ec85d0f17328cb..b1f10b5fa23a92 100644 --- a/app/javascript/mastodon/reducers/markers.ts +++ b/app/javascript/mastodon/reducers/markers.ts @@ -1,6 +1,7 @@ import { createReducer } from '@reduxjs/toolkit'; -import { submitMarkersAction } from 'mastodon/actions/markers'; +import { submitMarkersAction, fetchMarkers } from 'mastodon/actions/markers'; +import { compareId } from 'mastodon/compare_id'; const initialState = { home: '0', @@ -15,4 +16,23 @@ export const markersReducer = createReducer(initialState, (builder) => { if (notifications) state.notifications = notifications; }, ); + builder.addCase( + fetchMarkers.fulfilled, + ( + state, + { + payload: { + markers: { home, notifications }, + }, + }, + ) => { + if (home && compareId(home.last_read_id, state.home) > 0) + state.home = home.last_read_id; + if ( + notifications && + compareId(notifications.last_read_id, state.notifications) > 0 + ) + state.notifications = notifications.last_read_id; + }, + ); }); diff --git a/app/javascript/mastodon/reducers/notification_groups.ts b/app/javascript/mastodon/reducers/notification_groups.ts new file mode 100644 index 00000000000000..e59f3e7ca11b57 --- /dev/null +++ b/app/javascript/mastodon/reducers/notification_groups.ts @@ -0,0 +1,508 @@ +import { createReducer, isAnyOf } from '@reduxjs/toolkit'; + +import { + authorizeFollowRequestSuccess, + blockAccountSuccess, + muteAccountSuccess, + rejectFollowRequestSuccess, +} from 'mastodon/actions/accounts_typed'; +import { focusApp, unfocusApp } from 'mastodon/actions/app'; +import { blockDomainSuccess } from 'mastodon/actions/domain_blocks_typed'; +import { fetchMarkers } from 'mastodon/actions/markers'; +import { + clearNotifications, + fetchNotifications, + fetchNotificationsGap, + processNewNotificationForGroups, + loadPending, + updateScrollPosition, + markNotificationsAsRead, + mountNotifications, + unmountNotifications, +} from 'mastodon/actions/notification_groups'; +import { + disconnectTimeline, + timelineDelete, +} from 'mastodon/actions/timelines_typed'; +import type { ApiNotificationJSON } from 'mastodon/api_types/notifications'; +import { compareId } from 'mastodon/compare_id'; +import { usePendingItems } from 'mastodon/initial_state'; +import { + NOTIFICATIONS_GROUP_MAX_AVATARS, + createNotificationGroupFromJSON, + createNotificationGroupFromNotificationJSON, +} from 'mastodon/models/notification_group'; +import type { NotificationGroup } from 'mastodon/models/notification_group'; + +const NOTIFICATIONS_TRIM_LIMIT = 50; + +export interface NotificationGap { + type: 'gap'; + maxId?: string; + sinceId?: string; +} + +interface NotificationGroupsState { + groups: (NotificationGroup | NotificationGap)[]; + pendingGroups: (NotificationGroup | NotificationGap)[]; + scrolledToTop: boolean; + isLoading: boolean; + lastReadId: string; + mounted: number; + isTabVisible: boolean; +} + +const initialState: NotificationGroupsState = { + groups: [], + pendingGroups: [], // holds pending groups in slow mode + scrolledToTop: false, + isLoading: false, + // The following properties are used to track unread notifications + lastReadId: '0', // used for unread notifications + mounted: 0, // number of mounted notification list components, usually 0 or 1 + isTabVisible: true, +}; + +function filterNotificationsForAccounts( + groups: NotificationGroupsState['groups'], + accountIds: string[], + onlyForType?: string, +) { + groups = groups + .map((group) => { + if ( + group.type !== 'gap' && + (!onlyForType || group.type === onlyForType) + ) { + const previousLength = group.sampleAccountIds.length; + + group.sampleAccountIds = group.sampleAccountIds.filter( + (id) => !accountIds.includes(id), + ); + + const newLength = group.sampleAccountIds.length; + const removed = previousLength - newLength; + + group.notifications_count -= removed; + } + + return group; + }) + .filter( + (group) => group.type === 'gap' || group.sampleAccountIds.length > 0, + ); + mergeGaps(groups); + return groups; +} + +function filterNotificationsForStatus( + groups: NotificationGroupsState['groups'], + statusId: string, +) { + groups = groups.filter( + (group) => + group.type === 'gap' || + !('statusId' in group) || + group.statusId !== statusId, + ); + mergeGaps(groups); + return groups; +} + +function removeNotificationsForAccounts( + state: NotificationGroupsState, + accountIds: string[], + onlyForType?: string, +) { + state.groups = filterNotificationsForAccounts( + state.groups, + accountIds, + onlyForType, + ); + state.pendingGroups = filterNotificationsForAccounts( + state.pendingGroups, + accountIds, + onlyForType, + ); +} + +function removeNotificationsForStatus( + state: NotificationGroupsState, + statusId: string, +) { + state.groups = filterNotificationsForStatus(state.groups, statusId); + state.pendingGroups = filterNotificationsForStatus( + state.pendingGroups, + statusId, + ); +} + +function isNotificationGroup( + groupOrGap: NotificationGroup | NotificationGap, +): groupOrGap is NotificationGroup { + return groupOrGap.type !== 'gap'; +} + +// Merge adjacent gaps in `groups` in-place +function mergeGaps(groups: NotificationGroupsState['groups']) { + for (let i = 0; i < groups.length; i++) { + const firstGroupOrGap = groups[i]; + + if (firstGroupOrGap?.type === 'gap') { + let lastGap = firstGroupOrGap; + let j = i + 1; + + for (; j < groups.length; j++) { + const groupOrGap = groups[j]; + if (groupOrGap?.type === 'gap') lastGap = groupOrGap; + else break; + } + + if (j - i > 1) { + groups.splice(i, j - i, { + type: 'gap', + maxId: firstGroupOrGap.maxId, + sinceId: lastGap.sinceId, + }); + } + } + } +} + +// Checks if `groups[index-1]` and `groups[index]` are gaps, and merge them in-place if they are +function mergeGapsAround( + groups: NotificationGroupsState['groups'], + index: number, +) { + if (index > 0) { + const potentialFirstGap = groups[index - 1]; + const potentialSecondGap = groups[index]; + + if ( + potentialFirstGap?.type === 'gap' && + potentialSecondGap?.type === 'gap' + ) { + groups.splice(index - 1, 2, { + type: 'gap', + maxId: potentialFirstGap.maxId, + sinceId: potentialSecondGap.sinceId, + }); + } + } +} + +function processNewNotification( + groups: NotificationGroupsState['groups'], + notification: ApiNotificationJSON, +) { + const existingGroupIndex = groups.findIndex( + (group) => + group.type !== 'gap' && group.group_key === notification.group_key, + ); + + // In any case, we are going to add a group at the top + // If there is currently a gap at the top, now is the time to update it + if (groups.length > 0 && groups[0]?.type === 'gap') { + groups[0].maxId = notification.id; + } + + if (existingGroupIndex > -1) { + const existingGroup = groups[existingGroupIndex]; + + if ( + existingGroup && + existingGroup.type !== 'gap' && + !existingGroup.sampleAccountIds.includes(notification.account.id) // This can happen for example if you like, then unlike, then like again the same post + ) { + // Update the existing group + if ( + existingGroup.sampleAccountIds.unshift(notification.account.id) > + NOTIFICATIONS_GROUP_MAX_AVATARS + ) + existingGroup.sampleAccountIds.pop(); + + existingGroup.most_recent_notification_id = notification.id; + existingGroup.page_max_id = notification.id; + existingGroup.latest_page_notification_at = notification.created_at; + existingGroup.notifications_count += 1; + + groups.splice(existingGroupIndex, 1); + mergeGapsAround(groups, existingGroupIndex); + + groups.unshift(existingGroup); + } + } else { + // Create a new group + groups.unshift(createNotificationGroupFromNotificationJSON(notification)); + } +} + +function trimNotifications(state: NotificationGroupsState) { + if (state.scrolledToTop) { + state.groups.splice(NOTIFICATIONS_TRIM_LIMIT); + } +} + +function shouldMarkNewNotificationsAsRead( + { + isTabVisible, + scrolledToTop, + mounted, + lastReadId, + groups, + }: NotificationGroupsState, + ignoreScroll = false, +) { + const isMounted = mounted > 0; + const oldestGroup = groups.findLast(isNotificationGroup); + const hasMore = groups.at(-1)?.type === 'gap'; + const oldestGroupReached = + !hasMore || + lastReadId === '0' || + (oldestGroup?.page_min_id && + compareId(oldestGroup.page_min_id, lastReadId) <= 0); + + return ( + isTabVisible && + (ignoreScroll || scrolledToTop) && + isMounted && + oldestGroupReached + ); +} + +function updateLastReadId( + state: NotificationGroupsState, + group: NotificationGroup | undefined = undefined, +) { + if (shouldMarkNewNotificationsAsRead(state)) { + group = group ?? state.groups.find(isNotificationGroup); + if ( + group?.page_max_id && + compareId(state.lastReadId, group.page_max_id) < 0 + ) + state.lastReadId = group.page_max_id; + } +} + +export const notificationGroupsReducer = createReducer( + initialState, + (builder) => { + builder + .addCase(fetchNotifications.fulfilled, (state, action) => { + state.groups = action.payload.map((json) => + json.type === 'gap' ? json : createNotificationGroupFromJSON(json), + ); + state.isLoading = false; + updateLastReadId(state); + }) + .addCase(fetchNotificationsGap.fulfilled, (state, action) => { + const { notifications } = action.payload; + + // find the gap in the existing notifications + const gapIndex = state.groups.findIndex( + (groupOrGap) => + groupOrGap.type === 'gap' && + groupOrGap.sinceId === action.meta.arg.gap.sinceId && + groupOrGap.maxId === action.meta.arg.gap.maxId, + ); + + if (gapIndex < 0) + // We do not know where to insert, let's return + return; + + // Filling a disconnection gap means we're getting historical data + // about groups we may know or may not know about. + + // The notifications timeline is split in two by the gap, with + // group information newer than the gap, and group information older + // than the gap. + + // Filling a gap should not touch anything before the gap, so any + // information on groups already appearing before the gap should be + // discarded, while any information on groups appearing after the gap + // can be updated and re-ordered. + + const oldestPageNotification = notifications.at(-1)?.page_min_id; + + // replace the gap with the notifications + a new gap + + const newerGroupKeys = state.groups + .slice(0, gapIndex) + .filter(isNotificationGroup) + .map((group) => group.group_key); + + const toInsert: NotificationGroupsState['groups'] = notifications + .map((json) => createNotificationGroupFromJSON(json)) + .filter( + (notification) => !newerGroupKeys.includes(notification.group_key), + ); + + const apiGroupKeys = (toInsert as NotificationGroup[]).map( + (group) => group.group_key, + ); + + const sinceId = action.meta.arg.gap.sinceId; + if ( + notifications.length > 0 && + !( + oldestPageNotification && + sinceId && + compareId(oldestPageNotification, sinceId) <= 0 + ) + ) { + // If we get an empty page, it means we reached the bottom, so we do not need to insert a new gap + // Similarly, if we've fetched more than the gap's, this means we have completely filled it + toInsert.push({ + type: 'gap', + maxId: notifications.at(-1)?.page_max_id, + sinceId, + } as NotificationGap); + } + + // Remove older groups covered by the API + state.groups = state.groups.filter( + (groupOrGap) => + groupOrGap.type !== 'gap' && + !apiGroupKeys.includes(groupOrGap.group_key), + ); + + // Replace the gap with API results (+ the new gap if needed) + state.groups.splice(gapIndex, 1, ...toInsert); + + // Finally, merge any adjacent gaps that could have been created by filtering + // groups earlier + mergeGaps(state.groups); + + state.isLoading = false; + + updateLastReadId(state); + }) + .addCase(processNewNotificationForGroups.fulfilled, (state, action) => { + const notification = action.payload; + processNewNotification( + usePendingItems ? state.pendingGroups : state.groups, + notification, + ); + updateLastReadId(state); + trimNotifications(state); + }) + .addCase(disconnectTimeline, (state, action) => { + if (action.payload.timeline === 'home') { + if (state.groups.length > 0 && state.groups[0]?.type !== 'gap') { + state.groups.unshift({ + type: 'gap', + sinceId: state.groups[0]?.page_min_id, + }); + } + } + }) + .addCase(timelineDelete, (state, action) => { + removeNotificationsForStatus(state, action.payload.statusId); + }) + .addCase(clearNotifications.pending, (state) => { + state.groups = []; + state.pendingGroups = []; + }) + .addCase(blockAccountSuccess, (state, action) => { + removeNotificationsForAccounts(state, [action.payload.relationship.id]); + }) + .addCase(muteAccountSuccess, (state, action) => { + if (action.payload.relationship.muting_notifications) + removeNotificationsForAccounts(state, [ + action.payload.relationship.id, + ]); + }) + .addCase(blockDomainSuccess, (state, action) => { + removeNotificationsForAccounts( + state, + action.payload.accounts.map((account) => account.id), + ); + }) + .addCase(loadPending, (state) => { + // First, remove any existing group and merge data + state.pendingGroups.forEach((group) => { + if (group.type !== 'gap') { + const existingGroupIndex = state.groups.findIndex( + (groupOrGap) => + isNotificationGroup(groupOrGap) && + groupOrGap.group_key === group.group_key, + ); + if (existingGroupIndex > -1) { + const existingGroup = state.groups[existingGroupIndex]; + if (existingGroup && existingGroup.type !== 'gap') { + group.notifications_count += existingGroup.notifications_count; + group.sampleAccountIds = group.sampleAccountIds + .concat(existingGroup.sampleAccountIds) + .slice(0, NOTIFICATIONS_GROUP_MAX_AVATARS); + state.groups.splice(existingGroupIndex, 1); + } + } + } + trimNotifications(state); + }); + + // Then build the consolidated list and clear pending groups + state.groups = state.pendingGroups.concat(state.groups); + state.pendingGroups = []; + }) + .addCase(updateScrollPosition, (state, action) => { + state.scrolledToTop = action.payload.top; + updateLastReadId(state); + trimNotifications(state); + }) + .addCase(markNotificationsAsRead, (state) => { + const mostRecentGroup = state.groups.find(isNotificationGroup); + if ( + mostRecentGroup?.page_max_id && + compareId(state.lastReadId, mostRecentGroup.page_max_id) < 0 + ) + state.lastReadId = mostRecentGroup.page_max_id; + }) + .addCase(fetchMarkers.fulfilled, (state, action) => { + if ( + action.payload.markers.notifications && + compareId( + state.lastReadId, + action.payload.markers.notifications.last_read_id, + ) < 0 + ) + state.lastReadId = action.payload.markers.notifications.last_read_id; + }) + .addCase(mountNotifications, (state) => { + state.mounted += 1; + updateLastReadId(state); + }) + .addCase(unmountNotifications, (state) => { + state.mounted -= 1; + }) + .addCase(focusApp, (state) => { + state.isTabVisible = true; + updateLastReadId(state); + }) + .addCase(unfocusApp, (state) => { + state.isTabVisible = false; + }) + .addMatcher( + isAnyOf(authorizeFollowRequestSuccess, rejectFollowRequestSuccess), + (state, action) => { + removeNotificationsForAccounts( + state, + [action.payload.id], + 'follow_request', + ); + }, + ) + .addMatcher( + isAnyOf(fetchNotifications.pending, fetchNotificationsGap.pending), + (state) => { + state.isLoading = true; + }, + ) + .addMatcher( + isAnyOf(fetchNotifications.rejected, fetchNotificationsGap.rejected), + (state) => { + state.isLoading = false; + }, + ); + }, +); diff --git a/app/javascript/mastodon/reducers/notifications.js b/app/javascript/mastodon/reducers/notifications.js index 79aa5651ff1da6..622f5e8e884bbd 100644 --- a/app/javascript/mastodon/reducers/notifications.js +++ b/app/javascript/mastodon/reducers/notifications.js @@ -16,13 +16,13 @@ import { import { fetchMarkers, } from '../actions/markers'; +import { clearNotifications } from '../actions/notification_groups'; import { notificationsUpdate, NOTIFICATIONS_EXPAND_SUCCESS, NOTIFICATIONS_EXPAND_REQUEST, NOTIFICATIONS_EXPAND_FAIL, NOTIFICATIONS_FILTER_SET, - NOTIFICATIONS_CLEAR, NOTIFICATIONS_SCROLL_TOP, NOTIFICATIONS_LOAD_PENDING, NOTIFICATIONS_MOUNT, @@ -290,7 +290,7 @@ export default function notifications(state = initialState, action) { case authorizeFollowRequestSuccess.type: case rejectFollowRequestSuccess.type: return filterNotifications(state, [action.payload.id], 'follow_request'); - case NOTIFICATIONS_CLEAR: + case clearNotifications.pending.type: return state.set('items', ImmutableList()).set('pendingItems', ImmutableList()).set('hasMore', false); case timelineDelete.type: return deleteByStatus(state, action.payload.statusId); diff --git a/app/javascript/mastodon/selectors/notifications.ts b/app/javascript/mastodon/selectors/notifications.ts new file mode 100644 index 00000000000000..1b1ed2154cdaa7 --- /dev/null +++ b/app/javascript/mastodon/selectors/notifications.ts @@ -0,0 +1,34 @@ +import { createSelector } from '@reduxjs/toolkit'; + +import { compareId } from 'mastodon/compare_id'; +import type { RootState } from 'mastodon/store'; + +export const selectUnreadNotificationGroupsCount = createSelector( + [ + (s: RootState) => s.notificationGroups.lastReadId, + (s: RootState) => s.notificationGroups.pendingGroups, + (s: RootState) => s.notificationGroups.groups, + ], + (notificationMarker, pendingGroups, groups) => { + return ( + groups.filter( + (group) => + group.type !== 'gap' && + group.page_max_id && + compareId(group.page_max_id, notificationMarker) > 0, + ).length + + pendingGroups.filter( + (group) => + group.type !== 'gap' && + group.page_max_id && + compareId(group.page_max_id, notificationMarker) > 0, + ).length + ); + }, +); + +export const selectPendingNotificationGroupsCount = createSelector( + [(s: RootState) => s.notificationGroups.pendingGroups], + (pendingGroups) => + pendingGroups.filter((group) => group.type !== 'gap').length, +); diff --git a/app/javascript/mastodon/selectors/settings.ts b/app/javascript/mastodon/selectors/settings.ts new file mode 100644 index 00000000000000..64d9440bc8d3b0 --- /dev/null +++ b/app/javascript/mastodon/selectors/settings.ts @@ -0,0 +1,40 @@ +import type { RootState } from 'mastodon/store'; + +/* eslint-disable @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */ +// state.settings is not yet typed, so we disable some ESLint checks for those selectors +export const selectSettingsNotificationsShows = (state: RootState) => + state.settings.getIn(['notifications', 'shows']).toJS() as Record< + string, + boolean + >; + +export const selectSettingsNotificationsExcludedTypes = (state: RootState) => + Object.entries(selectSettingsNotificationsShows(state)) + .filter(([_type, enabled]) => !enabled) + .map(([type, _enabled]) => type); + +export const selectSettingsNotificationsQuickFilterShow = (state: RootState) => + state.settings.getIn(['notifications', 'quickFilter', 'show']) as boolean; + +export const selectSettingsNotificationsQuickFilterActive = ( + state: RootState, +) => state.settings.getIn(['notifications', 'quickFilter', 'active']) as string; + +export const selectSettingsNotificationsQuickFilterAdvanced = ( + state: RootState, +) => + state.settings.getIn(['notifications', 'quickFilter', 'advanced']) as boolean; + +export const selectSettingsNotificationsShowUnread = (state: RootState) => + state.settings.getIn(['notifications', 'showUnread']) as boolean; + +export const selectNeedsNotificationPermission = (state: RootState) => + (state.settings.getIn(['notifications', 'alerts']).includes(true) && + state.notifications.get('browserSupport') && + state.notifications.get('browserPermission') === 'default' && + !state.settings.getIn([ + 'notifications', + 'dismissPermissionBanner', + ])) as boolean; + +/* eslint-enable @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */ diff --git a/app/javascript/styles/mastodon-light/diff.scss b/app/javascript/styles/mastodon-light/diff.scss index 07e9d9868b4272..a41272364a3106 100644 --- a/app/javascript/styles/mastodon-light/diff.scss +++ b/app/javascript/styles/mastodon-light/diff.scss @@ -48,6 +48,10 @@ html { } } +.icon-button:disabled { + color: darken($action-button-color, 25%); +} + .account__header__bar .avatar .account__avatar { border-color: $white; } diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index a8272a3ac225f6..fe9dd025173ed0 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -1382,6 +1382,8 @@ body > [data-popper-placement] { min-height: 54px; border-bottom: 1px solid var(--background-border-color); cursor: auto; + opacity: 1; + animation: fade 150ms linear; @keyframes fade { 0% { @@ -1393,9 +1395,6 @@ body > [data-popper-placement] { } } - opacity: 1; - animation: fade 150ms linear; - .media-gallery, .video-player, .audio-player, @@ -1628,14 +1627,19 @@ body > [data-popper-placement] { } } -.status__wrapper-direct { +.status__wrapper-direct, +.notification-ungrouped--direct { background: rgba($ui-highlight-color, 0.05); &:focus { - background: rgba($ui-highlight-color, 0.05); + background: rgba($ui-highlight-color, 0.1); } +} - .status__prepend { +.status__wrapper-direct, +.notification-ungrouped--direct { + .status__prepend, + .notification-ungrouped__header { color: $highlight-text-color; } } @@ -2226,41 +2230,28 @@ a.account__display-name { } } -.notification__relationships-severance-event, -.notification__moderation-warning { - display: flex; - gap: 16px; +.notification-group--link { color: $secondary-text-color; text-decoration: none; - align-items: flex-start; - padding: 16px 32px; - border-bottom: 1px solid var(--background-border-color); - - &:hover { - color: $primary-text-color; - } - - .icon { - padding: 2px; - color: $highlight-text-color; - } - &__content { + .notification-group__main { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; flex-grow: 1; - font-size: 16px; - line-height: 24px; + font-size: 15px; + line-height: 22px; - strong { + strong, + bdi { font-weight: 700; } .link-button { font-size: inherit; line-height: inherit; + font-weight: inherit; } } } @@ -4867,8 +4858,10 @@ a.status-card { &__menu { @include search-popout; - padding: 0; - background: $ui-secondary-color; + & { + padding: 0; + background: $ui-secondary-color; + } } &__menu-list { @@ -10352,10 +10345,9 @@ noscript { .filtered-notifications-banner { display: flex; align-items: center; - border: 1px solid var(--background-border-color); - border-top: 0; - padding: 24px 32px; - gap: 16px; + border-bottom: 1px solid var(--background-border-color); + padding: 16px 24px; + gap: 8px; color: $darker-text-color; text-decoration: none; @@ -10365,10 +10357,8 @@ noscript { color: $secondary-text-color; } - .icon { - width: 24px; - height: 24px; - padding: 2px; + .notification-group__icon { + color: inherit; } &__text { @@ -10506,6 +10496,251 @@ noscript { } } +.notification-group { + display: flex; + align-items: flex-start; + gap: 8px; + padding: 16px 24px; + border-bottom: 1px solid var(--background-border-color); + + &__icon { + width: 40px; + display: flex; + align-items: center; + justify-content: center; + flex: 0 0 auto; + color: $dark-text-color; + + .icon { + width: 28px; + height: 28px; + } + } + + &--follow &__icon, + &--follow-request &__icon { + color: $highlight-text-color; + } + + &--favourite &__icon { + color: $gold-star; + } + + &--reblog &__icon { + color: $valid-value-color; + } + + &--relationships-severance-event &__icon, + &--admin-report &__icon, + &--admin-sign-up &__icon { + color: $dark-text-color; + } + + &--moderation-warning &__icon { + color: $red-bookmark; + } + + &--follow-request &__actions { + align-items: center; + display: flex; + gap: 8px; + + .icon-button { + border: 1px solid var(--background-border-color); + border-radius: 50%; + padding: 1px; + } + } + + &__main { + display: flex; + flex-direction: column; + gap: 8px; + flex: 1 1 auto; + overflow: hidden; + + &__header { + display: flex; + flex-direction: column; + gap: 8px; + + &__wrapper { + display: flex; + justify-content: space-between; + } + + &__label { + display: flex; + gap: 8px; + font-size: 15px; + line-height: 22px; + color: $darker-text-color; + + a { + color: inherit; + text-decoration: none; + } + + bdi { + font-weight: 700; + color: $primary-text-color; + } + + time { + color: $dark-text-color; + } + } + } + + &__status { + border: 1px solid var(--background-border-color); + border-radius: 8px; + padding: 8px; + } + } + + &__avatar-group { + display: flex; + gap: 8px; + height: 28px; + overflow-y: hidden; + flex-wrap: wrap; + } + + .status { + padding: 0; + border: 0; + } + + &__embedded-status { + &__account { + display: flex; + align-items: center; + gap: 4px; + margin-bottom: 8px; + color: $dark-text-color; + + bdi { + color: inherit; + } + } + + .account__avatar { + opacity: 0.5; + } + + &__content { + display: -webkit-box; + font-size: 15px; + line-height: 22px; + color: $dark-text-color; + cursor: pointer; + -webkit-line-clamp: 4; + -webkit-box-orient: vertical; + max-height: 4 * 22px; + overflow: hidden; + + p, + a { + color: inherit; + } + } + } +} + +.notification-ungrouped { + padding: 16px 24px; + border-bottom: 1px solid var(--background-border-color); + + &__header { + display: flex; + align-items: center; + gap: 8px; + color: $dark-text-color; + font-size: 15px; + line-height: 22px; + font-weight: 500; + padding-inline-start: 24px; + margin-bottom: 16px; + + &__icon { + display: flex; + align-items: center; + justify-content: center; + flex: 0 0 auto; + + .icon { + width: 16px; + height: 16px; + } + } + + a { + color: inherit; + text-decoration: none; + } + } + + .status { + border: 0; + padding: 0; + + &__avatar { + width: 40px; + height: 40px; + } + } + + .status__wrapper-direct { + background: transparent; + } + + $icon-margin: 48px; // 40px avatar + 8px gap + + .status__content, + .status__action-bar, + .media-gallery, + .video-player, + .audio-player, + .attachment-list, + .picture-in-picture-placeholder, + .more-from-author, + .status-card, + .hashtag-bar { + margin-inline-start: $icon-margin; + width: calc(100% - $icon-margin); + } + + .more-from-author { + width: calc(100% - $icon-margin + 2px); + } + + .status__content__read-more-button { + margin-inline-start: $icon-margin; + } + + .notification__report { + border: 0; + padding: 0; + } +} + +.notification-group--unread, +.notification-ungrouped--unread { + position: relative; + + &::before { + content: ''; + position: absolute; + top: 0; + inset-inline-start: 0; + width: 100%; + height: 100%; + border-inline-start: 4px solid $highlight-text-color; + pointer-events: none; + } +} + .hover-card-controller[data-popper-reference-hidden='true'] { opacity: 0; pointer-events: none; @@ -10614,7 +10849,7 @@ noscript { gap: 4px; dt { - flex: 0 0 auto; + flex: 0 1 auto; color: $dark-text-color; min-width: 0; overflow: hidden; diff --git a/app/javascript/styles/win95.scss b/app/javascript/styles/win95.scss index 66d451303ab64b..2302dc40d5b6f7 100644 --- a/app/javascript/styles/win95.scss +++ b/app/javascript/styles/win95.scss @@ -2503,6 +2503,7 @@ body { background: $win95-tooltip-yellow; border: 1px solid black; padding: 4px; + margin-bottom: 24px; h1, h1 small { color:black; @@ -2510,8 +2511,6 @@ body { text-overflow: unset; } - margin-bottom: 24px; - &:after { content: ""; display:block; diff --git a/app/lib/link_details_extractor.rb b/app/lib/link_details_extractor.rb index dbfdd33fccaf3a..d81f4a30622dec 100644 --- a/app/lib/link_details_extractor.rb +++ b/app/lib/link_details_extractor.rb @@ -62,7 +62,8 @@ def date_modified end def author_name - author['name'] + name = author['name'] + name.is_a?(Array) ? name.join(', ') : name end def author_url @@ -156,11 +157,11 @@ def height end def title - html_entities.decode(structured_data&.headline || opengraph_tag('og:title') || document.xpath('//title').map(&:content).first).strip + html_entities_decode(structured_data&.headline || opengraph_tag('og:title') || document.xpath('//title').map(&:content).first)&.strip end def description - html_entities.decode(structured_data&.description || opengraph_tag('og:description') || meta_tag('description')) + html_entities_decode(structured_data&.description || opengraph_tag('og:description') || meta_tag('description')) end def published_at @@ -180,7 +181,7 @@ def canonical_url end def provider_name - html_entities.decode(structured_data&.publisher_name || opengraph_tag('og:site_name')) + html_entities_decode(structured_data&.publisher_name || opengraph_tag('og:site_name')) end def provider_url @@ -188,7 +189,7 @@ def provider_url end def author_name - html_entities.decode(structured_data&.author_name || opengraph_tag('og:author') || opengraph_tag('og:author:username')) + html_entities_decode(structured_data&.author_name || opengraph_tag('og:author') || opengraph_tag('og:author:username')) end def author_url @@ -257,7 +258,7 @@ def structured_data next if json_ld.blank? - structured_data = StructuredData.new(html_entities.decode(json_ld)) + structured_data = StructuredData.new(html_entities_decode(json_ld)) next unless structured_data.valid? @@ -273,10 +274,11 @@ def document end def detect_encoding_and_parse_document - [detect_encoding, nil, @html_charset, 'UTF-8'].uniq.each do |encoding| + [detect_encoding, nil, header_encoding].uniq.each do |encoding| document = Nokogiri::HTML(@html, nil, encoding) return document if document.to_s.valid_encoding? end + Nokogiri::HTML(@html, nil, 'UTF-8') end def detect_encoding @@ -284,12 +286,28 @@ def detect_encoding guess&.fetch(:confidence, 0).to_i > 60 ? guess&.fetch(:encoding, nil) : nil end + def header_encoding + Encoding.find(@html_charset).name if @html_charset + rescue ArgumentError + # Encoding from HTTP header is not recognized by ruby + nil + end + def detector @detector ||= CharlockHolmes::EncodingDetector.new.tap do |detector| detector.strip_tags = true end end + def html_entities_decode(string) + return if string.nil? + + unicode_string = string.to_s.encode('UTF-8') + raise EncodingError, 'cannot convert string to valid UTF-8' unless unicode_string.valid_encoding? + + html_entities.decode(unicode_string) + end + def html_entities @html_entities ||= HTMLEntities.new(:expanded) end diff --git a/app/lib/webfinger.rb b/app/lib/webfinger.rb index ae8a3b1eae0264..aeafe197024974 100644 --- a/app/lib/webfinger.rb +++ b/app/lib/webfinger.rb @@ -26,7 +26,7 @@ def link(rel, attribute) private def links - @links ||= @json['links'].index_by { |link| link['rel'] } + @links ||= @json.fetch('links', []).index_by { |link| link['rel'] } end def validate_response! diff --git a/app/models/concerns/user/has_settings.rb b/app/models/concerns/user/has_settings.rb index 53100cc097b4f5..b79726e38aedf6 100644 --- a/app/models/concerns/user/has_settings.rb +++ b/app/models/concerns/user/has_settings.rb @@ -103,6 +103,10 @@ def setting_disable_swiping settings['web.disable_swiping'] end + def setting_disable_hover_cards + settings['web.disable_hover_cards'] + end + def setting_always_send_emails settings['always_send_emails'] end diff --git a/app/models/notification.rb b/app/models/notification.rb index 01abe74f5e7eb3..6d404114788c00 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -30,6 +30,7 @@ class Notification < ApplicationRecord 'Poll' => :poll, }.freeze + # Please update app/javascript/api_types/notification.ts if you change this PROPERTIES = { mention: { filterable: true, diff --git a/app/models/notification_group.rb b/app/models/notification_group.rb index b1cbd7c19abf9f..223945f07bf681 100644 --- a/app/models/notification_group.rb +++ b/app/models/notification_group.rb @@ -3,13 +3,17 @@ class NotificationGroup < ActiveModelSerializers::Model attributes :group_key, :sample_accounts, :notifications_count, :notification, :most_recent_notification_id + # Try to keep this consistent with `app/javascript/mastodon/models/notification_group.ts` + SAMPLE_ACCOUNTS_SIZE = 8 + def self.from_notification(notification, max_id: nil) if notification.group_key.present? - # TODO: caching and preloading + # TODO: caching, and, if caching, preloading scope = notification.account.notifications.where(group_key: notification.group_key) scope = scope.where(id: ..max_id) if max_id.present? - most_recent_notifications = scope.order(id: :desc).take(3) + # Ideally, we would not load accounts for each notification group + most_recent_notifications = scope.order(id: :desc).includes(:from_account).take(SAMPLE_ACCOUNTS_SIZE) most_recent_id = most_recent_notifications.first.id sample_accounts = most_recent_notifications.map(&:from_account) notifications_count = scope.count diff --git a/app/models/notification_policy.rb b/app/models/notification_policy.rb index f10b0c2a816e9e..2bb58004e37fad 100644 --- a/app/models/notification_policy.rb +++ b/app/models/notification_policy.rb @@ -31,6 +31,6 @@ def summarize! private def pending_notification_requests - @pending_notification_requests ||= notification_requests.where(dismissed: false).limit(MAX_MEANINGFUL_COUNT).pick(Arel.sql('count(*), coalesce(sum(notifications_count), 0)::bigint')) + @pending_notification_requests ||= notification_requests.limit(MAX_MEANINGFUL_COUNT).pick(Arel.sql('count(*), coalesce(sum(notifications_count), 0)::bigint')) end end diff --git a/app/models/notification_request.rb b/app/models/notification_request.rb index 6e9cae66255032..2f601ac36b7f82 100644 --- a/app/models/notification_request.rb +++ b/app/models/notification_request.rb @@ -9,12 +9,13 @@ # from_account_id :bigint(8) not null # last_status_id :bigint(8) # notifications_count :bigint(8) default(0), not null -# dismissed :boolean default(FALSE), not null # created_at :datetime not null # updated_at :datetime not null # class NotificationRequest < ApplicationRecord + self.ignored_columns += %w(dismissed) + include Paginable MAX_MEANINGFUL_COUNT = 100 @@ -34,8 +35,6 @@ def self.preload_cache_collection(requests) end def reconsider_existence! - return if dismissed? - prepare_notifications_count if notifications_count.positive? diff --git a/app/models/preview_card.rb b/app/models/preview_card.rb index eac02ac14ff05c..5a11351e58808a 100644 --- a/app/models/preview_card.rb +++ b/app/models/preview_card.rb @@ -46,6 +46,11 @@ class PreviewCard < ApplicationRecord y_comp: 4, }.freeze + # URL size limit to safely store in PosgreSQL's unique indexes + # Technically this is a byte-size limit but we use it as a + # character limit to work with length validation + URL_CHARACTER_LIMIT = 2692 + self.inheritance_column = false enum :type, { link: 0, photo: 1, video: 2, rich: 3 } @@ -63,7 +68,7 @@ class PreviewCard < ApplicationRecord convert_options: { all: '-quality 90 +profile "!icc,*" +set date:modify +set date:create +set date:timestamp' }, validate_media_type: false - validates :url, presence: true, uniqueness: true, url: true + validates :url, presence: true, uniqueness: true, url: true, length: { maximum: URL_CHARACTER_LIMIT } validates_attachment_content_type :image, content_type: IMAGE_MIME_TYPES validates_attachment_size :image, less_than: LIMIT remotable_attachment :image, LIMIT diff --git a/app/models/report.rb b/app/models/report.rb index 3df5a20e1819c1..17c1503436f0ff 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -18,6 +18,7 @@ # category :integer default("other"), not null # action_taken_at :datetime # rule_ids :bigint(8) is an Array +# application_id :bigint(8) # class Report < ApplicationRecord @@ -31,6 +32,7 @@ class Report < ApplicationRecord rate_limit by: :account, family: :reports belongs_to :account + belongs_to :application, class_name: 'Doorkeeper::Application', optional: true with_options class_name: 'Account' do belongs_to :target_account diff --git a/app/models/status.rb b/app/models/status.rb index a6ea7bb90b3e28..4f2ceb9ca95271 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -295,7 +295,7 @@ def ordered_media_attachments else map = media_attachments.index_by(&:id) ordered_media_attachment_ids.filter_map { |media_attachment_id| map[media_attachment_id] } - end + end.take(MEDIA_ATTACHMENTS_LIMIT) end def replies_count diff --git a/app/models/status_edit.rb b/app/models/status_edit.rb index e5d7cb46eaca47..165b5403ec165c 100644 --- a/app/models/status_edit.rb +++ b/app/models/status_edit.rb @@ -54,12 +54,14 @@ def emojis def ordered_media_attachments return @ordered_media_attachments if defined?(@ordered_media_attachments) - @ordered_media_attachments = if ordered_media_attachment_ids.nil? - [] - else - map = status.media_attachments.index_by(&:id) - ordered_media_attachment_ids.map.with_index { |media_attachment_id, index| PreservedMediaAttachment.new(media_attachment: map[media_attachment_id], description: media_descriptions[index]) } - end + @ordered_media_attachments = begin + if ordered_media_attachment_ids.nil? + [] + else + map = status.media_attachments.index_by(&:id) + ordered_media_attachment_ids.map.with_index { |media_attachment_id, index| PreservedMediaAttachment.new(media_attachment: map[media_attachment_id], description: media_descriptions[index]) } + end + end.take(Status::MEDIA_ATTACHMENTS_LIMIT) end def proper diff --git a/app/models/user_settings.rb b/app/models/user_settings.rb index 886c5c9c4d0ccf..3b245a4e461941 100644 --- a/app/models/user_settings.rb +++ b/app/models/user_settings.rb @@ -29,6 +29,7 @@ class KeyError < Error; end setting :use_pending_items, default: false setting :use_system_font, default: false setting :disable_swiping, default: false + setting :disable_hover_cards, default: false setting :delete_modal, default: true setting :reblog_modal, default: false setting :favourite_modal, default: false diff --git a/app/serializers/initial_state_serializer.rb b/app/serializers/initial_state_serializer.rb index fe6ab5e995195d..5bbb0fe4b4e503 100644 --- a/app/serializers/initial_state_serializer.rb +++ b/app/serializers/initial_state_serializer.rb @@ -39,6 +39,7 @@ def meta store[:expand_spoilers] = object_account_user.setting_expand_spoilers store[:reduce_motion] = object_account_user.setting_reduce_motion store[:disable_swiping] = object_account_user.setting_disable_swiping + store[:disable_hover_cards] = object_account_user.setting_disable_hover_cards store[:advanced_layout] = object_account_user.setting_advanced_layout store[:use_blurhash] = object_account_user.setting_use_blurhash store[:use_pending_items] = object_account_user.setting_use_pending_items diff --git a/app/serializers/rest/notification_group_serializer.rb b/app/serializers/rest/notification_group_serializer.rb index 9aa5663f4e040c..749f71775463e0 100644 --- a/app/serializers/rest/notification_group_serializer.rb +++ b/app/serializers/rest/notification_group_serializer.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true class REST::NotificationGroupSerializer < ActiveModel::Serializer + # Please update app/javascript/api_types/notification.ts when making changes to the attributes attributes :group_key, :notifications_count, :type, :most_recent_notification_id attribute :page_min_id, if: :paginated? diff --git a/app/serializers/rest/notification_serializer.rb b/app/serializers/rest/notification_serializer.rb index 966819585fcc7c..320bc86961d922 100644 --- a/app/serializers/rest/notification_serializer.rb +++ b/app/serializers/rest/notification_serializer.rb @@ -1,8 +1,11 @@ # frozen_string_literal: true class REST::NotificationSerializer < ActiveModel::Serializer + # Please update app/javascript/api_types/notification.ts when making changes to the attributes attributes :id, :type, :created_at, :group_key + attribute :filtered, if: :filtered? + belongs_to :from_account, key: :account, serializer: REST::AccountSerializer belongs_to :target_status, key: :status, if: :status_type?, serializer: REST::StatusSerializer belongs_to :report, if: :report_type?, serializer: REST::ReportSerializer @@ -32,4 +35,6 @@ def relationship_severance_event? def moderation_warning_event? object.type == :moderation_warning end + + delegate :filtered?, to: :object end diff --git a/app/services/fetch_link_card_service.rb b/app/services/fetch_link_card_service.rb index 8bc9f912c55da0..adabb1096e86eb 100644 --- a/app/services/fetch_link_card_service.rb +++ b/app/services/fetch_link_card_service.rb @@ -15,9 +15,6 @@ class FetchLinkCardService < BaseService ) }iox - # URL size limit to safely store in PosgreSQL's unique indexes - BYTESIZE_LIMIT = 2692 - def call(status) @status = status @original_url = parse_urls @@ -32,7 +29,7 @@ def call(status) end attach_card if @card&.persisted? - rescue HTTP::Error, OpenSSL::SSL::SSLError, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError, Encoding::UndefinedConversionError => e + rescue HTTP::Error, OpenSSL::SSL::SSLError, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError, EncodingError, ActiveRecord::RecordInvalid => e Rails.logger.debug { "Error fetching link #{@original_url}: #{e}" } nil end @@ -88,7 +85,7 @@ def parse_urls def bad_url?(uri) # Avoid local instance URLs and invalid URLs - uri.host.blank? || TagManager.instance.local_url?(uri.to_s) || !%w(http https).include?(uri.scheme) || uri.to_s.bytesize > BYTESIZE_LIMIT + uri.host.blank? || TagManager.instance.local_url?(uri.to_s) || !%w(http https).include?(uri.scheme) end def mention_link?(anchor) diff --git a/app/services/notify_service.rb b/app/services/notify_service.rb index d69b5af141214f..23f92c816b86c0 100644 --- a/app/services/notify_service.rb +++ b/app/services/notify_service.rb @@ -4,7 +4,6 @@ class NotifyService < BaseService include Redisable MAXIMUM_GROUP_SPAN_HOURS = 12 - MAXIMUM_GROUP_GAP_TIME = 4.hours.to_i NON_EMAIL_TYPES = %i( admin.report @@ -217,9 +216,8 @@ def notification_group_key previous_bucket = redis.get(redis_key).to_i hour_bucket = previous_bucket if hour_bucket < previous_bucket + MAXIMUM_GROUP_SPAN_HOURS - # Do not track groups past a given inactivity time # We do not concern ourselves with race conditions since we use hour buckets - redis.set(redis_key, hour_bucket, ex: MAXIMUM_GROUP_GAP_TIME) + redis.set(redis_key, hour_bucket, ex: MAXIMUM_GROUP_SPAN_HOURS.hours.to_i) "#{type_prefix}-#{hour_bucket}" end diff --git a/app/services/report_service.rb b/app/services/report_service.rb index dea6df7b0a1b1b..c95e216c790162 100644 --- a/app/services/report_service.rb +++ b/app/services/report_service.rb @@ -10,6 +10,7 @@ def call(source_account, target_account, options = {}) @comment = options.delete(:comment).presence || '' @category = options[:rule_ids].present? ? 'violation' : (options.delete(:category).presence || 'other') @rule_ids = options.delete(:rule_ids).presence + @application = options.delete(:application).presence @options = options raise ActiveRecord::RecordNotFound if @target_account.unavailable? @@ -35,7 +36,8 @@ def create_report! uri: @options[:uri], forwarded: forward_to_origin?, category: @category, - rule_ids: @rule_ids + rule_ids: @rule_ids, + application: @application ) end diff --git a/app/views/admin/reports/_header_details.html.haml b/app/views/admin/reports/_header_details.html.haml index 45790b9cd50d75..434231f7333626 100644 --- a/app/views/admin/reports/_header_details.html.haml +++ b/app/views/admin/reports/_header_details.html.haml @@ -14,6 +14,12 @@ = admin_account_link_to report.account - else = report.account.domain + - if report.application.present? + .report-header__details__item + .report-header__details__item__header + %strong= t('admin.reports.reported_with_application') + .report-header__details__item__content + = report.application.name .report-header__details__item .report-header__details__item__header %strong= t('admin.reports.status') diff --git a/app/views/settings/preferences/appearance/show.html.haml b/app/views/settings/preferences/appearance/show.html.haml index a5ad02a600891d..b0cd1cba09d63c 100644 --- a/app/views/settings/preferences/appearance/show.html.haml +++ b/app/views/settings/preferences/appearance/show.html.haml @@ -48,6 +48,7 @@ = ff.input :'web.auto_play', wrapper: :with_label, recommended: true, label: I18n.t('simple_form.labels.defaults.setting_auto_play_gif') = ff.input :'web.reduce_motion', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_reduce_motion') = ff.input :'web.disable_swiping', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_disable_swiping') + = ff.input :'web.disable_hover_cards', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_disable_hover_cards') = ff.input :'web.use_system_font', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_system_font_ui') = ff.input :'web.use_system_emoji_font', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_system_emoji_font'), glitch_only: true diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb index 53b02edc40227e..5b2f317bf2efc1 100644 --- a/config/initializers/sidekiq.rb +++ b/config/initializers/sidekiq.rb @@ -5,6 +5,23 @@ Sidekiq.configure_server do |config| config.redis = REDIS_SIDEKIQ_PARAMS + # This is used in Kubernetes setups, to signal that the Sidekiq process has started and will begin processing jobs + # This comes from https://github.com/sidekiq/sidekiq/wiki/Kubernetes#sidekiq + ready_filename = ENV.fetch('MASTODON_SIDEKIQ_READY_FILENAME', nil) + if ready_filename + raise 'MASTODON_SIDEKIQ_READY_FILENAME is not a valid filename' if File.basename(ready_filename) != ready_filename + + ready_path = Rails.root.join('tmp', ready_filename) + + config.on(:startup) do + FileUtils.touch(ready_path) + end + + config.on(:shutdown) do + FileUtils.rm_f(ready_path) + end + end + config.server_middleware do |chain| chain.add Mastodon::SidekiqMiddleware end diff --git a/config/initializers/vapid.rb b/config/initializers/vapid.rb index 7dd870c8b7d9af..551ede34fb9004 100644 --- a/config/initializers/vapid.rb +++ b/config/initializers/vapid.rb @@ -5,7 +5,7 @@ # You should only generate this once per instance. If you later decide to change it, all push subscription will # be invalidated, requiring the users to access the website again to resubscribe. # - # Generate with `rake mastodon:webpush:generate_vapid_key` task (`docker-compose run --rm web rake mastodon:webpush:generate_vapid_key` if you use docker compose) + # Generate with `bundle exec rails mastodon:webpush:generate_vapid_key` task (`docker-compose run --rm web bundle exec rails mastodon:webpush:generate_vapid_key` if you use docker compose) # # For more information visit https://rossta.net/blog/using-the-web-push-api-with-vapid.html diff --git a/config/locales-glitch/simple_form.ko.yml b/config/locales-glitch/simple_form.ko.yml index f9420f1336dafa..96e13201419de7 100644 --- a/config/locales-glitch/simple_form.ko.yml +++ b/config/locales-glitch/simple_form.ko.yml @@ -8,6 +8,7 @@ ko: setting_default_content_type_markdown: 게́‹œë¬¼́„ ́‘́„±í•  ë•Œ, 형́‹́„ ́§€́ •í•˜́§€ ́•́•˜ë‹¤ë©´, 마í¬ë‹¤́´́´ë¼ê³  ê°€́ •í•©ë‹ˆë‹¤ setting_default_content_type_plain: 게́‹œë¬¼́„ ́‘́„±í•  ë•Œ, 형́‹́„ ́§€́ •í•˜́§€ ́•́•˜ë‹¤ë©´, ́¼ë°˜́ ́¸ í…́¤í¸ë¼ê³  ê°€́ •í•©ë‹ˆë‹¤. (마́¤í† ëˆ́˜ 기본 ë™́‘) setting_default_language: ́‘́„±í•˜ë” 게́‹œë¬¼́˜ ́–¸́–´ë” ́ë™́œ¼ë¡œ ́„¤́ •ë  ́ˆ˜ ́ˆ́µë‹ˆë‹¤, 하́§€ë§Œ ́–¸́ œë‚˜ ́ •í™•í•˜́§€ë” ́•́µë‹ˆë‹¤ + setting_show_followers_count: 팔로́›Œ ́¹´́´í¸ë¥¼ 프로필́—́„œ ́ˆ¨ê¹ë‹ˆë‹¤. 팔로́›Œ ́ˆ˜ë¥¼ ́ˆ¨ê¸°ë©´ 나́—ê²Œë„ ë³´́´́§€ ́•́œ¼ë©° 몇몇 ́•±́—́„œë” 팔로́›Œ ́ˆ˜ê°€ ́Œ́ˆ˜ë¡œ í‘œ́‹œë  ́ˆ˜ ́ˆ́µë‹ˆë‹¤. setting_skin: ́„ íƒí•œ 마́¤í† ëˆ í’미́˜ ́¤í‚΅„ 바꿉니다 labels: defaults: @@ -16,6 +17,7 @@ ko: setting_default_content_type_markdown: 마í¬ë‹¤́´ setting_default_content_type_plain: ́¼ë°˜ í…́¤í¸ setting_favourite_modal: ê´€́‹¬ê¸€́„ ́§€́ •í•  ë•Œ 확́¸ ́°½́„ ë„́›ë‹ˆë‹¤(글리́¹˜ í’미́—만 ́ ́©ë¨) + setting_show_followers_count: 팔로́›Œ ́ˆ˜ í‘œ́‹œ setting_skin: ́¤í‚¨ setting_system_emoji_font: ́—모́§€́— ́‹œ́¤í…œ 기본 í°í¸ ́ ́©í•˜ê¸° (글리́¹˜ í’미́—만 ́ ́©ë¨) notification_emails: diff --git a/config/locales/activerecord.ga.yml b/config/locales/activerecord.ga.yml index 236cc479e17e1b..1b61edb2e2fe00 100644 --- a/config/locales/activerecord.ga.yml +++ b/config/locales/activerecord.ga.yml @@ -19,8 +19,41 @@ ga: account: attributes: username: + invalid: nĂ­ mĂ³r go mbeadh litreacha, uimhreacha agus pointĂ­ bĂ©ime amhĂ¡in reserved: in Ă¡irithe + admin/webhook: + attributes: + url: + invalid: nach URL bailĂ­ Ă© + doorkeeper/application: + attributes: + website: + invalid: nach URL bailĂ­ Ă© import: attributes: data: malformed: mĂ­chumtha + status: + attributes: + reblog: + taken: den phost cheana fĂ©in + user: + attributes: + email: + blocked: ĂºsĂ¡ideann solĂ¡thraĂ­ rĂ­omhphoist dĂ­cheadaithe + unreachable: nĂ­ cosĂºil go bhfuil sĂ© ann + role_id: + elevated: nĂ­ fĂ©idir leat a bheith nĂ­os airde nĂ¡ do rĂ³l reatha + user_role: + attributes: + permissions_as_keys: + dangerous: cuir san Ă¡ireamh ceadanna nach bhfuil sĂ¡bhĂ¡ilte don rĂ³l bunĂºsach + elevated: nĂ­ fĂ©idir ceadanna nach bhfuil ag do rĂ³l reatha a Ă¡ireamh + own_role: nĂ­ fĂ©idir Ă© a athrĂº le do rĂ³l reatha + position: + elevated: nĂ­ fĂ©idir leat a bheith nĂ­os airde nĂ¡ do rĂ³l reatha + own_role: nĂ­ fĂ©idir Ă© a athrĂº le do rĂ³l reatha + webhook: + attributes: + events: + invalid_permissions: nĂ­ fĂ©idir imeachtaĂ­ nach bhfuil na cearta agat ina leith a chur san Ă¡ireamh diff --git a/config/locales/activerecord.kab.yml b/config/locales/activerecord.kab.yml index b3ca90069b50ed..8cdc6501cbb494 100644 --- a/config/locales/activerecord.kab.yml +++ b/config/locales/activerecord.kab.yml @@ -21,6 +21,18 @@ kab: username: invalid: ilaq ad ilin isekkilen, uá¹­á¹­unen d yijerriden n wadda kan reserved: yettwaá¹­á¹­ef + admin/webhook: + attributes: + url: + invalid: maÄÄi d URL ameÉ£tu + doorkeeper/application: + attributes: + website: + invalid: maÄÄi d URL ameÉ£tu + import: + attributes: + data: + malformed: yir amsal status: attributes: reblog: @@ -28,4 +40,20 @@ kab: user: attributes: email: + blocked: isseqdac asaǧǧaw n yimayl ur yettusirgen ara unreachable: ur d-ttban ara d akken yella + role_id: + elevated: ur yezmir ara ad iεeddi tamlilt-ik tamirant + user_role: + attributes: + permissions_as_keys: + dangerous: deg-s tisirag tiriÉ£elsanin i temlilt tazadurt + elevated: ur yezmir ara ad yesεu tirirag ur nelli ara deg temlilit-ik tamirant + own_role: ur yezmir ara ad yettwabeddel s temlilt-ik tamirant + position: + elevated: ur yezmir ara ad iεeddi tamlilt-ik tamirant + own_role: ur yezmir ara ad yettwabeddel s temlilt-ik tamirant + webhook: + attributes: + events: + invalid_permissions: ur yezmir ara ad yesεu tidyanin iwumi ur tesεiḠara tisirag diff --git a/config/locales/ar.yml b/config/locales/ar.yml index 2ca7538c324d00..4df24c984c0ed0 100644 --- a/config/locales/ar.yml +++ b/config/locales/ar.yml @@ -1762,6 +1762,10 @@ ar: webauthn_authentication: Ù…ÙاتÙØ­ الأمان severed_relationships: download: تنزÙÙ„ (%{count}) + lost_followers: المتابعون المÙقودون + lost_follows: المتابعات المÙقودة + preamble: بحجبكم اسم نطاق قد تخسرون متابÙعاتÙØŒ Ùˆ كذلك إذا قرّر مدÙرو الخادوم حظر خادوم ما. Ùˆ Ù٠هذه الحالات Ùكون بوسعكم تنزÙÙ„ قائمة بالصلات المبتورة لمعاÙنتها، مع القدرة على استÙرادها إلى خادوم آخر. + purged: حذ٠مدÙر خادومكم المعلومات عن هذا الخادوم. statuses: attached: audio: @@ -1978,6 +1982,7 @@ ar: edit_profile_title: قم بتخصÙص ملÙÙƒ التعرÙÙÙ explanation: ها ه٠بعض النصائح قبل بداÙØ© الاستخدام feature_action: اعر٠المزÙد + feature_audience: ÙتÙØ­ لكم مًستÙدون إدارة جمهوركم بلا وسطاء. ÙبتنصÙب Ùˆ تشغÙÙ„ Ù…ÙستÙودون على بنÙتكم التحتÙØ© تمكنكم متابعة مستخدم٠مÙستÙدون من Ø£ÙÙ‘ خادوم،كما Ùمكنهم متابعتكم، بلا تحكّÙÙ… من أ٠طر٠ثالث. feature_audience_title: اÙبنوا جÙمهورÙكم بÙØ«ÙÙ‚ÙØ© feature_control: أنتم الأدرى بالمحتوى الذ٠ترÙدون أن تطالعوه ÙÙ ÙÙض المنشورات الرئÙس. لا خوارزمÙات تتحكم ÙÙما Ùظهر لكم ولا إعلانات تضÙع وقتكم. بحساب واحد تمكنكم متابعة من تشاؤون على Ø£ÙÙ‘ خادوم ماستدون، وتلقّى منشوراتهم بترتÙبها الزمنÙØŒ لتصنعوا ركنكم الألÙÙ Ù٠الإنترنت. feature_control_title: تحكّÙموا ÙÙ ÙÙض المنشورات الخاص بكم diff --git a/config/locales/bg.yml b/config/locales/bg.yml index 602a26225c2d23..c0abc3c845579d 100644 --- a/config/locales/bg.yml +++ b/config/locales/bg.yml @@ -226,6 +226,7 @@ bg: update_custom_emoji: ĐĐ±Đ½Đ¾Đ²ÑĐ²Đ°Đ½Đµ Đ½Đ° Đ¿ĐµÑ€ÑĐ¾Đ½Đ°Đ»Đ¸Đ·Đ¸Ñ€Đ°Đ½Đ¾Ñ‚Đ¾ ĐµĐ¼Đ¾Đ´Đ¶Đ¸ update_domain_block: ĐĐ±Đ½Đ¾Đ²ÑĐ²Đ°Đ½Đµ Đ½Đ° Đ±Đ»Đ¾ĐºĐ¸Ñ€Đ°Đ½ĐµÑ‚Đ¾ Đ·Đ° Đ´Đ¾Đ¼ĐµĐ¹Đ½Đ° update_ip_block: ĐĐ±Đ½Đ¾Đ²ÑĐ²Đ°Đ½Đµ Đ½Đ° Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ¾ Đ·Đ° IP + update_report: ĐĐ±Đ½Đ¾Đ²ÑĐ²Đ°Đ½Đµ Đ½Đ° Đ´Đ¾ĐºĐ»Đ°Đ´Đ° update_status: ĐĐ±Đ½Đ¾Đ²ÑĐ²Đ°Đ½Đµ Đ½Đ° Đ¿ÑƒĐ±Đ»Đ¸ĐºĐ°Ñ†Đ¸Ñ update_user_role: ĐĐ±Đ½Đ¾Đ²ÑĐ²Đ°Đ½Đµ Đ½Đ° Ñ€Đ¾Đ»ÑÑ‚Đ° actions: @@ -638,6 +639,7 @@ bg: report: 'Đ”Đ¾ĐºĐ»Đ°Đ´Đ²Đ°Đ½Đµ Đ½Đ° #%{id}' reported_account: Đ”Đ¾ĐºĐ»Đ°Đ´Đ²Đ°Đ½ Đ°ĐºĐ°ÑƒĐ½Ñ‚ reported_by: Đ”Đ¾ĐºĐ»Đ°Đ´Đ²Đ°Đ½Đ¾ Đ¾Ñ‚ + reported_with_application: Đ”Đ¾ĐºĐ»Đ°Đ´Đ²Đ°Đ½Đ¾ Ñ Đ¿Ñ€Đ¸Đ»Đ¾Đ¶ĐµĐ½Đ¸ĐµÑ‚Đ¾ resolved: Đ Đ°Đ·Ñ€ĐµÑˆĐµĐ½Đ¾ resolved_msg: Đ£ÑĐ¿ĐµÑˆĐ½Đ¾ Ñ€Đ°Đ·Ñ€ĐµÑˆĐµĐ½ Đ´Đ¾ĐºĐ»Đ°Đ´! skip_to_actions: ĐŸÑ€ĐµÑĐºĐ¾Đº ĐºÑĐ¼ Đ´ĐµĐ¹ÑÑ‚Đ²Đ¸Ñ diff --git a/config/locales/ca.yml b/config/locales/ca.yml index f892df02c1e689..4d0e2ab389d2a4 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -226,6 +226,7 @@ ca: update_custom_emoji: Actualitza l'emoji personalitzat update_domain_block: Actualitza el Bloqueig de Domini update_ip_block: Actualitza norma IP + update_report: Actualitza l'informe update_status: Actualitza l'estat update_user_role: Actualitza Rol actions: @@ -638,6 +639,7 @@ ca: report: 'Informe #%{id}' reported_account: Compte denunciat reported_by: Denunciat per + reported_with_application: Reportat amb l'aplicaciĂ³ resolved: Resolt resolved_msg: Informe resolt correctament! skip_to_actions: Salta a les accions diff --git a/config/locales/cs.yml b/config/locales/cs.yml index 20e7e4d46b81d5..7e0aaaeefb6fe3 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -118,7 +118,7 @@ cs: promote: PovĂ½Å¡it protocol: Protokol public: VeÅ™ejnĂ½ - push_subscription_expires: OdebĂ­rĂ¡nĂ­ PuSH expiruje + push_subscription_expires: OdebĂ­rĂ¡nĂ­ PuSH vyprÅ¡Ă­ redownload: Obnovit profil redownloaded_msg: Profil ĂºÄtu %{username} byl ĂºspěšnÄ› obnoven ze zdroje reject: ZamĂ­tnout diff --git a/config/locales/cy.yml b/config/locales/cy.yml index 35ed5ade8aa913..cd48b3e3b0ec2f 100644 --- a/config/locales/cy.yml +++ b/config/locales/cy.yml @@ -305,6 +305,7 @@ cy: filter_by_action: Hidlo yn Ă´l gweithred filter_by_user: Hidlo yn Ă´l defnyddiwr title: Cofnod archwilio + unavailable_instance: "(nid yw enw'r parth ar gael)" announcements: destroyed_msg: Cyhoeddiad wedi'i ddileu'n llwyddiannus! edit: @@ -1436,7 +1437,7 @@ cy: domain_blocking_html: Rydych ar fin rhwystro hyd at %{total_items} parth o %{filename} . following_html: Rydych ar fin dilyn hyd at %{total_items} cyfrif gan %{filename} . lists_html: Rydych ar fin ychwanegu hyd at %{total_items} o gyfrifon o %{filename} at eich rhestrau . Bydd rhestrau newydd yn cael eu creu os nad oes rhestr i ychwanegu ati. - muting_html: Rydych ar fin tewi hyd at %{total_items} cyfrif o %{filename} . + muting_html: Rydych ar fin anwybyddu hyd at %{total_items} cyfrif o %{filename}. preface: Gallwch fewnforio data rydych chi wedi'i allforio o weinydd arall, fel rhestr o'r bobl rydych chi'n eu dilyn neu'n eu blocio. recent_imports: Mewnforion diweddar states: @@ -1529,9 +1530,9 @@ cy: too_many: Methu atodi mwy na 4 ffeil migrations: acct: Symudwyd i - cancel: Diddymu ailgyfeirio - cancel_explanation: Bydd diddymu'r ailgyfeiriad yn ail agor eich cyfrif cyfredol, ond ni fydd yn dod Ă¢ dilynwyr sydd wedi'u symud i'r cyfrif hwnnw yn Ă´l. - cancelled_msg: Wedi diddymu'r ailgyfeiriad yn llwyddiannus. + cancel: Canslo ailgyfeirio + cancel_explanation: Bydd canslo'r ailgyfeiriad yn ail agor eich cyfrif cyfredol, ond ni fydd yn dod Ă¢ dilynwyr sydd wedi'u symud i'r cyfrif hwnnw yn Ă´l. + cancelled_msg: Wedi canslo'r ailgyfeiriad yn llwyddiannus. errors: already_moved: yw'r un cyfrif rydych chi wedi symud iddo eisoes missing_also_known_as: nid yw'n arallenw o'r cyfrif hwn diff --git a/config/locales/da.yml b/config/locales/da.yml index fc7373cc94c700..75da9a0b363fdf 100644 --- a/config/locales/da.yml +++ b/config/locales/da.yml @@ -226,6 +226,7 @@ da: update_custom_emoji: OpdatĂ©r tilpasset emoji update_domain_block: OpdatĂ©r domæneblokering update_ip_block: OpdatĂ©r IP-regel + update_report: OpdatĂ©r anmeldelse update_status: OpdatĂ©r indlæg update_user_role: OpdatĂ©r rolle actions: diff --git a/config/locales/de.yml b/config/locales/de.yml index 82ed9d8178c3d5..81b7cd172d64fb 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -226,6 +226,7 @@ de: update_custom_emoji: Eigenes Emoji aktualisieren update_domain_block: Domain-Sperre aktualisieren update_ip_block: IP-Regel aktualisieren + update_report: Meldung aktualisieren update_status: Beitrag aktualisieren update_user_role: Rolle bearbeiten actions: @@ -638,6 +639,7 @@ de: report: "%{id}. Meldung" reported_account: Gemeldetes Konto reported_by: Gemeldet von + reported_with_application: Per App gemeldet resolved: Geklärt resolved_msg: Meldung erfolgreich geklärt! skip_to_actions: Zur MaĂŸnahme springen diff --git a/config/locales/devise.cy.yml b/config/locales/devise.cy.yml index 523ae70b049c4a..b41e12f85d69fd 100644 --- a/config/locales/devise.cy.yml +++ b/config/locales/devise.cy.yml @@ -93,7 +93,7 @@ cy: updated: Mae eich cyfrinair wedi'i newid yn llwyddiannus. Rydych chi bellach wedi mewngofnodi. updated_not_active: Mae eich cyfrinair wedi ei newid yn llwyddiannus. registrations: - destroyed: Hwyl fawr! Mae eich cyfrif wedi ei ddiddymu'n llwyddiannus. Gobeithiwn eich gweld chi eto'n fuan. + destroyed: Hwyl fawr! Mae eich cyfrif wedi ei chanslo'n llwyddiannus. Gobeithiwn eich gweld chi eto'n fuan. signed_up: Croeso! Rydych wedi cofrestru'n llwyddiannus. signed_up_but_inactive: Yr ydych wedi cofrestru'n llwyddiannus. Fodd bynnag, ni allwn eich mewngofnodi achos nid yw eich cyfrif wedi ei hagor eto. signed_up_but_locked: Rydych chi wedi cofrestru'n llwyddiannus. Fodd bynnag, ni allem eich mewngofnodi oherwydd bod eich cyfrif wedi'i gloi. diff --git a/config/locales/devise.ga.yml b/config/locales/devise.ga.yml index 6e6bd0a01360b3..cc8ae0874ea816 100644 --- a/config/locales/devise.ga.yml +++ b/config/locales/devise.ga.yml @@ -11,19 +11,114 @@ ga: invalid: "%{authentication_keys} nĂ³ pasfhocal neamhbhailĂ­." last_attempt: TĂ¡ iarracht amhĂ¡in eile agat sula gcuirtear do chuntas faoi ghlas. locked: TĂ¡ do chuntas faoi ghlas. + not_found_in_database: "%{authentication_keys} nĂ³ pasfhocal neamhbhailĂ­." + omniauth_user_creation_failure: EarrĂ¡id agus cuntas Ă¡ chruthĂº don aitheantas seo. pending: TĂ¡ do chuntas fĂ³s faoi athbhreithniĂº. + timeout: Chuaigh do sheisiĂºn in Ă©ag. LogĂ¡il isteach arĂ­s chun leanĂºint ar aghaidh. unauthenticated: NĂ­ mĂ³r duit lĂ³gĂ¡il isteach nĂ³ sĂ­niĂº suas roimh leanĂºint leat. unconfirmed: Caithfidh tĂº do r-phost a dheimhniĂº roimh leanĂºint leat. mailer: confirmation_instructions: action: Deimhnigh seoladh r-phost action_with_app: Deimhnigh agus fill ar %{app} + explanation: TĂ¡ cuntas cruthaithe agat ar %{host} leis an seoladh rĂ­omhphoist seo. TĂ¡ tĂº ceann cliceĂ¡il ar shiĂºl Ă³ Ă© a ghnĂ­omhachtĂº. Mura tusa a bhĂ­ ann, dĂ©an neamhaird den rĂ­omhphost seo le do thoil. + explanation_when_pending: Chuir tĂº isteach ar chuireadh chuig %{host} leis an seoladh rĂ­omhphoist seo. Nuair a dheimhnĂ­onn tĂº do sheoladh r-phoist, dĂ©anfaimid athbhreithniĂº ar d’iarratas. Is fĂ©idir leat logĂ¡il isteach chun do shonraĂ­ a athrĂº nĂ³ chun do chuntas a scriosadh, ach nĂ­ fĂ©idir leat rochtain a fhĂ¡il ar fhormhĂ³r na bhfeidhmeanna go dtĂ­ go mbeidh do chuntas faofa. MĂ¡ dhiĂºltaĂ­tear do d’iarratas, bainfear do shonraĂ­, mar sin nĂ­ bheidh aon ghnĂ­omh eile ag teastĂ¡il uait. Mura tusa a bhĂ­ ann, dĂ©an neamhaird den rĂ­omhphost seo le do thoil. + extra_html: SeiceĂ¡il freisin rialacha an fhreastalaĂ­ agus Ă¡r dtĂ©armaĂ­ seirbhĂ­se. + subject: 'Mastodon: Treoracha dearbhaithe do %{instance}' + title: FĂ­oraigh seoladh rĂ­omhphoist email_changed: + explanation: 'TĂ¡ seoladh rĂ­omhphoist do chuntais Ă¡ athrĂº go:' + extra: Murar athraigh tĂº do rĂ­omhphost, is dĂ³cha go bhfuil rochtain faighte ag duine Ă©igin ar do chuntas. Athraigh do phasfhocal lĂ¡ithreach le do thoil nĂ³ dĂ©an teagmhĂ¡il le riarthĂ³ir an fhreastalaĂ­ mĂ¡ tĂ¡ tĂº glasĂ¡ilte amach as do chuntas. + subject: 'Mastodon: AthraĂ­odh an rĂ­omhphost' title: Seoladh rĂ­omhphoist nua password_change: + explanation: AthraĂ­odh an pasfhocal do do chuntas. + extra: Murar athraigh tĂº do phasfhocal, is dĂ³cha go bhfuil rochtain faighte ag duine Ă©igin ar do chuntas. Athraigh do phasfhocal lĂ¡ithreach le do thoil nĂ³ dĂ©an teagmhĂ¡il le riarthĂ³ir an fhreastalaĂ­ mĂ¡ tĂ¡ tĂº glasĂ¡ilte amach as do chuntas. + subject: 'Mastodon: AthraĂ­odh an pasfhocal' title: Pasfhocal athraithe + reconfirmation_instructions: + explanation: Deimhnigh an seoladh nua chun do rĂ­omhphost a athrĂº. + extra: Murar tusa a thionscain an t-athrĂº seo, dĂ©an neamhaird den rĂ­omhphost seo le do thoil. NĂ­ athrĂ³far seoladh rĂ­omhphoist an chuntais Mastodon go dtĂ­ go bhfaighidh tĂº rochtain ar an nasc thuas. + subject: 'Mastodon: Deimhnigh rĂ­omhphost le haghaidh %{instance}' + title: FĂ­oraigh seoladh rĂ­omhphoist reset_password_instructions: action: Athraigh pasfhocal + explanation: D'iarr tĂº pasfhocal nua do do chuntas. + extra: Murar iarr tĂº Ă© seo, dĂ©an neamhaird den rĂ­omhphost seo le do thoil. NĂ­ athrĂ³far do phasfhocal go dtĂ­ go bhfaighidh tĂº rochtain ar an nasc thuas agus go gcruthĂ³idh tĂº ceann nua. + subject: 'Mastodon: Athshocraigh treoracha pasfhocail' + title: AthshocrĂº pasfhocal + two_factor_disabled: + explanation: Is fĂ©idir logĂ¡il isteach anois ach ĂºsĂ¡id a bhaint as seoladh rĂ­omhphoist agus pasfhocal amhĂ¡in. + subject: 'Mastodon: DĂ­chumasaĂ­odh fĂ­ordheimhniĂº dhĂ¡ fhachtĂ³ir' + subtitle: DĂ­chumasaĂ­odh fĂ­ordheimhniĂº dhĂ¡-fhachtĂ³ir do do chuntas. + title: 2FA dĂ­chumasaithe + two_factor_enabled: + explanation: Beidh comhartha ginte ag an aip TOTP pĂ©ireĂ¡ilte ag teastĂ¡il chun logĂ¡il isteach. + subject: 'Mastodon: FĂ­ordheimhniĂº dhĂ¡-fhachtĂ³ir cumasaithe' + subtitle: CumasaĂ­odh fĂ­ordheimhniĂº dhĂ¡ fhachtĂ³ir do do chuntas. + title: 2FA cumasaithe + two_factor_recovery_codes_changed: + explanation: TĂ¡ na cĂ³id athshlĂ¡naithe roimhe seo neamhbhailĂ­ agus gineadh cinn nua. + subject: 'Mastodon: CĂ³id aisghabhĂ¡la dhĂ¡-fhachtĂ³ir athghinte' + subtitle: TĂ¡ na cĂ³id athshlĂ¡naithe roimhe seo neamhbhailĂ­ agus gineadh cinn nua. + title: AthraĂ­odh cĂ³id aisghabhĂ¡la 2FA + unlock_instructions: + subject: 'Mastodon: DĂ­ghlasĂ¡il treoracha' + webauthn_credential: + added: + explanation: Cuireadh an eochair shlĂ¡ndĂ¡la seo a leanas le do chuntas + subject: 'Mastodon: Eochair shlĂ¡ndĂ¡la nua' + title: TĂ¡ eochair shlĂ¡ndĂ¡la nua curtha leis + deleted: + explanation: Scriosadh an eochair shlĂ¡ndĂ¡la seo a leanas Ă³ do chuntas + subject: 'Mastodon: Scriosadh an eochair shlĂ¡ndĂ¡la' + title: Scriosadh ceann de d'eochracha slĂ¡ndĂ¡la + webauthn_disabled: + explanation: DĂ­chumasaĂ­odh fĂ­ordheimhniĂº le heochracha slĂ¡ndĂ¡la do do chuntas. + extra: Is fĂ©idir logĂ¡il isteach anois ag baint ĂºsĂ¡ide as an comhartha a ghineann an aip TOTP pĂ©ireĂ¡ilte amhĂ¡in. + subject: 'Mastodon: DĂ­chumasaĂ­odh fĂ­ordheimhniĂº le heochracha slĂ¡ndĂ¡la' + title: Eochracha slĂ¡ndĂ¡la dĂ­chumasaithe + webauthn_enabled: + explanation: CumasaĂ­odh fĂ­ordheimhniĂº eochair shlĂ¡ndĂ¡la do do chuntas. + extra: Is fĂ©idir d'eochair shlĂ¡ndĂ¡la a ĂºsĂ¡id le logĂ¡il isteach anois. + subject: 'Mastodon: FĂ­ordheimhniĂº eochair shlĂ¡ndĂ¡la cumasaithe' + title: Eochracha slĂ¡ndĂ¡la cumasaithe + omniauth_callbacks: + failure: NĂ­orbh fhĂ©idir tĂº a fhĂ­ordheimhniĂº Ă³ %{kind} toisc "%{reason}". + success: D'Ă©irigh le fĂ­ordheimhniĂº Ă³ chuntas %{kind}. + passwords: + no_token: NĂ­ fĂ©idir leat rochtain a fhĂ¡il ar an leathanach seo gan teacht Ă³ rĂ­omhphost athshocraithe pasfhocail. MĂ¡ thagann tĂº Ă³ rĂ­omhphost athshocraithe pasfhocail, cinntigh le do thoil gur ĂºsĂ¡id tĂº an URL iomlĂ¡n a cuireadh ar fĂ¡il. + send_instructions: MĂ¡ tĂ¡ do sheoladh rĂ­omhphoist inĂ¡r mbunachar sonraĂ­, gheobhaidh tĂº nasc athshlĂ¡naithe pasfhocail ag do sheoladh rĂ­omhphoist i gceann cĂºpla nĂ³imĂ©ad. SeiceĂ¡il d'fhillteĂ¡n turscair mura bhfuair tĂº an rĂ­omhphost seo. + send_paranoid_instructions: MĂ¡ tĂ¡ do sheoladh rĂ­omhphoist inĂ¡r mbunachar sonraĂ­, gheobhaidh tĂº nasc athshlĂ¡naithe pasfhocail ag do sheoladh rĂ­omhphoist i gceann cĂºpla nĂ³imĂ©ad. SeiceĂ¡il d'fhillteĂ¡n turscair mura bhfuair tĂº an rĂ­omhphost seo. + updated: AthraĂ­odh do phasfhocal go rathĂºil. TĂ¡ tĂº sĂ­nithe isteach anois. + updated_not_active: Your password has been changed successfully. + registrations: + destroyed: SlĂ¡n! CealaĂ­odh do chuntas go rathĂºil. TĂ¡ sĂºil againn tĂº a fheiceĂ¡il arĂ­s go luath. + signed_up: FĂ¡ilte romhat! D'Ă©irigh leat sĂ­niĂº suas. + signed_up_but_inactive: D'Ă©irigh leat sĂ­niĂº suas. Mar sin fĂ©in, nĂ­orbh fhĂ©idir linn tĂº a shĂ­niĂº isteach toisc nach bhfuil do chuntas gnĂ­omhachtaithe fĂ³s. + signed_up_but_locked: D'Ă©irigh leat sĂ­niĂº suas. Mar sin fĂ©in, nĂ­orbh fhĂ©idir linn tĂº a shĂ­niĂº isteach toisc go bhfuil do chuntas glasĂ¡ilte. + signed_up_but_pending: TĂ¡ teachtaireacht le nasc deimhnithe seolta chuig do sheoladh rĂ­omhphoist. Tar Ă©is duit an nasc a chliceĂ¡il, dĂ©anfaimid athbhreithniĂº ar d’iarratas. Cuirfear in iĂºl duit mĂ¡ cheadaĂ­tear Ă©. + signed_up_but_unconfirmed: TĂ¡ teachtaireacht le nasc deimhnithe seolta chuig do sheoladh rĂ­omhphoist. Lean an nasc chun do chuntas a ghnĂ­omhachtĂº. SeiceĂ¡il d'fhillteĂ¡n turscair mura bhfuair tĂº an rĂ­omhphost seo. + update_needs_confirmation: D'Ă©irigh leat do chuntas a nuashonrĂº, ach caithfimid do sheoladh rĂ­omhphoist nua a fhĂ­orĂº. SeiceĂ¡il do rĂ­omhphost agus lean an nasc dearbhaithe chun do sheoladh rĂ­omhphoist nua a dhearbhĂº. SeiceĂ¡il d'fhillteĂ¡n turscair mura bhfuair tĂº an rĂ­omhphost seo. + updated: D'Ă©irigh le do chuntas a nuashonrĂº. + sessions: + already_signed_out: D'Ă©irigh le sĂ­niĂº amach. + signed_in: D'Ă©irigh le sĂ­niĂº isteach. + signed_out: D'Ă©irigh le sĂ­niĂº amach. + unlocks: + send_instructions: Gheobhaidh tĂº rĂ­omhphost le treoracha maidir le conas do chuntas a dhĂ­ghlasĂ¡il i gceann cĂºpla nĂ³imĂ©ad. SeiceĂ¡il d'fhillteĂ¡n turscair mura bhfuair tĂº an rĂ­omhphost seo. + send_paranoid_instructions: MĂ¡ tĂ¡ do chuntas ann, gheobhaidh tĂº rĂ­omhphost le treoracha maidir le conas Ă© a dhĂ­ghlasĂ¡il i gceann cĂºpla nĂ³imĂ©ad. SeiceĂ¡il d'fhillteĂ¡n turscair mura bhfuair tĂº an rĂ­omhphost seo. + unlocked: DĂ­ghlasĂ¡ladh do chuntas go rathĂºil. LogĂ¡il isteach le do thoil chun leanĂºint ar aghaidh. errors: messages: + already_confirmed: deimhnĂ­odh cheana fĂ©in, bain triail as sĂ­niĂº isteach + confirmation_period_expired: nĂ­ mĂ³r Ă© a dhearbhĂº laistigh de %{period}, iarr ceann nua le do thoil + expired: imithe in Ă©ag, iarr ceann nua le do thoil not_found: nĂ­or aimsĂ­odh Ă© + not_locked: nach raibh faoi ghlas + not_saved: + few: 'Chuir %{count} earrĂ¡id cosc ​​ar an %{resource} seo a shĂ¡bhĂ¡il:' + many: 'Chuir %{count} earrĂ¡id cosc ​​ar an %{resource} seo a shĂ¡bhĂ¡il:' + one: 'Chuir earrĂ¡id 1 cosc ​​ar an %{resource} seo a shĂ¡bhĂ¡il:' + other: 'Chuir %{count} earrĂ¡id cosc ​​ar an %{resource} seo a shĂ¡bhĂ¡il:' + two: 'Chuir %{count} earrĂ¡id cosc ​​ar an %{resource} seo a shĂ¡bhĂ¡il:' diff --git a/config/locales/devise.kab.yml b/config/locales/devise.kab.yml index 438c1df2b9a46f..3fbc58c1f57fcb 100644 --- a/config/locales/devise.kab.yml +++ b/config/locales/devise.kab.yml @@ -12,6 +12,7 @@ kab: last_attempt: Γur-k yiwen n uÉ›raá¸-nniá¸en kan send ad yettucekkel umiá¸an-ik. locked: Amiá¸an-ik yettwargel. not_found_in_database: Tella tuccá¸a deg %{authentication_keys} neγ deg wawal uffir. + omniauth_user_creation_failure: Tuccá¸a lawan n tmerna n umiá¸an i timagit-a. pending: Amiá¸an-inek mazal-it deg É›iwed n tmuγli. timeout: TiÉ£imit n tuqqna tezri. Ma ulac aÉ£ilif É›iwed tuqqna akken ad tkemmleá¸. unauthenticated: Ilaq ad teqqneḠneÉ£ ad tjerrá¸eḠakken ad tkemmelá¸. @@ -47,21 +48,41 @@ kab: subject: 'Mastodon: Iwellihen n uwennez n wawal uffir' title: AÉ›iwed n wawal uffir two_factor_disabled: + explanation: Tuqqna tella tura s useqdec n tansa n yimayl tasuft d wawal n uεeddi. subject: 'Mastodon: Asesteb s snat n tarrayin yensa' + subtitle: Asesteb s snat tarrayin i umiá¸an-ik yensan. title: Asesteb s snat n tarrayin insa two_factor_enabled: + explanation: Ajuá¹­u yettusirwen s usnas TOTP yeqqnen ilaq i wakken ad teqqneá¸. subject: 'Mastodon: Asesteb s snat n tarrayin yermed' + subtitle: Asesteb s snat tarrayin yettwarmed i umiá¸an-ik. title: Asesteb s snat n tarrayin irmed two_factor_recovery_codes_changed: explanation: Tangalt n tuÉ£alin tettwaḥbes sakin nesnulfa-d yiwet d tamaynut. subject: 'Mastodon: Tingalin n tuÉ£alin n snat n tarayin ttwarnanat i tikkelt-nniá¸en' + subtitle: Tangalt n tuÉ£alin tettwaḥbes sakin nesnulfa-d yiwet d tamaynut. title: Tangalt n tuÉ£alin 2FA tettwabeddel unlock_instructions: subject: 'Mastodon: iwelihhen n userreḥ' webauthn_credential: added: + explanation: Tasarut-a n tÉ£ellist tettwarna É£er umiá¸an-ik·im subject: 'Maṣṭudun : Tasarutt tamaynutt n tÉ£ellist' title: Tasarut tamaynutt n tÉ£ellist tamaynut tettwarna + deleted: + explanation: Tasarut-a n tÉ£ellist tettwakkes seg umiá¸an-ik·im + subject: 'Mastodon: Tasarut n tÉ£ellsit tettwakkes' + title: Yiwet seg tsura-k·m n tÉ£ellist tettwakkes + webauthn_disabled: + explanation: Yensa usesteb s tsura n tÉ£ellist i umiá¸an-ik. + extra: TzemreḠad tkecmeḠtura s useqdec asuf n ujuá¹­u yettwasran s usnas TOPTP yeqqnen. + subject: 'Mastodon: Asesteb s tsura n tÉ£ellist yensa' + title: Tisura n tÉ£ellist nsant + webauthn_enabled: + explanation: Asesteb n tsarut n tÉ£ellist tettwarmed i umiá¸an-ik. + extra: Tasarut-ik n tÉ£ellist tezmer tura ad tettuseqdec i unekcum. + subject: 'Mastodon: Asesteb n tsarut n tÉ£ellist yermed' + title: Tisura n tÉ£ellist remdent omniauth_callbacks: failure: Ur nezmir ara ad ak·akem-nsesá¹­eb seg %{kind} acku "%{reason}". success: Asesá¹­eb idda akken iwata seg umiá¸an %{kind}. diff --git a/config/locales/devise.nl.yml b/config/locales/devise.nl.yml index ab6ae84db4d229..662401a57a679a 100644 --- a/config/locales/devise.nl.yml +++ b/config/locales/devise.nl.yml @@ -75,7 +75,7 @@ nl: title: Een van jouw beveiligingssleutels is verwijderd webauthn_disabled: explanation: Verificatie met beveiligingssleutels is uitgeschakeld voor je account. - extra: Het is nu alleen mogelijk om in te loggen met een door de authenticatie-app gegeneerde toegangscode. + extra: Het is nu alleen mogelijk om in te loggen met een door de authenticatie-app gegeneerde toegangscode als extra controle. subject: 'Mastodon: Verificatie met beveiligingssleutels is uitgeschakeld' title: Beveiligingssleutels uitgeschakeld webauthn_enabled: diff --git a/config/locales/devise.zh-TW.yml b/config/locales/devise.zh-TW.yml index 7ead831e4f75aa..3e3af9f323997c 100644 --- a/config/locales/devise.zh-TW.yml +++ b/config/locales/devise.zh-TW.yml @@ -75,7 +75,7 @@ zh-TW: title: 您ç„一支安全密鑰已經被移除 webauthn_disabled: explanation: 您ç„帳號已åœç”¨å®‰å…¨é‡‘é‘°èº«ä»½é©—è­‰ă€‚ - extra: ç¾åœ¨åƒ…å¯ä½¿ç”¨é…å°ç„ TOTP 應用程å¼ç”¢ç”Ÿä¹‹ token ç™»å…¥ă€‚ + extra: ç›®å‰åƒ…å¯ä½¿ç”¨é…å°ç„ TOTP 應用程å¼ç”¢ç”Ÿä¹‹ token ç™»å…¥ă€‚ subject: Mastodonï¼å®‰å…¨å¯†é‘°èªè­‰æ–¹å¼å·²åœç”¨ title: å·²åœç”¨å®‰å…¨å¯†é‘° webauthn_enabled: @@ -90,7 +90,7 @@ zh-TW: no_token: 您必須é€é密碼é‡è¨­ä¿¡ä»¶æ‰èƒ½å­˜å–æ­¤é é¢ă€‚若確實如此,請確å®è¼¸å…¥ç„網å€æ˜¯å®Œæ•´ç„。 send_instructions: 若電å­éƒµä»¶åœ°å€å­˜åœ¨æ–¼æˆ‘們ç„資料庫,幾分é˜å¾Œæ‚¨å°‡æ–¼ä¿¡ç®±ä¸­æ”¶åˆ°å¯†ç¢¼å¾©åŸé€£çµă€‚若未收到請檢查åƒåœ¾éƒµä»¶è³‡æ–™å¤¾ă€‚ send_paranoid_instructions: 若電å­éƒµä»¶åœ°å€å­˜åœ¨æ–¼æˆ‘們ç„資料庫,幾分é˜å¾Œæ‚¨å°‡æ–¼ä¿¡ç®±ä¸­æ”¶åˆ°å¯†ç¢¼å¾©åŸé€£çµă€‚若未收到請檢查åƒåœ¾éƒµä»¶è³‡æ–™å¤¾ă€‚ - updated: 您ç„密碼已æˆåŸè®æ›´ï¼Œç¾åœ¨å·²ç¶“ç™»å…¥ă€‚ + updated: 您ç„密碼已æˆåŸè®æ›´ï¼Œæ‚¨ç¾åœ¨å·²ç¶“æˆåŸç™»å…¥ă€‚ updated_not_active: 您ç„密碼已æˆåŸè®æ›´ă€‚ registrations: destroyed: å†è¦‹ï¼æ‚¨ç„帳號已æˆåŸå–消,期待å†ç›¸é€¢ă€‚ diff --git a/config/locales/doorkeeper.cy.yml b/config/locales/doorkeeper.cy.yml index e79aa0359f67b8..e023bc060312c8 100644 --- a/config/locales/doorkeeper.cy.yml +++ b/config/locales/doorkeeper.cy.yml @@ -20,7 +20,7 @@ cy: applications: buttons: authorize: Awdurdodi - cancel: Diddymu + cancel: Canslo destroy: Dinistrio edit: Golygu submit: Cyflwyno @@ -72,7 +72,7 @@ cy: revoke: Ydych chi'n siŵr? index: authorized_at: Wedi'i awdurdodi ar %{date} - description_html: Mae'r rhain yn raglenni sy'n gallu cael mynediad i'ch cyfrif gan ddefnyddio'r API. Os oes yna rhaglenni nad ydych chi'n eu hadnabod yma, neu os yw rhaglen yn camymddwyn, gallwch chi ddiddymu ei fynediad. + description_html: Mae'r rhain yn raglenni sy'n gallu cael mynediad i'ch cyfrif gan ddefnyddio'r API. Os oes yna rhaglenni nad ydych chi'n eu hadnabod yma, neu os yw rhaglen yn camymddwyn, gallwch chi ddirymu ei fynediad. last_used_at: Defnyddiwyd ddiwethaf ar %{date} never_used: Erioed wedi'i ddefnyddio scopes: CaniatĂ¢d @@ -83,7 +83,7 @@ cy: access_denied: Mae perchennog yr adnodd neu'r gweinydd awdurdodi wedi atal y cais. credential_flow_not_configured: Llif meini prawf cyfrinair perchennog yr adnodd wedi methu achos fod Doorkeeper.configure.resource_owner_from_credentials heb ei ffurfweddu. invalid_client: Methodd dilysu cleient oherwydd cleient anhysbys, dim dilysiad cleient wedi'i gynnwys, neu ddull dilysu heb ei gefnogi. - invalid_grant: Mae'r grant awdurdodi ar yr amod yn annilys, wedi dod i ben, wedi'i ddiddymu, nid yw'n cyfateb i'r URI ailgyfeirio a ddefnyddiwyd yn y cais am awdurdodiad, neu wedi'i roi i gleient arall. + invalid_grant: Mae'r grant awdurdodi ar yr amod yn annilys, wedi dod i ben, wedi'i ddirymu, nid yw'n cyfateb i'r URI ailgyfeirio a ddefnyddiwyd yn y cais am awdurdodiad, neu wedi'i roi i gleient arall. invalid_redirect_uri: Nid yw'r uri ailgyfeirio a gynhwysir yn ddilys. invalid_request: missing_param: 'Paramedr gofynnol ar goll: %{value}.' @@ -135,6 +135,7 @@ cy: media: Atodiadau cyfryngau mutes: Anwybyddiadau notifications: Hysbysiadau + profile: Eich proffil Mastodon push: Hysbysiadau gwthiadwy reports: Adroddiadau search: Chwilio @@ -165,6 +166,7 @@ cy: admin:write:reports: cyflawni camau cymedroli ar adroddiadau crypto: defnyddio amgryptio ben i ben follow: addasu perthnasau cyfrif + profile: darllen dim ond gwybodaeth proffil eich cyfrif push: derbyn eich hysbysiadau gwthiadwy read: darllen holl ddata eich cyfrif read:accounts: gweld gwybodaeth y cyfrif diff --git a/config/locales/doorkeeper.ga.yml b/config/locales/doorkeeper.ga.yml index a263a6b15dc529..09857768e39744 100644 --- a/config/locales/doorkeeper.ga.yml +++ b/config/locales/doorkeeper.ga.yml @@ -5,7 +5,17 @@ ga: doorkeeper/application: name: Ainm feidhmchlĂ¡ir redirect_uri: Atreoraigh URI + scopes: ScĂ³ip website: SuĂ­omh grĂ©asĂ¡in feidhmchlĂ¡ir + errors: + models: + doorkeeper/application: + attributes: + redirect_uri: + fragment_present: nĂ­ fĂ©idir blĂºire a bheith ann. + invalid_uri: caithfidh gur URI bailĂ­ Ă©. + relative_uri: a bheith ina URI iomlĂ¡n. + secured_uri: caithfidh gur URI HTTPS/SSL Ă©. doorkeeper: applications: buttons: @@ -16,36 +26,172 @@ ga: submit: Cuir isteach confirmations: destroy: An bhfuil tĂº cinnte? + edit: + title: Cuir feidhmchlĂ¡r in eagar + form: + error: Ăps! SeiceĂ¡il d'fhoirm le haghaidh earrĂ¡idĂ­ fĂ©ideartha + help: + native_redirect_uri: ĂsĂ¡id %{native_redirect_uri} le haghaidh tĂ¡stĂ¡lacha logĂ¡nta + redirect_uri: ĂsĂ¡id lĂ­ne amhĂ¡in in aghaidh an URI + scopes: ScĂ³ipeanna ar leith le spĂ¡sanna. FĂ¡g bĂ¡n chun na scĂ³ip rĂ©amhshocraithe a ĂºsĂ¡id. index: application: Ainm feidhmchlĂ¡ir + callback_url: URL aisghlaoch delete: Scrios + empty: NĂ­l aon iarratais agat. name: Ainm + new: FeidhmchlĂ¡r nua + scopes: ScĂ³ip show: TaispeĂ¡in + title: D'iarratais + new: + title: FeidhmchlĂ¡r nua show: + actions: GnĂ­omhartha application_id: Eochair chliaint + callback_urls: URLanna aisghlaoch + scopes: ScĂ³ip secret: RĂºn cliaint title: 'Ainm feidhmchlĂ¡ir: %{name}' authorizations: buttons: authorize: Ceadaigh deny: DiĂºltaigh + error: + title: Tharla earrĂ¡id + new: + prompt_html: Ba mhaith le %{client_name} cead rochtain a fhĂ¡il ar do chuntas. Is iarratas trĂ­Ăº pĂ¡irtĂ­ Ă©. Mura bhfuil muinĂ­n agat as, nĂ­or cheart duit Ă© a ĂºdarĂº. + review_permissions: Ceadanna a athbhreithniĂº + title: TĂ¡ ĂºdarĂº ag teastĂ¡il + show: + title: CĂ³ipeĂ¡il an cĂ³d Ăºdaraithe seo agus greamaigh don fheidhmchlĂ¡r Ă©. authorized_applications: + buttons: + revoke: CĂºlghair confirmations: revoke: An bhfuil tĂº cinnte? index: + authorized_at: Ceadaithe ar %{date} + description_html: Is feidhmchlĂ¡ir iad seo ar fĂ©idir rochtain a fhĂ¡il ar do chuntas leis an API. MĂ¡ tĂ¡ feidhmchlĂ¡ir ann nach n-aithnĂ­onn tĂº anseo, nĂ³ mĂ¡ tĂ¡ feidhmchlĂ¡r mĂ­-iompair, is fĂ©idir leat a rochtain a chĂºlghairm. + last_used_at: ĂsĂ¡idte an uair dheireanach ar %{date} + never_used: NĂ¡ hĂºsĂ¡ideadh scopes: Ceadanna superapp: InmheĂ¡nach + title: D’iarratais Ăºdaraithe + errors: + messages: + access_denied: ShĂ©an ĂºinĂ©ir na hacmhainne nĂ³ an freastalaĂ­ Ăºdaraithe an t-iarratas. + credential_flow_not_configured: Theip ar shreabhadh DintiĂºir Pasfhocal ĂinĂ©ir Acmhainne toisc go raibh Doorkeeper.configure.resource_owner_from_credentials dĂ­chumraithe. + invalid_client: Theip ar fhĂ­ordheimhniĂº cliant de bharr cliant anaithnid, nĂ­l fĂ­ordheimhniĂº cliant san Ă¡ireamh, nĂ³ modh fĂ­ordheimhnithe nach dtacaĂ­tear leis. + invalid_grant: TĂ¡ an deonĂº Ăºdaraithe ar choinnĂ­oll neamhbhailĂ­, imithe in Ă©ag, cĂºlghairthe, nach ionann Ă© agus an URI atreoraithe a ĂºsĂ¡ideadh san iarratas ar ĂºdarĂº, nĂ³ gur eisĂ­odh Ă© chuig cliant eile. + invalid_redirect_uri: NĂ­l an uri atreoraithe atĂ¡ san Ă¡ireamh bailĂ­. + invalid_request: + missing_param: 'ParaimĂ©adar riachtanach in easnamh: %{value}.' + request_not_authorized: NĂ­ mĂ³r an t-iarratas a ĂºdarĂº. TĂ¡ an paraimĂ©adar riachtanach chun iarratas a ĂºdarĂº in easnamh nĂ³ neamhbhailĂ­. + unknown: TĂ¡ paraimĂ©adar riachtanach in easnamh ar an iarratas, folaĂ­onn sĂ© luach paraimĂ©adar nach dtacaĂ­tear leis, nĂ³ tĂ¡ sĂ© mĂ­chumtha ar shlĂ­ eile. + invalid_resource_owner: NĂ­l na dintiĂºir ĂºinĂ©ara acmhainne a solĂ¡thraĂ­odh bailĂ­, nĂ³ nĂ­ fĂ©idir ĂºinĂ©ir na hacmhainne a aimsiĂº + invalid_scope: TĂ¡ an scĂ³ip iarrtha neamhbhailĂ­, anaithnid nĂ³ mĂ­chumtha. + invalid_token: + expired: Chuaigh an comhartha rochtana in Ă©ag + revoked: CĂºlghairmeadh an comhartha rochtana + unknown: TĂ¡ an comhartha rochtana neamhbhailĂ­ + resource_owner_authenticator_not_configured: Theip ar aimsiĂº ĂinĂ©ir Acmhainne toisc go bhfuil Doorkeeper.configure.resource_owner_authenticator dĂ­chumraithe. + server_error: ThĂ¡inig an freastalaĂ­ Ăºdaraithe ar riocht gan choinne a chuir cosc ​​air an t-iarratas a chomhlĂ­onadh. + temporarily_unavailable: NĂ­ fĂ©idir leis an bhfreastalaĂ­ Ăºdaraithe an t-iarratas a lĂ¡imhseĂ¡il mar gheall ar rĂ³-ualĂº sealadach nĂ³ cothabhĂ¡il an fhreastalaĂ­. + unauthorized_client: NĂ­l an cliant Ăºdaraithe an t-iarratas seo a dhĂ©anamh leis an modh seo. + unsupported_grant_type: NĂ­ thacaĂ­onn an freastalaĂ­ Ăºdaraithe leis an gcineĂ¡l deontais Ăºdaraithe. + unsupported_response_type: NĂ­ thacaĂ­onn an freastalaĂ­ Ăºdaraithe leis an gcineĂ¡l freagartha seo. + flash: + applications: + create: + notice: CruthaĂ­odh feidhmchlĂ¡r. + destroy: + notice: Scriosadh an feidhmchlĂ¡r. + update: + notice: FeidhmchlĂ¡r nuashonraithe. + authorized_applications: + destroy: + notice: CĂºlghairmeadh an t-iarratas. grouped_scopes: + access: + read: Rochtain inlĂ©ite-amhĂ¡in + read/write: LĂ©igh agus scrĂ­obh rochtain + write: Rochtain scrĂ­ofa-amhĂ¡in title: accounts: Cuntais + admin/accounts: Cuntas a riar + admin/all: Feidhmeanna riarachĂ¡in go lĂ©ir + admin/reports: TuarascĂ¡lacha a riar + all: Rochtain iomlĂ¡n ar do chuntas Mastodon + blocks: Bloic bookmarks: Leabharmharcanna conversations: ComhrĂ¡ite + crypto: CriptiĂº ceann-go-deireadh + favourites: CeanĂ¡in filters: ScagairĂ­ + follow: Leanann, MĂºchann agus BlocĂ¡lann follows: Cuntais leanta lists: LiostaĂ­ + media: CeangaltĂ¡in meĂ¡n + mutes: MĂºchann notifications: FĂ³graĂ­ + profile: Do phrĂ³ifĂ­l Mastodon + push: FĂ³graĂ­ a bhrĂº + reports: TuarascĂ¡lacha search: Cuardaigh statuses: PostĂ¡lacha + layouts: + admin: + nav: + applications: FeidhmchlĂ¡ir + oauth2_provider: SolĂ¡thraĂ­ OAuth2 + application: + title: TĂ¡ ĂºdarĂº OAuth riachtanach scopes: + admin:read: lĂ©igh na sonraĂ­ go lĂ©ir ar an bhfreastalaĂ­ + admin:read:accounts: faisnĂ©is Ă­ogair na gcuntas go lĂ©ir a lĂ©amh + admin:read:canonical_email_blocks: lĂ©igh faisnĂ©is Ă­ogair ar gach bloc rĂ­omhphoist canĂ³nach + admin:read:domain_allows: lĂ©igh faisnĂ©is Ă­ogair gach fearainn + admin:read:domain_blocks: lĂ©igh faisnĂ©is Ă­ogair gach bloc fearainn + admin:read:email_domain_blocks: lĂ©igh faisnĂ©is Ă­ogair gach bloc fearainn rĂ­omhphoist + admin:read:ip_blocks: lĂ©igh faisnĂ©is Ă­ogair gach bloic IP + admin:read:reports: faisnĂ©is Ă­ogair na dtuarascĂ¡lacha agus na gcuntas tuairiscithe go lĂ©ir a lĂ©amh + admin:write: na sonraĂ­ go lĂ©ir ar an bhfreastalaĂ­ a mhodhnĂº + admin:write:accounts: gnĂ­omhartha modhnĂ³ireachta a dhĂ©anamh ar chuntais + admin:write:canonical_email_blocks: gnĂ­omhartha modhnĂ³ireachta a dhĂ©anamh ar bhlocanna rĂ­omhphoist chanĂ³nacha + admin:write:domain_allows: gnĂ­omhartha modhnĂ³ireachta a dhĂ©anamh ar cheadaĂ­onn fearainn + admin:write:domain_blocks: gnĂ­omhartha modhnĂ³ireachta a dhĂ©anamh ar bhlocanna fearainn + admin:write:email_domain_blocks: gnĂ­omhartha modhnĂ³ireachta a dhĂ©anamh ar bhlocanna fearainn rĂ­omhphoist + admin:write:ip_blocks: gnĂ­omhartha modhnĂ³ireachta a dhĂ©anamh ar bhlocanna IP + admin:write:reports: gnĂ­omhartha modhnĂ³ireachta a dhĂ©anamh ar thuarascĂ¡lacha + crypto: ĂºsĂ¡id criptiĂº ceann-go-ceann + follow: caidrimh chuntais a mhodhnĂº + profile: lĂ©igh faisnĂ©is phrĂ³ifĂ­le do chuntais amhĂ¡in + push: faigh do bhrĂºfhĂ³graĂ­ + read: lĂ©igh sonraĂ­ do chuntais go lĂ©ir + read:accounts: fĂ©ach eolas cuntais + read:blocks: fĂ©ach ar do bloic + read:bookmarks: fĂ©ach ar do leabharmharcanna + read:favourites: fĂ©ach ar do cheanĂ¡in + read:filters: fĂ©ach ar do chuid scagairĂ­ + read:follows: fĂ©ach do chuid seo a leanas + read:lists: fĂ©ach ar do liostaĂ­ + read:mutes: fĂ©ach ar do bhalbh + read:notifications: fĂ©ach ar do chuid fĂ³graĂ­ + read:reports: fĂ©ach ar do thuarascĂ¡lacha + read:search: cuardach ar do shon + read:statuses: fĂ©ach ar gach post + write: sonraĂ­ do chuntais go lĂ©ir a mhodhnĂº + write:accounts: do phrĂ³ifĂ­l a mhodhnĂº + write:blocks: cuntais agus fearainn a bhlocĂ¡il + write:bookmarks: poist leabharmharcĂ¡la + write:conversations: comhrĂ¡ite balbh agus scrios + write:favourites: poist is fearr leat write:filters: cruthaigh scagairĂ­ + write:follows: daoine a leanĂºint write:lists: cruthaigh liostaĂ­ + write:media: uaslĂ³dĂ¡il comhaid meĂ¡in + write:mutes: balbhaigh daoine agus comhrĂ¡ite + write:notifications: soilĂ©ir do chuid fĂ³graĂ­ + write:reports: tuairisc a thabhairt do dhaoine eile + write:statuses: foilsigh poist diff --git a/config/locales/doorkeeper.kab.yml b/config/locales/doorkeeper.kab.yml index 1b1a7df957645f..33aecd8c6f03d7 100644 --- a/config/locales/doorkeeper.kab.yml +++ b/config/locales/doorkeeper.kab.yml @@ -5,6 +5,7 @@ kab: doorkeeper/application: name: Isem n usnas redirect_uri: URI n uwelleh + scopes: Tinerfadin website: Asmel web n usnas errors: models: @@ -39,6 +40,7 @@ kab: empty: Ulac É£ur-k·m isnasen. name: Isem new: Asnas amaynut + scopes: Tinerfadin show: Ẓer title: Isnasen-ik·im new: @@ -47,6 +49,8 @@ kab: actions: Tigawin application_id: ID n usnas callback_urls: URL n tririt n wawal + scopes: Tinerfadin + secret: Tuffirt n umsaÉ£ title: 'Asnas: %{name}' authorizations: buttons: @@ -55,6 +59,7 @@ kab: error: title: Tella-d tuccá¸a new: + review_permissions: Asenqed n tsirag title: Tlaq tsiregt show: title: NÉ£el tangalt n wurag sakkin senteá¸-itt deg usnas. @@ -64,8 +69,12 @@ kab: confirmations: revoke: Tetḥeqqeá¸? index: + authorized_at: Yettwasireg É£ef %{date} description_html: Ha-t-an yisnasen i izemren ad kecmen É£er umiá¸an-ik·im, s useqdec n API. Ma llan yisnasen ur teεqileḠara da, neÉ£ kra n wesnas ur iteddu ara akken ilaq, tzemreḠad tekkseḠanekcum-is. last_used_at: Yettwaseqdec i tikkelt taneggarut ass n %{date} + never_used: Urǧin yettwaseqdac + scopes: Tisirag + superapp: Adigan title: Isnasen-ik·im yettusirgen errors: messages: @@ -82,13 +91,28 @@ kab: destroy: notice: Yettwaḥwi wesnas. grouped_scopes: + access: + read: Anekcum i tÉ£uri kan + read/write: Anekcum i tÉ£uri d tira + write: Anekcum i tira kan title: accounts: Imiá¸anen admin/accounts: Tadbelt n imiá¸an + admin/all: Akk timahilin tinebdalin + admin/reports: Tadbelt n yineqqisen + blocks: Yewḥel + bookmarks: TicraḠ+ conversations: Idiwenniyen crypto: Awgelhen seg yixef É£er yixef + favourites: Imenyafen filters: Imzizdigen + follow: Aá¸far, asgugem akked usewḥel + follows: Aá¸far lists: Tibdarin + media: Imeddayen n umidya + mutes: Yeggugem notifications: TilÉ£a + profile: AmaÉ£nu-k Mastodon push: TilÉ£a yettudemmren reports: Ineqqisen search: Nadi diff --git a/config/locales/doorkeeper.ko.yml b/config/locales/doorkeeper.ko.yml index 3ab0698d51c4ef..7ec357bf9fdec4 100644 --- a/config/locales/doorkeeper.ko.yml +++ b/config/locales/doorkeeper.ko.yml @@ -31,7 +31,7 @@ ko: form: error: ́´ëŸ°! ́˜¤ë¥˜ë¥¼ 확́¸í•˜́„¸́” help: - native_redirect_uri: "%{native_redirect_uri}́—́„œ ë¡œ́»¬ í…Œ́¤í¸ë¥¼ í•  ́ˆ˜ ́ˆ́µë‹ˆë‹¤." + native_redirect_uri: "%{native_redirect_uri}를 ́´́©í•´ ë¡œ́»¬ í…Œ́¤í¸ë¥¼ í•  ́ˆ˜ ́ˆ́µë‹ˆë‹¤" redirect_uri: í•œ ́¤„́— 하나́˜ URI를 ́‘́„±í•˜́„¸́” scopes: ́¤í˜́´́¤ë¡œ ë²”́œ„를 구분하́„¸́”. 빈 ́¹¸́œ¼ë¡œ 놔ë‘ë©´ 기본 ë²”́œ„를 ́‚¬́©í•©ë‹ˆë‹¤. index: diff --git a/config/locales/doorkeeper.lv.yml b/config/locales/doorkeeper.lv.yml index 5aa5daef3f6d16..11c50203050e4c 100644 --- a/config/locales/doorkeeper.lv.yml +++ b/config/locales/doorkeeper.lv.yml @@ -25,7 +25,7 @@ lv: edit: Labot submit: ApstiprinÄt confirmations: - destroy: Vai esi pÄrliecinÄts? + destroy: Vai tieÅ¡Äm? edit: title: Labot lietotni form: @@ -69,7 +69,7 @@ lv: buttons: revoke: Atsaukt confirmations: - revoke: Vai esi pÄrliecinÄts? + revoke: Vai tieÅ¡Äm? index: authorized_at: AutorizÄ“tas %{date} description_html: Å Ä«s ir lietotnes, kas var piekļūt Tavam kontam ar API. Ja Å¡eit ir lietotnes, kuras neatpazÄ«sti, vai lietotne darbojas ne tÄ, kÄ paredzÄ“ts, vari atsaukt tÄs piekļuvi. @@ -135,6 +135,7 @@ lv: media: Multividesu pielikumi mutes: ApklusinÄtie notifications: Paziņojumi + profile: Tavs Mastodon profils push: UznirstoÅ¡ie paziņojumi reports: Ziņojumi search: MeklÄ“t @@ -165,6 +166,7 @@ lv: admin:write:reports: veikt moderÄcijas darbÄ«bas pÄrskatos crypto: lieto pilnÄ«gu Å¡ifrÄ“Å¡anu follow: mainÄ«t konta attiecÄ«bas + profile: lasÄ«t tikai Tava konta profila informÄciju push: saņemt savus push paziņojumus read: lasÄ«t visus sava konta datus read:accounts: apskatÄ«t kontu informÄciju diff --git a/config/locales/doorkeeper.nl.yml b/config/locales/doorkeeper.nl.yml index 4115e0a17eb341..0a3d8fd081a81d 100644 --- a/config/locales/doorkeeper.nl.yml +++ b/config/locales/doorkeeper.nl.yml @@ -129,7 +129,7 @@ nl: crypto: End-to-end-encryptie favourites: Favorieten filters: Filters - follow: Volgers, genegeerde en geblokkeerde gebruikers + follow: Gevolgde, genegeerde en geblokkeerde gebruikers follows: Volgend lists: Lijsten media: Mediabijlagen diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml index 928823b995b674..a45ba290b74a20 100644 --- a/config/locales/en-GB.yml +++ b/config/locales/en-GB.yml @@ -226,6 +226,7 @@ en-GB: update_custom_emoji: Update Custom Emoji update_domain_block: Update Domain Block update_ip_block: Update IP rule + update_report: Update Report update_status: Update Post update_user_role: Update Role actions: diff --git a/config/locales/en.yml b/config/locales/en.yml index 20df80c272fb12..cccb1721634353 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -226,6 +226,7 @@ en: update_custom_emoji: Update Custom Emoji update_domain_block: Update Domain Block update_ip_block: Update IP rule + update_report: Update Report update_status: Update Post update_user_role: Update Role actions: @@ -638,6 +639,7 @@ en: report: 'Report #%{id}' reported_account: Reported account reported_by: Reported by + reported_with_application: Reported with application resolved: Resolved resolved_msg: Report successfully resolved! skip_to_actions: Skip to actions diff --git a/config/locales/es-AR.yml b/config/locales/es-AR.yml index fda1566e22c478..8c55551ce06320 100644 --- a/config/locales/es-AR.yml +++ b/config/locales/es-AR.yml @@ -226,6 +226,7 @@ es-AR: update_custom_emoji: Actualizar emoji personalizado update_domain_block: Actualizar bloque de dominio update_ip_block: Actualizar regla de direcciĂ³n IP + update_report: Actualizar denuncia update_status: Actualizar mensaje update_user_role: Actualizar rol actions: diff --git a/config/locales/fi.yml b/config/locales/fi.yml index be87258daf22bb..2d10250f68e134 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -226,6 +226,7 @@ fi: update_custom_emoji: Päivitä mukautettu emoji update_domain_block: Päivitä verkkotunnuksen esto update_ip_block: Päivitä IP-sääntö + update_report: Päivitä raportti update_status: Päivitä julkaisu update_user_role: Päivitä rooli actions: diff --git a/config/locales/fo.yml b/config/locales/fo.yml index 945a2216a3d6ba..6a5401ced4882f 100644 --- a/config/locales/fo.yml +++ b/config/locales/fo.yml @@ -226,6 +226,7 @@ fo: update_custom_emoji: Dagfør Sergjørt Kenslutekn update_domain_block: Dagfør Domain forĂ°ing update_ip_block: Dagfør IP reglur + update_report: Dagfør frĂ¡greiĂ°ing update_status: Dagfør Uppslag update_user_role: Dagfør Leiklut actions: @@ -638,6 +639,7 @@ fo: report: 'Melding #%{id}' reported_account: MeldaĂ° konta reported_by: MeldaĂ° av + reported_with_application: FrĂ¡boĂ°aĂ° viĂ° umsĂ³kn resolved: Loyst resolved_msg: Melding avgreidd! skip_to_actions: Leyp til atgerĂ°ir diff --git a/config/locales/ga.yml b/config/locales/ga.yml index a3ad293e5bd79d..370f3e82e62ed4 100644 --- a/config/locales/ga.yml +++ b/config/locales/ga.yml @@ -3,13 +3,24 @@ ga: about: about_mastodon_html: 'LĂ­onra sĂ³isialta a sheasfaidh an aimsir: Gan fĂ³graĂ­ocht, gan faire chorparĂ¡ideach, le leagan amach eiticiĂºil agus dĂ­lĂ¡rĂº. BĂ­odh do chuid sonraĂ­ agatsa fĂ©in le Mastodon!' contact_missing: Gan socrĂº - contact_unavailable: N/B + contact_unavailable: N/A hosted_on: Mastodon arna Ă³stĂ¡il ar %{domain} title: Maidir le accounts: follow: Lean + followers: + few: LeantĂ³irĂ­ + many: LeantĂ³irĂ­ + one: LeantĂ³ir + other: LeantĂ³irĂ­LeantĂ³irĂ­ + two: LeantĂ³irĂ­ following: Ag leanĂºint + instance_actor_flash: Is gnĂ­omhaĂ­ fĂ­orĂºil Ă© an cuntas seo a ĂºsĂ¡idtear chun an freastalaĂ­ fĂ©in agus nĂ­ aon ĂºsĂ¡ideoir aonair a lĂ©iriĂº. ĂsĂ¡idtear Ă© chun crĂ­ocha cĂ³naidhme agus nĂ­or cheart Ă© a chur ar fionraĂ­. + last_active: deireanach gnĂ­omhach + link_verified_on: SeiceĂ¡ladh ĂºinĂ©ireacht an naisc seo ar %{date} nothing_here: NĂ­l rud ar bith anseo! + pin_errors: + following: NĂ­ mĂ³r duit a bheith ag leanĂºint an duine is mian leat a fhormhuiniĂº cheana fĂ©in posts: few: PostĂ¡lacha many: PostĂ¡lacha @@ -23,12 +34,17 @@ ga: title: Dean gnĂ­omh modhnĂ³ireachta ar %{acct} account_moderation_notes: create: FĂ¡g nĂ³ta + created_msg: CruthaĂ­odh nĂ³ta modhnĂ³ireachta go rathĂºil! + destroyed_msg: NĂ³ta measarthachta scriosta go rathĂºil! accounts: + add_email_domain_block: Cuir bac ar fhearann ​​​​rĂ­omhphoist approve: Faomh + approved_msg: D'Ă©irigh le feidhmchlĂ¡r sĂ­nithe %{username} a cheadĂº are_you_sure: An bhfuil tĂº cinnte? avatar: AbhatĂ¡r by_domain: Fearann change_email: + changed_msg: D'Ă©irigh leis an rĂ­omhphost a athrĂº! current_email: RĂ­omhphost reatha label: Athraigh rĂ­omhphost new_email: RĂ­omhphost nua @@ -46,7 +62,9 @@ ga: delete: Scrios sonraĂ­ deleted: Scriosta demote: Ăsligh + destroyed_msg: TĂ¡ sonraĂ­ %{username} ciĂºĂ¡ilte anois le scriosadh gan mhoill disable: Reoigh + disable_sign_in_token_auth: DĂ­chumasaigh fĂ­ordheimhniĂº comhartha r-phoist disable_two_factor_authentication: DĂ­chumasaigh 2FA disabled: Reoite display_name: Ainm taispeĂ¡na @@ -55,22 +73,31 @@ ga: email: RĂ­omhphost email_status: StĂ¡das rĂ­omhphoist enable: DĂ­-reoigh + enable_sign_in_token_auth: Cumasaigh fĂ­ordheimhniĂº comhartha rĂ­omhphoist enabled: Ar chumas + enabled_msg: D'Ă©irigh le dĂ­-reoite cuntas %{username} followers: LeantĂ³irĂ­ follows: Ag leanĂºint header: CeanntĂ¡sc + inbox_url: URL an Bhosca Isteach + invite_request_text: CĂºiseanna le bheith pĂ¡irteach + invited_by: Ar cuireadh Ă³ ip: IP joined: ClĂ¡raithe location: all: Uile local: ĂitiĂºil remote: Cian + title: SuĂ­omh login_status: StĂ¡das logĂ¡la isteach + media_attachments: CeangaltĂ¡in meĂ¡n memorialize: DĂ©an cuntas chuimhneachĂ¡in de memorialized: Cuntas chuimhneachĂ¡in + memorialized_msg: D'Ă©irigh le %{username} a iompĂº ina chuntas cuimhneachĂ¡in moderation: active: GnĂ­omhach all: Uile + disabled: Faoi mhĂ­chumas pending: Ar feitheamh silenced: Teoranta suspended: Ar fionraĂ­ @@ -78,111 +105,389 @@ ga: moderation_notes: NĂ³taĂ­ modhnĂ³ireacht most_recent_activity: GnĂ­omhaĂ­ocht is dĂ©anaĂ­ most_recent_ip: IP is dĂ©anaĂ­ + no_account_selected: NĂ­or athraĂ­odh aon chuntas mar nĂ­or roghnaĂ­odh ceann ar bith + no_limits_imposed: NĂ­ fhorchuirtear aon teorainneacha + no_role_assigned: NĂ­l aon rĂ³l sannta + not_subscribed: Gan suibscrĂ­ofa + pending: AthbhreithniĂº ar feitheamh perform_full_suspension: FionraĂ­ previous_strikes: Cionta roimhe seo + previous_strikes_description_html: + few: TĂ¡ %{count} buailte ag an gcuntas seo. + many: TĂ¡ %{count} buailte ag an gcuntas seo. + one: TĂ¡ buail amhĂ¡in ag an gcuntas seo. + other: TĂ¡ %{count} buailte ag an gcuntas seo. + two: TĂ¡ %{count} buailte ag an gcuntas seo. promote: Ardaigh protocol: PrĂ³tacal public: PoiblĂ­ + push_subscription_expires: TĂ©ann sĂ­ntiĂºs PuSH in Ă©ag redownload: Athnuaigh prĂ³ifĂ­l + redownloaded_msg: D'Ă©irigh le hathnuachan prĂ³ifĂ­l %{username} Ă³n mbunĂºs reject: DiĂºltaigh + rejected_msg: D'Ă©irigh le diĂºltĂº le feidhmchlĂ¡r sĂ­nithe %{username} + remote_suspension_irreversible: Scriosadh sonraĂ­ an chuntais seo go do-aisiompaithe. + remote_suspension_reversible_hint_html: Cuireadh an cuntas ar fionraĂ­ ar a fhreastalaĂ­, agus bainfear na sonraĂ­ go hiomlĂ¡n ar %{date}. Go dtĂ­ sin, is fĂ©idir leis an gcianfhreastalaĂ­ an cuntas seo a chur ar ais gan aon drochĂ©ifeachtaĂ­. MĂ¡s mian leat sonraĂ­ uile an chuntais a bhaint lĂ¡ithreach, is fĂ©idir leat Ă© sin a dhĂ©anamh thĂ­os. remove_avatar: Bain abhatĂ¡r remove_header: Bain ceanntĂ¡sc + removed_avatar_msg: D'Ă©irigh leis an Ă­omhĂ¡ avatar %{username} a bhaint + removed_header_msg: D'Ă©irigh le hĂ­omhĂ¡ ceanntĂ¡sc %{username} a bhaint + resend_confirmation: + already_confirmed: TĂ¡ an t-ĂºsĂ¡ideoir seo deimhnithe cheana fĂ©in + send: Seol an nasc deimhnithe arĂ­s + success: D'Ă©irigh le nasc deimhnithe seolta! reset: Athshocraigh reset_password: Athshocraigh pasfhocal resubscribe: AthchlĂ¡raigh role: RĂ³l search: Cuardaigh + search_same_email_domain: ĂsĂ¡ideoirĂ­ eile a bhfuil an fearann ​​rĂ­omhphoist cĂ©anna acu + search_same_ip: ĂsĂ¡ideoirĂ­ eile a bhfuil an IP cĂ©anna acu + security: SlĂ¡ndĂ¡il security_measures: only_password: Pasfhocal amhĂ¡in password_and_2fa: Pasfhocal agus fĂ­ordheimhniĂº dĂ©shraithe + sensitive: FĂ³rsa-Ă­ogair sensitized: MarcĂ¡ladh mar Ă­ogair + shared_inbox_url: URL an bhosca isteach roinnte + show: + created_reports: TuarascĂ¡lacha dĂ©anta + targeted_reports: Thuairiscigh daoine eile silence: Teorannaigh silenced: Teoranta statuses: PostĂ¡lacha + strikes: Stailceanna roimhe seo subscribe: ClĂ¡raigh suspend: Cuir ar fionraĂ­ suspended: Ar fionraĂ­ + suspension_irreversible: Scriosadh sonraĂ­ an chuntais seo go do-aisiompaithe. Is fĂ©idir leat an cuntas a chur ar fionraĂ­ chun Ă© a dhĂ©anamh inĂºsĂ¡idte ach nĂ­ dhĂ©anfaidh sĂ© aon sonraĂ­ a bhĂ­ aige roimhe seo a aisghabhĂ¡il. + suspension_reversible_hint_html: TĂ¡ an cuntas curtha ar fionraĂ­, agus bainfear na sonraĂ­ go hiomlĂ¡n ar %{date}. Go dtĂ­ sin, is fĂ©idir an cuntas a chur ar ais gan aon drochthionchar. MĂ¡s mian leat sonraĂ­ uile an chuntais a bhaint lĂ¡ithreach, is fĂ©idir leat Ă© sin a dhĂ©anamh thĂ­os. title: Cuntais + unblock_email: Bain an bac den seoladh rĂ­omhphoist + unblocked_email_msg: D'Ă©irigh leis an mbac a bhain le seoladh rĂ­omhphoist %{username} + unconfirmed_email: RĂ­omhphost neamhdheimhnithe + undo_sensitized: Cealaigh fĂ³rsa-Ă­ogair + undo_silenced: Cealaigh teorainn + undo_suspension: Cealaigh fionraĂ­ + unsilenced_msg: D'Ă©irigh leis an teorainn chuntas %{username} a bhaint + unsubscribe: DĂ­liostĂ¡il + unsuspended_msg: D'Ă©irigh le dĂ­fhorlannĂº cuntas %{username} username: Ainm ĂºsĂ¡ideora + view_domain: FĂ©ach ar achoimre le haghaidh fearainn warn: Rabhadh a thabhairt web: GrĂ©asĂ¡n + whitelisted: Ceadaithe do chĂ³naidhm action_logs: action_types: + approve_appeal: Achomharc a cheadĂº + approve_user: ĂsĂ¡ideoir a cheadĂº assigned_to_self_report: Sann Tuairisc + change_email_user: Athraigh RĂ­omhphost don ĂsĂ¡ideoir + change_role_user: AthrĂº RĂ³l an ĂsĂ¡ideora + confirm_user: Deimhnigh ĂsĂ¡ideoir create_account_warning: Cruthaigh Rabhadh + create_announcement: Cruthaigh FĂ³gra + create_canonical_email_block: Cruthaigh Bloc RĂ­omhphoist + create_custom_emoji: Cruthaigh Emoji Saincheaptha + create_domain_allow: Cruthaigh Ceadaigh Fearainn + create_domain_block: Cruthaigh Bloc Fearainn + create_email_domain_block: Cruthaigh Bloc Fearainn RĂ­omhphoist create_ip_block: Cruthaigh riail IP + create_unavailable_domain: Cruthaigh Fearann ​​Gan FĂ¡il create_user_role: Cruthaigh RĂ³l demote_user: Ăsligh ĂºsĂ¡ideoir destroy_announcement: Scrios FĂ³gra + destroy_canonical_email_block: Scrios Bloc RĂ­omhphoist + destroy_custom_emoji: Scrios Saincheaptha Emoji + destroy_domain_allow: Scrios Ceadaigh Fearainn + destroy_domain_block: Scrios Bloc Fearainn + destroy_email_domain_block: Scrios Bloc Fearainn R-phoist + destroy_instance: Fearann ​​Purge destroy_ip_block: Scrios riail IP destroy_status: Scrios PostĂ¡il + destroy_unavailable_domain: Scrios Fearann ​​Gan FĂ¡il destroy_user_role: Scrios rĂ³l + disable_2fa_user: DĂ­chumasaigh 2FA + disable_custom_emoji: DĂ­chumasaigh Emoji Saincheaptha + disable_sign_in_token_auth_user: DĂ­chumasaigh FĂ­ordheimhniĂº Comhartha R-phoist don ĂsĂ¡ideoir + disable_user: DĂ­chumasaigh ĂsĂ¡ideoir + enable_custom_emoji: Cumasaigh Emoji Saincheaptha + enable_sign_in_token_auth_user: Cumasaigh FĂ­ordheimhniĂº Comhartha R-phoist don ĂsĂ¡ideoir + enable_user: Cumasaigh ĂsĂ¡ideoir + memorialize_account: Cuntas CuimhneachĂ¡in + promote_user: ĂsĂ¡ideoir a chur chun cinn + reject_appeal: DiĂºltaigh Achomharc + reject_user: DiĂºltaigh ĂsĂ¡ideoir remove_avatar_user: Bain AbhatĂ¡r reopen_report: Athoscail tuairisc + resend_user: Seol RĂ­omhphost Deimhnithe arĂ­s reset_password_user: Athshocraigh Pasfhocal resolve_report: RĂ©itigh tuairisc + sensitive_account: Cuntas Ăogair FĂ³rsa + silence_account: Cuntas Teorainn + suspend_account: Cuntas a FhionraĂ­ unassigned_report: DĂ­shann Tuairisc + unblock_email_account: Bain an bac den seoladh rĂ­omhphoist + unsensitive_account: Cealaigh Cuntas Ăogair FĂ³rsa + unsilence_account: Cealaigh an Cuntas Teorainn + unsuspend_account: DĂ­ghlasĂ¡il Cuntas update_announcement: Nuashonraigh FĂ³gra + update_custom_emoji: Nuashonraigh Emoji Saincheaptha + update_domain_block: Nuashonraigh Emoji Saincheaptha + update_ip_block: ĂoslĂ³dĂ¡il an riail IP + update_report: Tuairisc Nuashonraithe update_status: Nuashonraigh PostĂ¡il update_user_role: Nuashonraigh RĂ³l actions: + approve_appeal_html: Cheadaigh %{name} achomharc ar chinneadh modhnĂ³ireachta Ă³ %{target} + approve_user_html: Cheadaigh %{name} clĂ¡rĂº Ă³ %{target} + assigned_to_self_report_html: Shann %{name} tuairisc %{target} dĂ³ibh fĂ©in + change_email_user_html: D'athraigh %{name} seoladh rĂ­omhphoist ĂºsĂ¡ideora %{target} + change_role_user_html: D'athraigh %{name} rĂ³l %{target} + confirm_user_html: Dhearbhaigh %{name} seoladh rĂ­omhphoist ĂºsĂ¡ideora %{target} create_account_warning_html: Sheol %{name} rabhadh chuig %{target} + create_announcement_html: Chruthaigh %{name} fĂ³gra nua %{target} + create_canonical_email_block_html: Chuir %{name} bac ar rĂ­omhphost leis an hash %{target} + create_custom_emoji_html: D'uaslĂ³dĂ¡il %{name} emoji nua %{target} + create_domain_allow_html: Cheadaigh %{name} cĂ³naidhm le fearann ​​%{target} + create_domain_block_html: "%{name} fearann ​​bactha %{target}" + create_email_domain_block_html: Chuir %{name} bac ar fhearann ​​rĂ­omhphoist %{target} + create_ip_block_html: Chruthaigh %{name} riail don IP %{target} + create_unavailable_domain_html: Chuir %{name} deireadh leis an seachadadh chuig fearann ​​%{target} + create_user_role_html: Chruthaigh %{name} %{target} rĂ³l + demote_user_html: "%{name} ĂºsĂ¡ideoir scriosta %{target}" + destroy_announcement_html: "%{name} fĂ³gra scriosta %{target}" + destroy_canonical_email_block_html: "%{name} rĂ­omhphost dĂ­choiscthe leis an hash %{target}" + destroy_custom_emoji_html: Scriosadh %{name} emoji %{target} + destroy_domain_allow_html: DhiĂºltaigh %{name} cĂ³naidhm le fearann ​​%{target} + destroy_domain_block_html: "%{name} fearann ​​%{target} bainte de" + destroy_email_domain_block_html: "%{name} bain an bac den fhearann ​​rĂ­omhphoist %{target}" + destroy_instance_html: Glanadh %{name} fearann ​​%{target} + destroy_ip_block_html: "%{name} scriosta riail le haghaidh IP %{target}" + destroy_status_html: Bhain %{name} postĂ¡il le %{target} + destroy_unavailable_domain_html: D'athchrom %{name} ar an seachadadh chuig fearann ​​%{target} destroy_user_role_html: Scrios %{name} rĂ³l %{target} + disable_2fa_user_html: DhĂ­chumasaigh %{name} riachtanas dhĂ¡ fhachtĂ³ir don ĂºsĂ¡ideoir %{target} + disable_custom_emoji_html: DhĂ­chumasaigh %{name} emoji %{target} + disable_sign_in_token_auth_user_html: DhĂ­chumasaigh %{name} fĂ­ordheimhniĂº comhartha rĂ­omhphoist le haghaidh %{target} + disable_user_html: "%{name} logĂ¡il isteach dĂ­chumasaithe d'ĂºsĂ¡ideoir %{target}" + enable_custom_emoji_html: "%{name} emoji cumasaithe %{target}" + enable_sign_in_token_auth_user_html: Chuir %{name} fĂ­ordheimhniĂº comhartha rĂ­omhphoist ar chumas %{target} + enable_user_html: "%{name} logĂ¡il isteach cumasaithe don ĂºsĂ¡ideoir %{target}" + memorialize_account_html: Rinne %{name} cuntas %{target} a iompĂº ina leathanach cuimhneachĂ¡in + promote_user_html: Chuir %{name} ĂºsĂ¡ideoir %{target} chun cinn + reject_appeal_html: DhiĂºltaigh %{name} achomharc ar chinneadh modhnĂ³ireachta Ă³ %{target} + reject_user_html: DhiĂºltaigh %{name} sĂ­niĂº suas Ă³ %{target} + remove_avatar_user_html: Bhain %{name} avatar %{target} + reopen_report_html: D'athoscail %{name} tuairisc %{target} + resend_user_html: "%{name} athsheoladh rĂ­omhphost deimhnithe le haghaidh %{target}" + reset_password_user_html: Athshocraigh %{name} pasfhocal ĂºsĂ¡ideora %{target} + resolve_report_html: RĂ©itigh %{name} tuairisc %{target} + sensitive_account_html: MharcĂ¡il %{name} meĂ¡n %{target} mar Ă­ogair + silence_account_html: Chuir %{name} teorainn le cuntas %{target} + suspend_account_html: Chuir %{name} cuntas %{target} ar fionraĂ­ + unassigned_report_html: "%{name} tuairisc neamhshannta %{target}" + unblock_email_account_html: Bhain %{name} seoladh rĂ­omhphoist %{target} amach + unsensitive_account_html: "%{name} meĂ¡n %{target} gan mharcĂ¡il mar Ă­ogair" + unsilence_account_html: Chealaigh %{name} teorainn chuntas %{target} + unsuspend_account_html: NĂ­or chuir %{name} cuntas %{target} ar fionraĂ­ + update_announcement_html: "%{name} fĂ³gra nuashonraithe %{target}" + update_custom_emoji_html: "%{name} emoji nuashonraithe %{target}" + update_domain_block_html: "%{name} nuashonraithe bloc fearainn le haghaidh %{target}" + update_ip_block_html: D'athraigh %{name} riail an IP %{target} + update_report_html: "%{name} tuairisc nuashonraithe %{target}" + update_status_html: "%{name} postĂ¡il nuashonraithe faoi %{target}" update_user_role_html: D'athraigh %{name} rĂ³l %{target} deleted_account: cuntas scriosta + empty: NĂ­or aimsĂ­odh aon logaĂ­. + filter_by_action: Scag de rĂ©ir gnĂ­mh + filter_by_user: Scag de rĂ©ir ĂºsĂ¡ideora + title: Loga iniĂºchta + unavailable_instance: "(ainm fearainn ar fĂ¡il)" announcements: + destroyed_msg: D'Ă©irigh leis an bhfĂ³gra a scriosadh! edit: title: Cuir fĂ³gra in eagar + empty: NĂ­or aimsĂ­odh aon fhĂ³graĂ­. live: Beo new: create: Cruthaigh fĂ³gra title: FĂ³gra nua publish: Foilsigh + published_msg: D’éirigh leis an bhfĂ³gra a fhoilsiĂº! + scheduled_for: Sceidealta le haghaidh %{time} + scheduled_msg: TĂ¡ an fĂ³gra le foilsiĂº! title: FĂ³graĂ­ + unpublish: DĂ­fhoilsiĂº + unpublished_msg: D’éirigh leis an bhfĂ³gra neamhfhoilsithe! + updated_msg: D'Ă©irigh leis an bhfĂ³gra a nuashonrĂº! + critical_update_pending: NuashonrĂº criticiĂºil ar feitheamh custom_emojis: + assign_category: Sann catagĂ³ir by_domain: Fearann + copied_msg: CruthaĂ­odh cĂ³ip Ă¡itiĂºil den emoji go rathĂºil copy: CĂ³ipeĂ¡il + copy_failed_msg: NĂ­orbh fhĂ©idir cĂ³ip Ă¡itiĂºil den emoji sin a dhĂ©anamh create_new_category: Cruthaigh catagĂ³ir nua created_msg: CruthaĂ­odh emoji go rathĂºil! delete: Scrios destroyed_msg: Scriosadh emoji go rathĂºil! disable: DĂ­chumasaigh disabled: DĂ­chumasaithe + disabled_msg: D'Ă©irigh leis an emoji sin a dhĂ­chumasĂº emoji: Emoji enable: Cumasaigh enabled: Ar chumas + enabled_msg: D'Ă©irigh leis an emoji sin a chumasĂº + image_hint: PNG nĂ³ GIF suas go %{size} list: Liosta listed: Liostaithe + new: + title: Cuir emoji saincheaptha nua leis + no_emoji_selected: NĂ­or athraĂ­odh emojis ar bith mar nĂ­or roghnaĂ­odh ceann ar bith + not_permitted: NĂ­l cead agat an gnĂ­omh seo a dhĂ©anamh overwrite: ForscrĂ­obh + shortcode: GearrchĂ³d + shortcode_hint: 2 charachtar ar a laghad, gan ach carachtair alfa-uimhriĂºla agus bĂ©im ar leith + title: Emojis saincheaptha uncategorized: NeamhchatagĂ³irithe unlist: Neamhliostaigh unlisted: Neamhliostaithe + update_failed_msg: NĂ­orbh fhĂ©idir an emoji sin a nuashonrĂº + updated_msg: D'Ă©irigh le Emoji a nuashonrĂº! upload: UaslĂ³dĂ¡il dashboard: active_users: ĂºsĂ¡ideoirĂ­ gnĂ­omhacha + interactions: idirghnĂ­omhaĂ­ochtaĂ­ + media_storage: StĂ³rĂ¡il meĂ¡in new_users: ĂºsĂ¡ideoirĂ­ nua opened_reports: tuairiscĂ­ oscailte + pending_appeals_html: + few: "%{count} achomharc ar feitheamh" + many: "%{count} achomharc ar feitheamh" + one: "%{count} ar feitheamh achomhairc" + other: "%{count} achomharc ar feitheamh" + two: "%{count} achomharc ar feitheamh" + pending_reports_html: + few: "%{count} tuairiscĂ­ ar feitheamh" + many: "%{count} tuairiscĂ­ ar feitheamh" + one: "%{count} tuairisc ar feitheamh" + other: "%{count} tuairiscĂ­ ar feitheamh" + two: "%{count} tuairiscĂ­ ar feitheamh" + pending_tags_html: + few: "%{count} hashtags ar feitheamh" + many: "%{count} hashtags ar feitheamh" + one: "%{count} hashtag ar feitheamh" + other: "%{count} hashtags ar feitheamh" + two: "%{count} hashtags ar feitheamh" + pending_users_html: + few: "%{count} ĂºsĂ¡ideoirĂ­ ar feitheamh" + many: "%{count} ĂºsĂ¡ideoirĂ­ ar feitheamh" + one: "%{count} ĂºsĂ¡ideoir ar feitheamh" + other: "%{count} ĂºsĂ¡ideoirĂ­ ar feitheamh" + two: "%{count} ĂºsĂ¡ideoirĂ­ ar feitheamh" + resolved_reports: tuarascĂ¡lacha rĂ©itithe software: BogearraĂ­ + sources: FoinsĂ­ sĂ­nithe + space: ĂsĂ¡id spĂ¡is title: Deais + top_languages: Barr teangacha gnĂ­omhacha + top_servers: Barr freastalaithe gnĂ­omhacha website: SuĂ­omh GrĂ©asĂ¡in disputes: appeals: + empty: NĂ­or aimsĂ­odh aon achomharc. title: Achomhairc domain_allows: + add_new: Ceadaigh cĂ³naidhm leis an bhfearann + created_msg: CeadaĂ­odh fearann ​​don chĂ³naidhm go rathĂºil + destroyed_msg: DĂ­cheadaĂ­odh an fearann â€‹â€‹Ă³n gcĂ³naidhm export: EaspĂ³rtĂ¡il import: IompĂ³rtĂ¡il + undo: DĂ­cheadaigh cĂ³naidhm leis an bhfearann domain_blocks: + add_new: Cuir bloc fearainn nua leis + confirm_suspension: + cancel: Cealaigh + confirm: FionraĂ­ + permanent_action: MĂ¡ dhĂ©antar an fionraĂ­ a chealĂº, nĂ­ dhĂ©anfar aon sonraĂ­ nĂ³ gaol a athbhunĂº. + preamble_html: TĂ¡ tĂº ar tĂ­ %{domain} agus a fhofhearainn a chur ar fionraĂ­. + remove_all_data: Bainfidh sĂ© seo gach Ă¡bhar, meĂ¡n agus sonraĂ­ prĂ³ifĂ­le do chuntais an fhearainn seo de do fhreastalaĂ­. + stop_communication: Stopfaidh do fhreastalaĂ­ ag cumarsĂ¡id leis na freastalaithe seo. + title: Deimhnigh bloc fearainn le haghaidh %{domain} + undo_relationships: DĂ©anfaidh sĂ© seo aon ghaol leantach idir cuntais na bhfreastalaithe seo agus do chuid fĂ©in a chealĂº. + created_msg: TĂ¡ bloc fearainn Ă¡ phrĂ³iseĂ¡il anois + destroyed_msg: TĂ¡ an bloc fearainn cealaithe domain: Fearann + edit: Cuir bloc fearainn in eagar + existing_domain_block: Chuir tĂº teorainneacha nĂ­os dĂ©ine ar %{name} cheana fĂ©in. + existing_domain_block_html: Chuir tĂº teorainneacha nĂ­os dĂ©ine ar %{name} cheana fĂ©in, nĂ­ mĂ³r duit an bac a bhaint as ar dtĂºs. export: EaspĂ³rtĂ¡il import: IompĂ³rtĂ¡il new: + create: Cruthaigh bloc + hint: NĂ­ choiscfidh an bloc fearainn iontrĂ¡lacha cuntais a chruthĂº sa bhunachar sonraĂ­, ach cuirfidh sĂ© modhanna modhnĂ³ireachta sonracha i bhfeidhm go haisghnĂ­omhach agus go huathoibrĂ­och ar na cuntais sin. severity: + desc_html: DĂ©anfaidh Teorainn postĂ¡lacha Ă³ chuntais ag an bhfearann ​​seo dofheicthe d'aon duine nach bhfuil Ă¡ leanĂºint. Bainfidh FionraĂ­ gach Ă¡bhar, meĂ¡n agus sonraĂ­ prĂ³ifĂ­le do chuntais an fhearainn seo de do fhreastalaĂ­. ĂsĂ¡id Dada mĂ¡s mian leat comhaid meĂ¡n a dhiĂºltĂº. + noop: Dada silence: Teorannaigh suspend: Cuir ar fionraĂ­ + title: Bloc fearainn nua + no_domain_block_selected: NĂ­or athraĂ­odh aon bhloc fearainn mar nĂ­or roghnaĂ­odh ceann ar bith + not_permitted: NĂ­l cead agat an gnĂ­omh seo a dhĂ©anamh + obfuscate: Obfuscate ainm fearainn + obfuscate_hint: Cuir bac pĂ¡irteach ar an ainm fearainn sa liosta mĂ¡ tĂ¡ fĂ³graĂ­ocht ar an liosta teorainneacha fearainn cumasaithe + private_comment: TrĂ¡cht prĂ­obhĂ¡ideach + private_comment_hint: DĂ©an trĂ¡cht ar an teorannĂº fearainn seo le haghaidh ĂºsĂ¡id inmheĂ¡nach ag na modhnĂ³irĂ­. + public_comment: TrĂ¡cht poiblĂ­ + public_comment_hint: DĂ©an trĂ¡cht ar an teorannĂº fearainn seo don phobal i gcoitinne, mĂ¡ tĂ¡ fĂ³graĂ­ocht ar an liosta teorainneacha fearainn cumasaithe. + reject_media: DiĂºltaigh comhaid meĂ¡n + reject_media_hint: Baintear comhaid meĂ¡n atĂ¡ stĂ³rĂ¡ilte go hĂ¡itiĂºil agus diĂºltaĂ­onn sĂ© aon cheann a Ă­oslĂ³dĂ¡il amach anseo. NĂ­ bhaineann le fionraĂ­ + reject_reports: DiĂºltaigh tuarascĂ¡lacha + reject_reports_hint: DĂ©an neamhaird de gach tuairisc a thagann Ă³n bhfearann ​​seo. NĂ­ bhaineann le fionraĂ­ + undo: Cealaigh bloc fearainn + view: FĂ©ach ar bhloc fearainn email_domain_blocks: + add_new: Cuir nua leis + allow_registrations_with_approval: Ceadaigh clĂ¡rĂºchĂ¡in le ceadĂº + attempts_over_week: + few: "%{count} iarracht chun sĂ­niĂº suas le seachtain anuas" + many: "%{count} iarracht chun sĂ­niĂº suas le seachtain anuas" + one: "%{count} iarracht le seachtain anuas" + other: "%{count} iarracht chun sĂ­niĂº suas le seachtain anuas" + two: "%{count} iarracht chun sĂ­niĂº suas le seachtain anuas" + created_msg: D'Ă©irigh leis an bhfearann ​​rĂ­omhphoist a bhlocĂ¡il delete: Scrios + dns: + types: + mx: Taifead MX domain: Fearann + new: + create: Cuir fearann ​​leis + resolve: RĂ©itigh fearann + title: Cuir bac ar fhearann ​​​​r-phoist nua + no_email_domain_block_selected: NĂ­or athraĂ­odh aon bhloc fearainn rĂ­omhphoist mar nĂ­or roghnaĂ­odh ceann ar bith + not_permitted: NĂ­l sĂ© ceadaithe + resolved_dns_records_hint_html: RĂ©itĂ­onn an t-ainm fearainn chuig na fearainn MX seo a leanas, atĂ¡ freagrach sa deireadh as glacadh le rĂ­omhphost. MĂ¡ dhĂ©antar fearann ​​MX a bhlocĂ¡il, cuirfear bac ar chlĂ¡rĂºchĂ¡in Ă³ aon seoladh rĂ­omhphoist a ĂºsĂ¡ideann an fearann ​​MX cĂ©anna, fiĂº mĂ¡ tĂ¡ an t-ainm fearainn infheicthe difriĂºil. BĂ­ cĂºramach gan bac a chur ar phrĂ­omhsholĂ¡thraithe rĂ­omhphoist. + resolved_through_html: RĂ©itithe trĂ­ %{domain} + title: Fearainn rĂ­omhphoist bactha + export_domain_allows: + new: + title: CeadaĂ­onn fearann ​​​​iomportĂ¡la + no_file: NĂ­or roghnaĂ­odh aon chomhad + export_domain_blocks: + import: + description_html: TĂ¡ tĂº ar tĂ­ liosta de bhlocanna fearainn a allmhairiĂº. Athbhreithnigh an liosta seo go han-chĂºramach, le do thoil, go hĂ¡irithe murar scrĂ­obh tĂº fĂ©in an liosta seo. + existing_relationships_warning: Caidreamh leantach atĂ¡ ann cheana fĂ©in + private_comment_description_html: 'Chun cabhrĂº leat teacht ar cad as a dtagann bloic iompĂ³rtĂ¡ilte, cruthĂ³far bloic iompĂ³rtĂ¡ilte leis an nĂ³ta trĂ¡chta prĂ­obhĂ¡ideach seo a leanas: %{comment}' + private_comment_template: IompĂ³rtĂ¡ilte Ă³ %{source} ar %{date} + title: IompĂ³rtĂ¡il bloic fearainn + invalid_domain_block: 'LĂ©irĂ­odh bloc fearainn amhĂ¡in nĂ³ nĂ­os mĂ³ mar gheall ar an earrĂ¡id(Ă­): %{error}' + new: + title: IompĂ³rtĂ¡il bloic fearainn + no_file: NĂ­or roghnaĂ­odh aon chomhad follow_recommendations: + description_html: "Lean na moltaĂ­ cabhraĂ­onn sĂ© le hĂºsĂ¡ideoirĂ­ nua Ă¡bhar suimiĂºil a aimsiĂº go tapa. Nuair nach mbĂ­onn go leor idirghnĂ­omhaithe ag ĂºsĂ¡ideoir le daoine eile chun moltaĂ­ pearsantaithe a leanĂºint, moltar na cuntais seo ina ionad sin. DĂ©antar iad a athrĂ­omh ar bhonn laethĂºil Ă³ mheascĂ¡n de chuntais a bhfuil na rannphĂ¡irtĂ­ochtaĂ­ is airde acu le dĂ©anaĂ­ agus na hĂ¡irimh Ă¡itiĂºla is airde leanĂºna do theanga ar leith." language: Don teanga status: StĂ¡das suppress: Coisc moladh leanĂºna @@ -190,36 +495,94 @@ ga: title: MoltaĂ­ leanĂºna unsuppress: Aischuir moladh leanĂºna instances: + availability: + description_html: + few: MĂ¡ theipeann ar sheachadadh chuig an bhfearann ​​ar %{count} laethanta Ă©agsĂºla gan rath, nĂ­ dhĂ©anfar aon iarrachtaĂ­ seachadta eile mura bhfaightear Ă³ seachadadh Ă³n bhfearann. + many: MĂ¡ theipeann ar sheachadadh chuig an bhfearann ​​ar %{count} laethanta Ă©agsĂºla gan rath, nĂ­ dhĂ©anfar aon iarrachtaĂ­ seachadta eile mura bhfaightear Ă³ seachadadh Ă³n bhfearann. + one: MĂ¡ theipeann ar sheachadadh chuig an bhfearann ​​%{count} day gan rath, nĂ­ dhĂ©anfar aon iarrachtaĂ­ seachadta eile mura bhfaightear Ă³ seachadadh Ă³n bhfearann. + other: MĂ¡ theipeann ar sheachadadh chuig an bhfearann ​​ar %{count} laethanta Ă©agsĂºla gan rath, nĂ­ dhĂ©anfar aon iarrachtaĂ­ seachadta eile mura bhfaightear Ă³ seachadadh Ă³n bhfearann. + two: MĂ¡ theipeann ar sheachadadh chuig an bhfearann ​​ar %{count} laethanta Ă©agsĂºla gan rath, nĂ­ dhĂ©anfar aon iarrachtaĂ­ seachadta eile mura bhfaightear Ă³ seachadadh Ă³n bhfearann. + failure_threshold_reached: Baineadh an tairseach teipe amach ar %{date}. + failures_recorded: + few: Theip ar iarrachtaĂ­ ar %{count} lĂ¡ difriĂºil. + many: Theip ar iarrachtaĂ­ ar %{count} lĂ¡ difriĂºil. + one: Theip ar iarracht ar %{count} lĂ¡. + other: Theip ar iarrachtaĂ­ ar %{count} lĂ¡ difriĂºil. + two: Theip ar iarrachtaĂ­ ar %{count} lĂ¡ difriĂºil. + no_failures_recorded: Uimh teipeanna ar taifead. + title: Infhaighteacht + warning: NĂ­or Ă©irigh leis an iarracht dheireanach chun ceangal leis an bhfreastalaĂ­ seo back_to_all: Uile back_to_limited: Teoranta back_to_warning: Rabhadh by_domain: Fearann + confirm_purge: An bhfuil tĂº cinnte gur mian leat sonraĂ­ a scriosadh go buan Ă³n bhfearann ​​seo? content_policies: comment: NĂ³ta inmheĂ¡nach + description_html: Is fĂ©idir leat beartais inneachair a shainiĂº a chuirfear i bhfeidhm ar gach cuntas Ă³n bhfearann ​​seo agus aon cheann dĂ¡ fhofhearainn. + limited_federation_mode_description_html: Is fĂ©idir leat an rogha a dhĂ©anamh maidir le cĂ³naidhm a cheadĂº leis an bhfearann ​​seo. policies: + reject_media: Na meĂ¡in a dhiĂºltĂº + reject_reports: DiĂºltaigh tuarascĂ¡lacha silence: Teorannaigh suspend: Cuir ar fionraĂ­ policy: PolasaĂ­ + reason: CĂºis phoiblĂ­ + title: Polasaithe Ă¡bhair dashboard: + instance_accounts_dimension: Cuntais a lean a bhformhĂ³r + instance_accounts_measure: cuntais stĂ³rĂ¡ilte + instance_followers_measure: Ă¡r leantĂ³irĂ­ ann + instance_follows_measure: a lucht leanta anseo instance_languages_dimension: Teangacha is airde + instance_media_attachments_measure: ceangaltĂ¡in meĂ¡in stĂ³rĂ¡ilte + instance_reports_measure: tuairiscĂ­ mar gheall orthu + instance_statuses_measure: postanna stĂ³rĂ¡ilte delivery: all: Uile + clear: EarrĂ¡idĂ­ seachadta soilĂ©ir failing: Ag teip + restart: Seachadadh a atosĂº + stop: Stad seachadadh unavailable: NĂ­l ar fĂ¡il + delivery_available: TĂ¡ seachadadh ar fĂ¡il + delivery_error_days: Laethanta earrĂ¡ide seachadta + delivery_error_hint: Mura fĂ©idir seachadadh a dhĂ©anamh ar feadh %{count} lĂ¡, marcĂ¡lfar go huathoibrĂ­och Ă© mar dosheachadta. + destroyed_msg: TĂ¡ sonraĂ­ Ă³ %{domain} ciĂºĂ¡ilte anois le haghaidh scriosadh gan mhoill. + empty: NĂ­or aimsĂ­odh aon fhearainn. + known_accounts: + few: "%{count} cuntas aitheanta" + many: "%{count} cuntas aitheanta" + one: "%{count} cuntas aitheanta" + other: "%{count} cuntas aitheanta" + two: "%{count} cuntas aitheanta" moderation: all: Uile limited: Teoranta + title: Measarthacht + private_comment: TrĂ¡cht prĂ­obhĂ¡ideach + public_comment: TrĂ¡cht poiblĂ­ purge: Glan + purge_description_html: MĂ¡ chreideann tĂº go bhfuil an fearann ​​seo as lĂ­ne ar feadh tamaill mhaith, is fĂ©idir leat gach taifead cuntais agus sonraĂ­ gaolmhara Ă³n bhfearann ​​​​seo a scriosadh Ă³ do stĂ³r. Seans go dtĂ³gfaidh sĂ© seo tamall. title: CĂ³nascadh + total_blocked_by_us: BlocĂ¡ilte ag dĂºinn + total_followed_by_them: Ina dhiaidh sin iad total_followed_by_us: Ă leanĂºint againn + total_reported: TuarascĂ¡lacha mar gheall orthu + total_storage: CeangaltĂ¡in meĂ¡n + totals_time_period_hint_html: ĂirĂ­onn na hiomlĂ¡in a thaispeĂ¡ntar thĂ­os sonraĂ­ don am ar fad. + unknown_instance: NĂ­l aon taifead den fhearann ​​seo ar an bhfreastalaĂ­ seo faoi lĂ¡thair. invites: + deactivate_all: DĂ­ghnĂ­omhachtaigh go lĂ©ir filter: all: Uile available: Ar fĂ¡il + expired: Imithe in Ă©ag title: Scag title: CuirĂ­ ip_blocks: add_new: Cruthaigh riail + created_msg: Cuireadh riail IP nua leis go rathĂºil delete: Scrios expires_in: '1209600': CoicĂ­s @@ -228,111 +591,609 @@ ga: '31556952': Bliain amhĂ¡in '86400': LĂ¡ amhĂ¡in '94670856': 3 bhliain + new: + title: Cruthaigh riail IP nua + no_ip_block_selected: NĂ­or athraĂ­odh aon rialacha IP mar nĂ­or roghnaĂ­odh ceann ar bith title: Rialacha IP + relationships: + title: Caidrimh %{acct} relays: + add_new: Cuir sealaĂ­ochta nua leis delete: Scrios + description_html: Is freastalaĂ­ idirghabhĂ¡laĂ­ Ă© athsheachadĂ¡n cĂ³naidhme a mhalartaĂ­onn lĂ­on mĂ³r postĂ¡lacha poiblĂ­ idir freastalaithe a shĂ­nĂ­onn dĂ³ agus a fhoilsĂ­onn Ă©. Is fĂ©idir leis cabhrĂº le freastalaithe beaga agus meĂ¡nmhĂ©ide inneachar a aimsiĂº Ă³n bhfeideas, rud a d'Ă©ileodh ar ĂºsĂ¡ideoirĂ­ Ă¡itiĂºla daoine eile a leanĂºint de lĂ¡imh ar fhreastalaithe cianda. disable: DĂ­chumasaigh disabled: DĂ­chumasaithe enable: Cumasaigh + enable_hint: Nuair a bheidh sĂ© cumasaithe, liostĂ³idh do fhreastalaĂ­ le gach postĂ¡il phoiblĂ­ Ă³n athsheoladh seo, agus tosĂ³idh sĂ© ag seoladh postĂ¡lacha poiblĂ­ an fhreastalaĂ­ seo chuige. enabled: Ar chumas + inbox_url: URL Athsheolta + pending: Ag fanacht le ceadĂº sealaĂ­ochta save_and_enable: SĂ¡bhĂ¡il agus cumasaigh + setup: Socraigh nasc sealaĂ­ochta + signatures_not_enabled: Seans nach n-oibreoidh athsheachadĂ¡in i gceart agus mĂ³d slĂ¡n nĂ³ modh cĂ³naidhmthe teoranta cumasaithe status: StĂ¡das + title: AthsheachadĂ¡in + report_notes: + created_msg: CruthaĂ­odh nĂ³ta tuairisce go rathĂºil! + destroyed_msg: D'Ă©irigh leis an nĂ³ta tuairisce a scriosadh! reports: + account: + notes: + few: "%{count} nĂ³taĂ­" + many: "%{count} nĂ³taĂ­" + one: "%{count} nĂ³ta" + other: "%{count} nĂ³taĂ­" + two: "%{count} nĂ³taĂ­" + action_log: Loga iniĂºchta + action_taken_by: GnĂ­omh arna ghlacadh ag + actions: + delete_description_html: Scriosfar na postĂ¡lacha tuairiscithe agus dĂ©anfar stailc a thaifeadadh chun cabhrĂº leat dul in airde ar shĂ¡ruithe sa todhchaĂ­ trĂ­d an gcuntas cĂ©anna. + mark_as_sensitive_description_html: DĂ©anfar na meĂ¡in sna poist tuairiscithe a mharcĂ¡il mar Ă­ogair agus dĂ©anfar stailc a thaifeadadh chun cabhrĂº leat sĂ¡rĂº a dhĂ©anamh ar shĂ¡ruithe sa todhchaĂ­ trĂ­d an gcuntas cĂ©anna. + other_description_html: FĂ©ach ar a thuilleadh roghanna chun iompar an chuntais a rialĂº agus cumarsĂ¡id a shaincheapadh chuig an gcuntas tuairiscithe. + resolve_description_html: NĂ­ dhĂ©anfar aon ghnĂ­omhaĂ­ocht i gcoinne an chuntais thuairiscithe, nĂ­ dhĂ©anfar aon stailc a thaifeadadh, agus dĂºnfar an tuarascĂ¡il. + silence_description_html: NĂ­ bheidh an cuntas le feiceĂ¡il ach amhĂ¡in dĂ³ibh siĂºd a leanann Ă© cheana fĂ©in nĂ³ a bhreathnaĂ­onn suas de lĂ¡imh air, rud a chuirfidh srian mĂ³r ar a rochtain. Is fĂ©idir Ă© a chur ar ais i gcĂ³naĂ­. DĂºnann sĂ© gach tuairisc i gcoinne an chuntais seo. + suspend_description_html: Beidh an cuntas agus a bhfuil ann go lĂ©ir dorochtana agus scriosfar iad ar deireadh, agus beidh sĂ© dodhĂ©anta idirghnĂ­omhĂº leis. InchĂºlaithe laistigh de 30 lĂ¡. DĂºnann sĂ© gach tuairisc i gcoinne an chuntais seo. + actions_description_html: DĂ©an cinneadh ar an ngnĂ­omh atĂ¡ le dĂ©anamh chun an tuarascĂ¡il seo a rĂ©iteach. MĂ¡ dhĂ©anann tĂº beart pionĂ³sach in aghaidh an chuntais tuairiscithe, seolfar fĂ³gra rĂ­omhphoist chucu, ach amhĂ¡in nuair a roghnaĂ­tear an chatagĂ³ir Turscar. + actions_description_remote_html: DĂ©an cinneadh ar an ngnĂ­omh atĂ¡ le dĂ©anamh chun an tuarascĂ¡il seo a rĂ©iteach. NĂ­ bheidh tionchar aige seo ach ar an gcaoi a ndĂ©anann do fhreastalaĂ­ cumarsĂ¡id leis an gcianchuntas seo agus a lĂ¡imhseĂ¡lann sĂ© a Ă¡bhar. + add_to_report: Cuir tuilleadh leis an tuairisc + already_suspended_badges: + local: Ar fionraĂ­ cheana fĂ©in ar an bhfreastalaĂ­ seo + remote: Ar fionraĂ­ cheana fĂ©in ar a bhfreastalaĂ­ are_you_sure: An bhfuil tĂº cinnte? + assign_to_self: Sann dom + assigned: ModhnĂ³ir sannta + by_target_domain: Fearann ​​an chuntais tuairiscithe cancel: Cealaigh category: CatagĂ³ir + category_description_html: Luafar an chĂºis ar tuairiscĂ­odh an cuntas seo agus/nĂ³ an t-Ă¡bhar seo i gcumarsĂ¡id leis an gcuntas tuairiscithe + comment: + none: Dada + comment_description_html: 'Chun tuilleadh eolais a sholĂ¡thar, scrĂ­obh %{name}:' + confirm: Deimhnigh + confirm_action: Deimhnigh gnĂ­omh modhnĂ³ireachta i gcoinne @%{acct} created_at: Tuairiscithe delete_and_resolve: Scrios postĂ¡lacha + forwarded: Ar aghaidh + forwarded_replies_explanation: Is Ă³ chianĂºsĂ¡ideoir an tuairisc seo agus faoi chianĂ¡bhar. TĂ¡ sĂ© curtha ar aghaidh chugat toisc go bhfuil an t-Ă¡bhar tuairiscithe mar fhreagra ar cheann de na hĂºsĂ¡ideoirĂ­ atĂ¡ agat. + forwarded_to: Ar aghaidh chuig %{domain} mark_as_resolved: MarcĂ¡il mar rĂ©itithe mark_as_sensitive: MarcĂ¡il mar Ă­ogair + mark_as_unresolved: MarcĂ¡il mar gan rĂ©iteach no_one_assigned: Duine ar bith notes: create: Cruthaigh nĂ³ta create_and_resolve: RĂ©itigh le nĂ³ta + create_and_unresolve: Oscail arĂ­s le nĂ³ta delete: Scrios + placeholder: DĂ©an cur sĂ­os ar na bearta a rinneadh, nĂ³ ar aon nuashonruithe gaolmhara eile... title: NĂ³taĂ­ + notes_description_html: FĂ©ach ar agus fĂ¡g nĂ³taĂ­ do mhodhnĂ³irĂ­ eile agus duit fĂ©in amach anseo + processed_msg: 'D''Ă©irigh le prĂ³iseĂ¡il an tuairisc # %{id}' + quick_actions_description_html: 'DĂ©an gnĂ­omh tapa nĂ³ scrollaigh sĂ­os chun Ă¡bhar tuairiscithe a fheiceĂ¡il:' + remote_user_placeholder: an cianĂºsĂ¡ideoir Ă³ %{instance} + reopen: Tuairisc a athoscailt + report: 'Tuairiscigh # %{id}' + reported_account: Cuntas tuairiscithe + reported_by: Tuairiscithe ag + reported_with_application: TuairiscĂ­odh leis an iarratas + resolved: RĂ©itithe + resolved_msg: D'Ă©irigh le rĂ©iteach an tuairisc! + skip_to_actions: LĂ©im ar ghnĂ­omhartha status: StĂ¡das + statuses: Ăbhar tuairiscithe + statuses_description_html: Luafar Ă¡bhar ciontach i gcumarsĂ¡id leis an gcuntas tuairiscithe + summary: + action_preambles: + delete_html: 'TĂ¡ tĂº ar tĂ­ cuid de phostĂ¡lacha @%{acct} a bhaint. DĂ©anfaidh sĂ© seo:' + mark_as_sensitive_html: 'TĂ¡ tĂº ar tĂ­ marcĂ¡il ar chuid de phostĂ¡lacha @%{acct} mar Ă­ogair. DĂ©anfaidh sĂ© seo:' + silence_html: 'TĂ¡ tĂº ar tĂ­ teorannĂº a dhĂ©anamh ar chuntas @%{acct}. DĂ©anfaidh sĂ© seo:' + suspend_html: 'TĂ¡ tĂº ar tĂ­ cuntas a chur ar fionraĂ­ @%{acct}. DĂ©anfaidh sĂ© seo:' + actions: + delete_html: Bain na postĂ¡lacha ciontaithe + mark_as_sensitive_html: MarcĂ¡il meĂ¡in na bpost ciontaithe mar Ă­ogair + silence_html: Cuir teorainn mhĂ³r le rochtain @%{acct} trĂ­ a bprĂ³ifĂ­l agus a n-inneachar a dhĂ©anamh infheicthe ag daoine atĂ¡ Ă¡ leanĂºint cheana fĂ©in nĂ³ ag breathnĂº uirthi de lĂ¡imh + suspend_html: Cuir @%{acct} ar fionraĂ­, rud a fhĂ¡gann go bhfuil a bprĂ³ifĂ­l agus a bhfuil iontu dorochtana agus dodhĂ©anta idirghnĂ­omhĂº leo + close_report: 'MarcĂ¡il an tuairisc #%{id} mar rĂ©itithe' + close_reports_html: MarcĂ¡il gach tuairisc in aghaidh @%{acct} mar rĂ©itithe + delete_data_html: Scrios prĂ³ifĂ­l agus inneachar @%{acct} 30 lĂ¡ Ă³ anois mura mbeidh siad curtha ar fionraĂ­ idir an dĂ¡ linn + preview_preamble_html: 'Gheobhaidh @%{acct} rabhadh leis an Ă¡bhar seo a leanas:' + record_strike_html: Taifead stailc in aghaidh @%{acct} chun cabhrĂº leat dul i ngleic le sĂ¡ruithe amach anseo Ă³n gcuntas seo + send_email_html: Seol rĂ­omhphost rabhaidh chuig @%{acct} + warning_placeholder: RĂ©asĂºnaĂ­ocht bhreise roghnach don ghnĂ­omh modhnĂ³ireachta. + target_origin: BunĂºs an chuntais tuairiscithe title: TuairiscĂ­ + unassign: DĂ­shannadh + unknown_action_msg: 'GnĂ­omh anaithnid: %{action}' + unresolved: Gan rĂ©iteach + updated_at: Nuashonraithe + view_profile: FĂ©ach ar phrĂ³ifĂ­l roles: add_new: Cruthaigh rĂ³l + assigned_users: + few: "%{count} ĂºsĂ¡ideoirĂ­" + many: "%{count} ĂºsĂ¡ideoirĂ­" + one: "%{count} ĂºsĂ¡ideoir" + other: "%{count} ĂºsĂ¡ideoirĂ­" + two: "%{count} ĂºsĂ¡ideoirĂ­" categories: administration: Riar + devops: DevOps invites: CuirĂ­ + moderation: Measarthacht + special: Speisialta delete: Scrios + description_html: Le rĂ³il ĂºsĂ¡ideora, is fĂ©idir leat na feidhmeanna agus na rĂ©imsĂ­ de Mastodon ar fĂ©idir le d'ĂºsĂ¡ideoirĂ­ rochtain a fhĂ¡il orthu a shaincheapadh. + edit: Cuir rĂ³l '%{name}' in eagar + everyone: Ceadanna rĂ©amhshocraithe + everyone_full_description_html: Seo Ă© an bunrĂ³l a thĂ©ann i bhfeidhm ar gach ĂºsĂ¡ideoir, fiĂº iad siĂºd nach bhfuil rĂ³l sannta acu. Faigheann gach rĂ³l eile cead uaidh. + permissions_count: + few: "%{count} ceadanna" + many: "%{count} ceadanna" + one: "%{count} cead" + other: "%{count} ceadanna" + two: "%{count} ceadanna" privileges: administrator: RiarthĂ³ir + administrator_description: SeachnĂ³idh ĂºsĂ¡ideoirĂ­ a bhfuil an cead seo acu gach cead delete_user_data: Scrios SonraĂ­ ĂsĂ¡ideora + delete_user_data_description: Ligeann sĂ© d'ĂºsĂ¡ideoirĂ­ sonraĂ­ ĂºsĂ¡ideoirĂ­ eile a scriosadh gan mhoill + invite_users: Tabhair cuireadh d'ĂsĂ¡ideoirĂ­ + invite_users_description: Ligeann sĂ© d'ĂºsĂ¡ideoirĂ­ cuireadh a thabhairt do dhaoine nua chuig an bhfreastalaĂ­ + manage_announcements: Bainistigh FĂ³graĂ­ + manage_announcements_description: Ligeann sĂ© d'ĂºsĂ¡ideoirĂ­ fĂ³graĂ­ ar an bhfreastalaĂ­ a bhainistiĂº + manage_appeals: Achomharc a bhainistiĂº + manage_appeals_description: Ligeann sĂ© d'ĂºsĂ¡ideoirĂ­ athbhreithniĂº a dhĂ©anamh ar achomhairc i gcoinne gnĂ­omhartha modhnĂ³ireachta + manage_blocks: Bainistigh Bloic + manage_blocks_description: Ligeann sĂ© d'ĂºsĂ¡ideoirĂ­ bac a chur ar sholĂ¡thraithe rĂ­omhphoist agus seoltaĂ­ IP + manage_custom_emojis: Bainistigh Emojis Saincheaptha + manage_custom_emojis_description: Ligeann sĂ© d'ĂºsĂ¡ideoirĂ­ emojis saincheaptha a bhainistiĂº ar an bhfreastalaĂ­ + manage_federation: CĂ³naidhm a bhainistiĂº + manage_federation_description: Ligeann sĂ© dâ€™ĂºsĂ¡ideoirĂ­ cĂ³naidhm a bhlocĂ¡il nĂ³ a cheadĂº le fearainn eile, agus inseachadacht a rialĂº + manage_invites: Bainistigh CuirĂ­ + manage_invites_description: Ligeann sĂ© d'ĂºsĂ¡ideoirĂ­ naisc cuireadh a bhrabhsĂ¡il agus a dhĂ­ghnĂ­omhachtĂº + manage_reports: TuarascĂ¡lacha a bhainistiĂº + manage_reports_description: Ligeann sĂ© dâ€™ĂºsĂ¡ideoirĂ­ tuarascĂ¡lacha a athbhreithniĂº agus gnĂ­omhartha modhnĂ³ireachta a dhĂ©anamh ina gcoinne + manage_roles: Bainistigh RĂ³il + manage_roles_description: Ligeann sĂ© d'ĂºsĂ¡ideoirĂ­ rĂ³il faoina gcuid fĂ©in a bhainistiĂº agus a shannadh + manage_rules: Rialacha a bhainistiĂº + manage_rules_description: Ligeann sĂ© d'ĂºsĂ¡ideoirĂ­ rialacha freastalaĂ­ a athrĂº + manage_settings: Bainistigh Socruithe + manage_settings_description: Ligeann sĂ© d'ĂºsĂ¡ideoirĂ­ socruithe suĂ­mh a athrĂº + manage_taxonomies: TacsanomaĂ­ochtaĂ­ a bhainistiĂº + manage_taxonomies_description: Ligeann sĂ© d'ĂºsĂ¡ideoirĂ­ athbhreithniĂº a dhĂ©anamh ar inneachar treochta agus socruithe hashtag a nuashonrĂº + manage_user_access: Bainistigh Rochtain ĂsĂ¡ideoir + manage_user_access_description: Ligeann sĂ© d'ĂºsĂ¡ideoirĂ­ fĂ­ordheimhniĂº dhĂ¡ fhachtĂ³ir ĂºsĂ¡ideoirĂ­ eile a dhĂ­chumasĂº, a seoladh r-phoist a athrĂº, agus a bpasfhocal a athshocrĂº + manage_users: Bainistigh ĂsĂ¡ideoirĂ­ + manage_users_description: Ligeann sĂ© d'ĂºsĂ¡ideoirĂ­ sonraĂ­ ĂºsĂ¡ideoirĂ­ eile a fheiceĂ¡il agus gnĂ­omhartha modhnĂ³ireachta a dhĂ©anamh ina gcoinne + manage_webhooks: Bainistigh cuacha GrĂ©asĂ¡in + manage_webhooks_description: Ligeann sĂ© d'ĂºsĂ¡ideoirĂ­ cuacha grĂ©asĂ¡in a shocrĂº le haghaidh imeachtaĂ­ riarachĂ¡in + view_audit_log: FĂ©ach ar Loga IniĂºchta + view_audit_log_description: Ligeann sĂ© d'ĂºsĂ¡ideoirĂ­ stair gnĂ­omhartha riarachĂ¡in a fheiceĂ¡il ar an bhfreastalaĂ­ + view_dashboard: Amharc ar an Deais + view_dashboard_description: Ligeann sĂ© dâ€™ĂºsĂ¡ideoirĂ­ rochtain a fhĂ¡il ar an deais agus ar mhĂ©adrachtaĂ­ Ă©agsĂºla + view_devops: DevOps + view_devops_description: Ligeann sĂ© dâ€™ĂºsĂ¡ideoirĂ­ rochtain a fhĂ¡il ar dheais Sidekiq agus pgHero title: RĂ³il rules: add_new: Cruthaigh riail delete: Scrios + description_html: CĂ© go maĂ­onn a bhformhĂ³r gur lĂ©igh siad agus go n-aontaĂ­onn siad leis na tĂ©armaĂ­ seirbhĂ­se, de ghnĂ¡th nĂ­ lĂ©ann daoine trĂ­d go dtĂ­ go dtagann fadhb chun cinn. DĂ©an rialacha do fhreastalaĂ­ a fheiceĂ¡il go sracfhĂ©achaint trĂ­ iad a sholĂ¡thar i liosta comhrĂ©idh de phointe urchair. DĂ©an iarracht rialacha aonair a choinneĂ¡il gearr simplĂ­, ach dĂ©an iarracht gan iad a roinnt ina go leor mĂ­reanna ar leith ach an oiread. + edit: Cuir riail in eagar + empty: NĂ­l aon rialacha freastalaĂ­ sainmhĂ­nithe fĂ³s. + title: Rialacha freastalaĂ­ settings: + about: + manage_rules: Bainistigh rialacha freastalaĂ­ + preamble: Cuir eolas domhain ar fĂ¡il faoin gcaoi a n-oibrĂ­tear, a ndĂ©antar modhnĂ³ireacht agus maoiniĂº ar an bhfreastalaĂ­. + rules_hint: TĂ¡ rĂ©imse tiomnaithe rialacha ann a bhfuiltear ag sĂºil go gcloĂ­fidh dâ€™ĂºsĂ¡ideoirĂ­ leis. + title: Faoi appearance: + preamble: Saincheap comhĂ©adan grĂ©asĂ¡in Mastodon. title: Cuma + branding: + preamble: DĂ©anann brandĂ¡il do fhreastalaĂ­ Ă© a idirdhealĂº Ă³ fhreastalaithe eile sa lĂ­onra. FĂ©adfar an fhaisnĂ©is seo a thaispeĂ¡int ar fud timpeallachtaĂ­ Ă©agsĂºla, mar shampla comhĂ©adan grĂ©asĂ¡in Mastodon, feidhmchlĂ¡ir dhĂºchasacha, i rĂ©amhamhairc naisc ar lĂ¡ithreĂ¡in ghrĂ©asĂ¡in eile agus laistigh d’aipeanna teachtaireachtaĂ­, agus mar sin de. Ar an Ă¡bhar sin, is fearr an fhaisnĂ©is seo a choinneĂ¡il soilĂ©ir, gearr agus gonta. + title: BrandĂ¡il + captcha_enabled: + desc_html: Braitheann sĂ© seo ar scripteanna seachtracha Ă³ hCaptcha, rud a d’fhĂ©adfadh a bheith ina Ă¡bhar imnĂ­ maidir le slĂ¡ndĂ¡il agus prĂ­obhĂ¡ideacht. Ina theannta sin, is fĂ©idir leis seo an prĂ³iseas clĂ¡rĂºchĂ¡in a dhĂ©anamh i bhfad nĂ­os lĂº inrochtana ag roinnt daoine (go hĂ¡irithe faoi mhĂ­chumas). Ar na cĂºiseanna seo, smaoinigh le do thoil ar bhearta eile amhail clĂ¡rĂº bunaithe ar fhormheas nĂ³ ar chuireadh. + title: A cheangal ar ĂºsĂ¡ideoirĂ­ nua CAPTCHA a rĂ©iteach chun a gcuntas a dhearbhĂº + content_retention: + danger_zone: Crios contĂºirte + preamble: RialĂº conas a stĂ³rĂ¡iltear Ă¡bhar a ghintear ag ĂºsĂ¡ideoirĂ­ i Mastodon. + title: CoinneĂ¡il Ă¡bhair default_noindex: desc_html: I bhfeidhm do ghach ĂºsĂ¡ideoir nĂ¡r athraigh an socrĂº seo iad fĂ©in title: DiĂºltaigh d'innĂ©acsĂº inneall cuardaigh mar rĂ©amhshocrĂº d'ĂºsĂ¡ideoirĂ­ + discovery: + follow_recommendations: Lean na moltaĂ­ + preamble: TĂ¡ sĂ© rĂ­thĂ¡bhachtach dromchla a chur ar Ă¡bhar suimiĂºil chun ĂºsĂ¡ideoirĂ­ nua a chur ar bord nach bhfuil aithne acu ar dhuine ar bith Mastodon. RialĂº conas a oibrĂ­onn gnĂ©ithe fionnachtana Ă©agsĂºla ar do fhreastalaĂ­. + profile_directory: Eolaire prĂ³ifĂ­le + public_timelines: AmlĂ­nte poiblĂ­ + publish_discovered_servers: Foilsigh freastalaithe aimsithe + publish_statistics: StaitisticĂ­ a fhoilsiĂº + title: Fionnachtain + trends: TreochtaĂ­ + domain_blocks: + all: Do chĂ¡ch + disabled: Do dhuine ar bith + users: Chun ĂºsĂ¡ideoirĂ­ Ă¡itiĂºla logĂ¡ilte isteach 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Ă­. title: ClĂ¡rĂºchĂ¡in + registrations_mode: + modes: + approved: TeastaĂ­onn ceadĂº le clĂ¡rĂº + none: NĂ­ fĂ©idir le duine ar bith clĂ¡rĂº + open: Is fĂ©idir le duine ar bith clĂ¡rĂº + warning_hint: Molaimid ĂºsĂ¡id a bhaint as “Faomhadh riachtanach chun clĂ¡rĂºâ€ ach amhĂ¡in mĂ¡ tĂ¡ tĂº muinĂ­neach gur fĂ©idir le d’fhoireann mhodhnĂ³ireachta clĂ¡rĂº turscair agus mailĂ­seach a lĂ¡imhseĂ¡il go trĂ¡thĂºil. + security: + authorized_fetch: TeastaĂ­onn fĂ­ordheimhniĂº Ă³ fhreastalaithe cĂ³nasctha + authorized_fetch_hint: Toisc go n-Ă©ilĂ­tear fĂ­ordheimhniĂº Ă³ fhreastalaithe cĂ³nasctha, is fĂ©idir bloic ar leibhĂ©al an ĂºsĂ¡ideora agus ar leibhĂ©al an fhreastalaĂ­ araon a fhorfheidhmiĂº nĂ­os dĂ©ine. Mar sin fĂ©in, tagann sĂ© seo ar chostas pionĂ³s feidhmĂ­ochta, laghdaĂ­tear an teacht ar do chuid freagraĂ­, agus d'fhĂ©adfadh saincheisteanna comhoiriĂºnachta a thabhairt isteach le roinnt seirbhĂ­sĂ­ cĂ³nasctha. Ina theannta sin, nĂ­ chuirfidh sĂ© seo cosc ​​ar aisteoirĂ­ tiomnaithe do phoist phoiblĂ­ agus do chuntais phoiblĂ­ a fhĂ¡il. + authorized_fetch_overridden_hint: NĂ­ fĂ©idir leat an socrĂº seo a athrĂº faoi lĂ¡thair toisc go bhfuil sĂ© sĂ¡raithe ag athrĂ³g timpeallachta. + federation_authentication: ForghnĂ­omhĂº fĂ­ordheimhnithe CĂ³naidhm + title: Socruithe freastalaĂ­ site_uploads: delete: Scrios comhad uaslĂ³dĂ¡ilte + destroyed_msg: D'Ă©irigh le huaslĂ³dĂ¡il an tsuĂ­mh a scriosadh! + 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. + documentation_link: Foghlaim nĂ­os mĂ³ + release_notes: NĂ³taĂ­ scaoilte + title: Nuashonruithe ar fĂ¡il + type: CineĂ¡l + types: + major: MĂ³rscaoileadh + minor: Mionscaoileadh + patch: Scaoileadh paiste - ceartĂºchĂ¡in agus athruithe atĂ¡ Ă©asca a chur i bhfeidhm + version: Leagan statuses: account: Ădar + application: Iarratas back_to_account: Ar ais go leathanach cuntais + back_to_report: Ar ais go leathanach tuairisce + batch: + remove_from_report: Bain den tuairisc + report: Tuairisc deleted: Scriosta favourites: Toghanna + history: Stair leagan + in_reply_to: Ag freagairt do language: Teanga media: title: MeĂ¡in metadata: MeiteashonraĂ­ + no_status_selected: NĂ­or athraĂ­odh aon phostĂ¡il mar nĂ­or roghnaĂ­odh ceann ar bith open: Oscail postĂ¡il original_status: BunphostĂ¡il reblogs: Athbhlaganna status_changed: AthraĂ­odh postĂ¡il + title: Poist chuntais trending: Ag treochtĂ¡il + visibility: Infheictheacht with_media: Le meĂ¡in strikes: actions: delete_statuses: Scrios %{name} postĂ¡lacha de chuid %{target} + disable: Reoite %{name} cuntas %{target} + mark_statuses_as_sensitive: MharcĂ¡il %{name} postĂ¡lacha %{target} mar Ă­ogair + none: Sheol %{name} rabhadh chuig %{target} + sensitive: MharcĂ¡il %{name} cuntas %{target} mar Ă­ogair + silence: Chuir %{name} teorainn le cuntas %{target} + suspend: Chuir %{name} cuntas %{target} ar fionraĂ­ + appeal_approved: Achomharc + appeal_pending: Achomharc ar feitheamh + appeal_rejected: DiĂºltaĂ­odh don achomharc + system_checks: + database_schema_check: + message_html: TĂ¡ aistrithe bunachar sonraĂ­ ar feitheamh. Rith iad le do thoil chun a chinntiĂº go n-iompraĂ­onn an t-iarratas mar a bhĂ­othas ag sĂºil leis + elasticsearch_health_red: + message_html: TĂ¡ braisle Elasticsearch mĂ­shlĂ¡intiĂºil (stĂ¡das dearg), nĂ­l gnĂ©ithe cuardaigh ar fĂ¡il + elasticsearch_health_yellow: + message_html: TĂ¡ braisle Elasticsearch mĂ­shlĂ¡intiĂºil (stĂ¡das buĂ­), b'fhĂ©idir gur mhaith leat an chĂºis a fhiosrĂº + elasticsearch_index_mismatch: + message_html: TĂ¡ mapĂ¡lacha innĂ©acs Elasticsearch as dĂ¡ta. Rith tootctl search deploy --only=%{value} le do thoil + elasticsearch_preset: + action: FĂ©ach doicimĂ©adĂº + message_html: TĂ¡ nĂ­os mĂ³ nĂ¡ nĂ³d amhĂ¡in ag do bhraisle Elasticsearch, ach nĂ­l Mastodon cumraithe chun iad a ĂºsĂ¡id. + elasticsearch_preset_single_node: + action: FĂ©ach doicimĂ©adĂº + message_html: NĂ­l ach nĂ³d amhĂ¡in ag do bhraisle Elasticsearch, ba cheart ES_PRESET a shocrĂº go single_node_cluster. + elasticsearch_reset_chewy: + message_html: TĂ¡ d'innĂ©acs cĂ³rais Elasticsearch as dĂ¡ta mar gheall ar athrĂº socruithe. Rith tootctl search deploy --reset-chewy chun Ă© a nuashonrĂº. + elasticsearch_running_check: + message_html: NĂ­orbh fhĂ©idir ceangal le Elasticsearch. Cinntigh go bhfuil sĂ© ar siĂºl, nĂ³ dĂ­chumasaigh cuardach tĂ©acs iomlĂ¡n + elasticsearch_version_check: + message_html: 'Leagan neamh-chomhoiriĂºnach le Elasticsearch: %{value}' + version_comparison: TĂ¡ Elasticsearch %{running_version} ag rith agus %{required_version} ag teastĂ¡il + rules_check: + action: Bainistigh rialacha freastalaĂ­ + message_html: NĂ­l aon rialacha freastalaĂ­ sainmhĂ­nithe agat. + sidekiq_process_check: + message_html: NĂ­l prĂ³iseas Sidekiq ag rith don scuaine/(scuainĂ­) %{value}. DĂ©an athbhreithniĂº ar do chumraĂ­ocht Sidekiq + software_version_critical_check: + action: FĂ©ach nuashonruithe atĂ¡ ar fĂ¡il + message_html: TĂ¡ nuashonrĂº rĂ­thĂ¡bhachtach Mastodon ar fĂ¡il, nuashonraigh chomh tapa agus is fĂ©idir le do thoil. + software_version_patch_check: + action: FĂ©ach nuashonruithe atĂ¡ ar fĂ¡il + message_html: TĂ¡ nuashonrĂº bugfix Mastodon ar fĂ¡il. + upload_check_privacy_error: + action: SeiceĂ¡il anseo le haghaidh tuilleadh eolais + message_html: "TĂ¡ do fhreastalaĂ­ grĂ©asĂ¡in mĂ­chumraithe. TĂ¡ prĂ­obhĂ¡ideacht d'ĂºsĂ¡ideoirĂ­ i mbaol." + upload_check_privacy_error_object_storage: + action: SeiceĂ¡il anseo le haghaidh tuilleadh eolais + message_html: "TĂ¡ do stĂ³r oibiachtaĂ­ mĂ­chumraithe. TĂ¡ prĂ­obhĂ¡ideacht d'ĂºsĂ¡ideoirĂ­ i mbaol." tags: review: StĂ¡das athbhreithnithe + updated_msg: D'Ă©irigh le socruithe hashtag a nuashonrĂº title: Riar trends: allow: Ceadaigh + approved: Ceadaithe disallow: DĂ­cheadaigh + links: + allow: Ceadaigh nasc + allow_provider: Ceadaigh foilsitheoir + description_html: Is naisc iad seo atĂ¡ Ă¡ roinnt go mĂ³r faoi lĂ¡thair ag cuntais a bhfeiceann do fhreastalaĂ­ postĂ¡lacha uathu. Is fĂ©idir leis cabhrĂº le dâ€™ĂºsĂ¡ideoirĂ­ a fhĂ¡il amach cad atĂ¡ ar siĂºl ar fud an domhain. NĂ­ thaispeĂ¡nfar naisc ar bith go poiblĂ­ go dtĂ­ go gceadaĂ­onn tĂº an foilsitheoir. Is fĂ©idir leat naisc aonair a cheadĂº nĂ³ a dhiĂºltĂº freisin. + disallow: Nasc a dhĂ­cheadĂº + disallow_provider: DĂ­cheadaigh foilsitheoir + no_link_selected: NĂ­or athraĂ­odh aon nasc mar nĂ­or roghnaĂ­odh ceann ar bith + publishers: + no_publisher_selected: NĂ­or athraĂ­odh aon fhoilsitheoir mar nĂ­or roghnaĂ­odh ceann ar bith + shared_by_over_week: + few: Roinnte ag %{count} duine le seachtain anuas + many: Roinnte ag %{count} duine le seachtain anuas + one: Roinnte ag duine amhĂ¡in le seachtain anuas + other: Roinnte ag %{count} duine le seachtain anuas + two: Roinnte ag %{count} duine le seachtain anuas + title: Naisc treochta + usage_comparison: Roinnte %{today} uair inniu, i gcomparĂ¡id le %{yesterday} innĂ© + not_allowed_to_trend: NĂ­ cheadaĂ­tear treocht + only_allowed: NĂ­ cheadaĂ­tear ach + pending_review: AthbhreithniĂº ar feitheamh preview_card_providers: + allowed: Is fĂ©idir le naisc Ă³n bhfoilsitheoir seo treocht + description_html: Is fearainn iad seo Ă³na roinntear naisc go minic ar do fhreastalaĂ­. NĂ­ threochtĂ³idh naisc go poiblĂ­ mura gceadaĂ­tear fearann ​​an naisc. SĂ­neann do cheadĂº (nĂ³ diĂºltĂº) chuig fofhearainn. + rejected: NĂ­ bheidh treocht ag naisc Ă³n bhfoilsitheoir seo title: FoilsitheoirĂ­ rejected: DiĂºltaithe statuses: allow: Ceadaigh postĂ¡il allow_account: Ceadaigh Ăºdar + description_html: Is postĂ¡lacha iad seo a bhfuil do fhreastalaĂ­ ar an eolas fĂºthu agus atĂ¡ Ă¡ roinnt faoi lĂ¡thair agus is fearr leat go mĂ³r faoi lĂ¡thair. Is fĂ©idir leis cabhrĂº le dâ€™ĂºsĂ¡ideoirĂ­ nua agus ĂºsĂ¡ideoirĂ­ atĂ¡ ag filleadh nĂ­os mĂ³ daoine a aimsiĂº le leanĂºint. NĂ­ thaispeĂ¡nfar postĂ¡lacha ar bith go poiblĂ­ go dtĂ­ go gceadaĂ­onn tĂº an t-Ăºdar, agus ceadaĂ­onn an t-Ăºdar a gcuntas a mholadh do dhaoine eile. Is fĂ©idir leat postĂ¡lacha aonair a cheadĂº nĂ³ a dhiĂºltĂº freisin. + disallow: DĂ­cheadaigh postĂ¡il + disallow_account: Ădar a dhĂ­cheadĂº + no_status_selected: NĂ­or athraĂ­odh aon phostĂ¡il treochta mar nĂ­or roghnaĂ­odh ceann ar bith + not_discoverable: NĂ­or roghnaigh an t-Ăºdar a bheith in-aimsithe + shared_by: + few: Roinnte agus ansa leat %{friendly_count} uair + many: Roinnte agus ansa leat %{friendly_count} uair + one: Roinnte nĂ³ is fearr leat am amhĂ¡in + other: Roinnte agus ansa leat %{friendly_count} uair + two: Roinnte agus ansa leat %{friendly_count} uair + title: Poist trending + tags: + current_score: ScĂ³r reatha %{score} + dashboard: + tag_accounts_measure: ĂºsĂ¡idĂ­ uathĂºla + tag_languages_dimension: Barrtheangacha + tag_servers_dimension: Barrtheangacha + tag_servers_measure: freastalaithe Ă©agsĂºla + tag_uses_measure: ĂºsĂ¡idĂ­ iomlĂ¡na + description_html: Is hashtags iad seo atĂ¡ le feiceĂ¡il faoi lĂ¡thair i go leor postĂ¡lacha a fheiceann do fhreastalaĂ­. Is fĂ©idir leis cabhrĂº le dâ€™ĂºsĂ¡ideoirĂ­ a fhĂ¡il amach cad Ă© is mĂ³ atĂ¡ ag caint faoi dhaoine faoi lĂ¡thair. NĂ­ thaispeĂ¡nfar aon hashtags go poiblĂ­ go dtĂ­ go gceadaĂ­onn tĂº iad. + listable: Is fĂ©idir a mholadh + no_tag_selected: NĂ­or athraĂ­odh aon chlib mar nĂ­or roghnaĂ­odh ceann ar bith + not_listable: NĂ­ mholfar + not_trendable: NĂ­ bheidh le feiceĂ¡il faoi threochtaĂ­ + not_usable: NĂ­ fĂ©idir Ă© a ĂºsĂ¡id + peaked_on_and_decaying: Buaicphointe ar %{date}, ag lobhadh anois + title: Haischlib treochta + trendable: Is fĂ©idir le feiceĂ¡il faoi threochtaĂ­ + trending_rank: 'Ag treochtĂ¡il # %{rank}' + usable: Is fĂ©idir Ă© a ĂºsĂ¡id + usage_comparison: ĂsĂ¡idte %{today} uair inniu, i gcomparĂ¡id le %{yesterday} innĂ© + used_by_over_week: + few: ĂsĂ¡idte ag %{count} duine le seachtain anuas + many: ĂsĂ¡idte ag %{count} duine le seachtain anuas + one: ĂsĂ¡idte ag duine amhĂ¡in le seachtain anuas + other: ĂsĂ¡idte ag %{count} duine le seachtain anuas + two: ĂsĂ¡idte ag %{count} duine le seachtain anuas + title: TreochtaĂ­ + trending: Treocht warning_presets: + add_new: Cuir nua leis delete: Scrios + edit_preset: Cuir rĂ©amhshocrĂº rabhaidh in eagar + empty: NĂ­l aon rĂ©amhshocruithe rabhaidh sainithe agat fĂ³s. + title: RĂ©amhshocruithe rabhaidh webhooks: + add_new: Cuir crĂ­ochphointe leis delete: Scrios + description_html: Cuireann cuadĂ³g grĂ©asĂ¡in ar chumas Mastodon fĂ³graĂ­ fĂ­or-ama faoi imeachtaĂ­ roghnaithe a bhrĂº le d'iarratas fĂ©in, ionas gur fĂ©idir le d'iarratas imoibrithe a spreagadh go huathoibrĂ­och. disable: DĂ­chumasaigh disabled: DĂ­chumasaithe + edit: Cuir crĂ­ochphointe in eagar + empty: NĂ­l aon chrĂ­ochphointĂ­ cuaille grĂ©asĂ¡in agat fĂ³s. enable: Cumasaigh enabled: GnĂ­omhach + enabled_events: + few: "%{count} imeacht cumasaithe" + many: "%{count} imeacht cumasaithe" + one: 1 imeacht cumasaithe + other: "%{count} imeacht cumasaithe" + two: "%{count} imeacht cumasaithe" events: EachtraĂ­ + new: Cuaille grĂ©asĂ¡in nua + rotate_secret: Rothlaigh an rĂºn + secret: RĂºn a shĂ­niĂº status: StĂ¡das + title: CrĂºcaĂ­ grĂ©asĂ¡in + webhook: CrĂºca grĂ©asĂ¡in admin_mailer: + auto_close_registrations: + body: De bharr easpa gnĂ­omhaĂ­ochta modhnĂ³ra le dĂ©anaĂ­, aistrĂ­odh clĂ¡rĂºchĂ¡in ar %{instance} go huathoibrĂ­och chuig athbhreithniĂº de lĂ¡imh chun nach n-ĂºsĂ¡idfear %{instance} mar ardĂ¡n do dhrochghnĂ­omhaithe fĂ©ideartha. Is fĂ©idir leat Ă© a athrĂº ar ais chuig clĂ¡rĂºchĂ¡in a oscailt am ar bith. + subject: AthraĂ­odh clĂ¡rĂºchĂ¡in le haghaidh %{instance} go huathoibrĂ­och chuig a dteastaĂ­onn ceadĂº uathu new_appeal: actions: delete_statuses: a gcuid postĂ¡lacha a scrios + disable: a gcuntas a reo + mark_statuses_as_sensitive: a bpoist a mharcĂ¡il mar Ă­ogair none: rabhadh + sensitive: a gcuntas a mharcĂ¡il mar Ă­ogair + silence: a gcuntas a theorannĂº + suspend: a gcuntas a chur ar fionraĂ­ + body: 'TĂ¡ %{target} ag achomharc in aghaidh cinneadh modhnĂ³ireachta Ă³ %{action_taken_by} Ă³ %{date}, arbh Ă© %{type} Ă©. ScrĂ­obh siad:' + next_steps: Is fĂ©idir leat an t-achomharc a cheadĂº chun an cinneadh modhnĂ³ireachta a chealĂº, nĂ³ neamhaird a dhĂ©anamh air. + subject: TĂ¡ %{username} ag achomharc in aghaidh cinneadh modhnĂ³ireachta ar %{instance} + new_critical_software_updates: + body: TĂ¡ leaganacha criticiĂºla nua de Mastodon eisithe, b'fhĂ©idir gur mhaith leat a nuashonrĂº chomh luath agus is fĂ©idir! + subject: TĂ¡ nuashonruithe Critical Mastodon ar fĂ¡il do %{instance}! + new_pending_account: + body: TĂ¡ sonraĂ­ an chuntais nua thĂ­os. Is fĂ©idir leat an t-iarratas seo a cheadĂº nĂ³ a dhiĂºltĂº. + subject: Cuntas nua le lĂ©irmheas ar %{instance} (%{username}) + new_report: + body: Thuairiscigh %{reporter} %{target} + body_remote: Thuairiscigh duine Ă©igin Ă³ %{domain} %{target} + subject: Tuairisc nua do %{instance} (#%{id}) + new_software_updates: + body: TĂ¡ leaganacha nua Mastodon eisithe, b'fhĂ©idir gur mhaith leat a nuashonrĂº! + subject: TĂ¡ leaganacha nua Mastodon ar fĂ¡il do %{instance}! + new_trends: + body: 'Is gĂ¡ na mĂ­reanna seo a leanas a athbhreithniĂº sular fĂ©idir iad a thaispeĂ¡int go poiblĂ­:' + new_trending_links: + title: Naisc treochta + new_trending_statuses: + title: Poist trending + new_trending_tags: + title: Hashtags treochta + subject: TreochtaĂ­ nua le hathbhreithniĂº ar %{instance} + aliases: + add_new: Cruthaigh ailias + created_msg: D'Ă©irigh le hailias nua a chruthĂº. Is fĂ©idir leat an t-aistriĂº Ă³n seanchuntas a thionscnamh anois. + deleted_msg: D'Ă©irigh leis an ailias a bhaint. NĂ­ bheidh sĂ© indĂ©anta a thuilleadh bogadh Ă³n gcuntas sin chuig an gceann seo. + empty: NĂ­l aon ailiasanna agat. + hint_html: MĂ¡s mian leat bogadh Ă³ chuntas eile go dtĂ­ an ceann seo, anseo is fĂ©idir leat ailias a chruthĂº, a theastaĂ­onn sular fĂ©idir leat leanĂºint ar aghaidh le leantĂ³irĂ­ a bhogadh Ă³n seanchuntas go dtĂ­ an ceann seo. TĂ¡ an gnĂ­omh seo ann fĂ©in neamhdhĂ­obhĂ¡lach agus inchĂºlaithe. Cuirtear tĂºs leis an aistriĂº cuntais Ă³n seanchuntas. + remove: DĂ­cheangail ailias + appearance: + advanced_web_interface: ComhĂ©adan grĂ©asĂ¡in chun cinn + advanced_web_interface_hint: 'MĂ¡s mian leat ĂºsĂ¡id a bhaint as do leithead scĂ¡ileĂ¡in ar fad, ceadaĂ­onn an comhĂ©adan grĂ©asĂ¡in ardleibhĂ©il duit go leor colĂºin Ă©agsĂºla a chumrĂº chun an oiread faisnĂ©ise a fheiceĂ¡il ag an am cĂ©anna agus is mian leat: Baile, fĂ³graĂ­, amlĂ­ne chĂ³naidhme, aon lĂ­on liostaĂ­ agus hashtags.' + animations_and_accessibility: Beochan agus inrochtaineacht + confirmation_dialogs: DialĂ³ga deimhnithe + discovery: Fionnachtain + localization: + body: AistrĂ­onn oibrithe deonacha Mastodon. + guide_link: https://crowdin.com/project/mastodon + guide_link_text: Is fĂ©idir le gach duine rannchuidiĂº. + sensitive_content: Ăbhar Ă­ogair + application_mailer: + notification_preferences: Athraigh roghanna rĂ­omhphoist + salutation: "%{name}," + settings: 'Athraigh sainroghanna rĂ­omhphoist: %{link}' + unsubscribe: DĂ­liostĂ¡il + view: 'Amharc:' + view_profile: FĂ©ach ar phrĂ³ifĂ­l + view_status: FĂ©ach ar phostĂ¡il + applications: + created: D'Ă©irigh leis an bhfeidhmchlĂ¡r a chruthĂº + destroyed: D'Ă©irigh leis an bhfeidhmchlĂ¡r a scriosadh + logout: LogĂ¡il Amach + regenerate_token: Athghin comhartha rochtana + token_regenerated: D'Ă©irigh le hathghiniĂºint an comhartha rochtana + warning: BĂ­ an-chĂºramach leis na sonraĂ­ seo. NĂ¡ roinn Ă© le haon duine riamh! + your_token: Do chomhartha rochtana auth: + apply_for_account: Iarr cuntas + captcha_confirmation: + help_html: MĂ¡ tĂ¡ fadhbanna agat ag rĂ©iteach an CAPTCHA, is fĂ©idir leat dul i dteagmhĂ¡il linn trĂ­ %{email} agus is fĂ©idir linn cabhrĂº leat. + hint_html: Ach rud amhĂ¡in eile! NĂ­ mĂ³r dĂºinn a dhearbhĂº gur duine daonna thĂº (tĂ¡ sĂ© seo ionas gur fĂ©idir linn an turscar a choinneĂ¡il amach!). RĂ©itigh an CAPTCHA thĂ­os agus cliceĂ¡il "Ar aghaidh". + title: SeiceĂ¡il slĂ¡ndĂ¡la + confirmations: + awaiting_review: TĂ¡ do sheoladh r-phoist deimhnithe! TĂ¡ do chlĂ¡rĂºchĂ¡n Ă¡ athbhreithniĂº ag foireann %{domain} anois. Gheobhaidh tĂº r-phost mĂ¡ fhaomhann siad do chuntas! + awaiting_review_title: TĂ¡ do chlĂ¡rĂº Ă¡ athbhreithniĂº + clicking_this_link: ag cliceĂ¡il ar an nasc seo + login_link: logĂ¡il isteach + proceed_to_login_html: Is fĂ©idir leat dul ar aghaidh chuig %{login_link} anois. + redirect_to_app_html: Ba cheart go ndearnadh tĂº a atreorĂº chuig an aip %{app_name}. Murar tharla sin, bain triail as %{clicking_this_link} nĂ³ fill ar an aip de lĂ¡imh. + registration_complete: TĂ¡ do chlĂ¡rĂº ar %{domain} crĂ­ochnaithe anois! + welcome_title: FĂ¡ilte, %{name}! + wrong_email_hint: Mura bhfuil an seoladh rĂ­omhphoist sin ceart, is fĂ©idir leat Ă© a athrĂº i socruithe cuntais. delete_account: Scrios cuntas + delete_account_html: MĂ¡s mian leat do chuntas a scriosadh, is fĂ©idir leat leanĂºint ar aghaidh anseo. Iarrfar ort deimhniĂº. + description: + prefix_invited_by_user: Tugann @%{name} cuireadh duit pĂ¡irt a ghlacadh sa fhreastalaĂ­ seo de Mastodon! + prefix_sign_up: ClĂ¡raigh ar Mastodon inniu! + suffix: Le cuntas, beidh tĂº in ann daoine a leanĂºint, nuashonruithe a phostĂ¡il agus teachtaireachtaĂ­ a mhalartĂº le hĂºsĂ¡ideoirĂ­ Ă³ aon fhreastalaĂ­ Mastodon agus nĂ­os mĂ³! + didnt_get_confirmation: Nach bhfuair tĂº nasc deimhnithe? + dont_have_your_security_key: Nach bhfuil d'eochair shlĂ¡ndĂ¡la agat? + forgot_password: Ar rinne tĂº dearmad ar do PhĂ¡sfhocail? + invalid_reset_password_token: TĂ¡ comhartha athshocraithe pasfhocail neamhbhailĂ­ nĂ³ imithe in Ă©ag. Iarr ceann nua le do thoil. + link_to_otp: Cuir isteach cĂ³d dhĂ¡ fhachtĂ³ir Ă³ do ghuthĂ¡n nĂ³ cĂ³d aisghabhĂ¡la + link_to_webauth: ĂsĂ¡id d'eochair shlĂ¡ndĂ¡la glĂ©as + log_in_with: LogĂ¡il isteach le login: LogĂ¡il isteach logout: LogĂ¡il Amach + migrate_account: Bog chuig cuntas eile + migrate_account_html: MĂ¡s mian leat an cuntas seo a atreorĂº chuig ceann eile, is fĂ©idir leat Ă© a chumrĂº anseo. or_log_in_with: NĂ³ logĂ¡il isteach le + privacy_policy_agreement_html: LĂ©igh mĂ© agus aontaĂ­m leis an polasaĂ­ prĂ­obhĂ¡ideachais + progress: + confirm: Deimhnigh RĂ­omhphost + details: Do chuid sonraĂ­ + review: Ăr lĂ©irmheas + rules: Glac le rialacha + providers: + cas: CAS + saml: SAML register: ClĂ¡rĂº + registration_closed: NĂ­l %{instance} ag glacadh le baill nua + resend_confirmation: Seol an nasc deimhnithe arĂ­s + reset_password: Athshocraigh pasfhocal + rules: + accept: Glac + back: Ar ais + invited_by: 'Is fĂ©idir leat pĂ¡irt a ghlacadh i %{domain} a bhuĂ­ochas leis an gcuireadh a fuair tĂº Ă³:' + preamble: SocraĂ­onn agus cuireann na modhnĂ³irĂ­ %{domain} iad seo i bhfeidhm. + preamble_invited: Sula dtĂ©ann tĂº ar aghaidh, smaoinigh le do thoil ar na bunrialacha atĂ¡ socraithe ag modhnĂ³irĂ­ %{domain}. + title: Roinnt bunrialacha. + title_invited: TĂ¡ cuireadh faighte agat. security: SlĂ¡ndĂ¡il + set_new_password: Socraigh pasfhocal nua + setup: + email_below_hint_html: SeiceĂ¡il d'fhillteĂ¡n turscair, nĂ³ iarr ceann eile. Is fĂ©idir leat do sheoladh r-phoist a cheartĂº mĂ¡ tĂ¡ sĂ© mĂ­cheart. + email_settings_hint_html: CliceĂ¡il ar an nasc a sheol muid chugat chun %{email} a fhĂ­orĂº. Beidh muid ag fanacht ar dheis anseo. + link_not_received: Nach bhfuair tĂº nasc? + new_confirmation_instructions_sent: Gheobhaidh tĂº r-phost nua leis an nasc deimhnithe i gceann cĂºpla bomaite! + title: SeiceĂ¡il do bhosca isteach + sign_in: + preamble_html: LogĂ¡il isteach le do dhintiĂºir %{domain}. MĂ¡ tĂ¡ do chuntas Ă¡ Ă³stĂ¡il ar fhreastalaĂ­ eile, nĂ­ bheidh tĂº in ann logĂ¡il isteach anseo. + title: LogĂ¡il isteach go %{domain} + sign_up: + manual_review: TĂ©ann clĂ¡rĂºchĂ¡in ar %{domain} trĂ­ athbhreithniĂº lĂ¡imhe ag Ă¡r modhnĂ³irĂ­. Chun cabhrĂº linn do chlĂ¡rĂºchĂ¡n a phrĂ³iseĂ¡il, scrĂ­obh beagĂ¡n fĂºt fĂ©in agus cĂ©n fĂ¡th a bhfuil cuntas uait ar %{domain}. + preamble: Le cuntas ar an bhfreastalaĂ­ Mastodon seo, beidh tĂº in ann aon duine eile ar an lĂ­onra a leanĂºint, beag beann ar an Ă¡it a bhfuil a gcuntas Ă¡ Ă³stĂ¡il. + title: DĂ©anaimis tĂº a shocrĂº ar %{domain}. status: account_status: StĂ¡das cuntais + confirming: Ag fanacht le deimhniĂº r-phoist a bheith crĂ­ochnaithe. + functional: TĂ¡ do chuntas ag feidhmiĂº go hiomlĂ¡n. + pending: TĂ¡ d’iarratas ar feitheamh athbhreithnithe ag Ă¡r bhfoireann. Seans go dtĂ³gfaidh sĂ© seo roinnt ama. Gheobhaidh tĂº rĂ­omhphost mĂ¡ cheadaĂ­tear d’iarratas. + redirecting_to: TĂ¡ do chuntas neamhghnĂ­omhach toisc go bhfuil sĂ© Ă¡ atreorĂº chuig %{acct} faoi lĂ¡thair. + self_destruct: Toisc go bhfuil %{domain} ag dĂºnadh sĂ­os, nĂ­ bhfaighidh tĂº ach rochtain theoranta ar do chuntas. + view_strikes: FĂ©ach ar stailceanna san am atĂ¡ caite i gcoinne do chuntais too_fast: Cuireadh an fhoirm isteach rĂ³thapa, triail arĂ­s. + use_security_key: ĂsĂ¡id eochair shlĂ¡ndĂ¡la challenge: confirm: Lean ar aghaidh + hint_html: "Leid: NĂ­ iarrfaimid do phasfhocal ort arĂ­s go ceann uair an chloig eile." + invalid_password: Pasfhocal neamhbhailĂ­ + prompt: Deimhnigh an pasfhocal chun leanĂºint ar aghaidh + crypto: + errors: + invalid_key: nach eochair bhailĂ­ Ed25519 nĂ³ Curve25519 Ă­ + invalid_signature: nach sĂ­niĂº bailĂ­ Ed25519 Ă© + date: + formats: + default: "%b %d, %Y" + with_month_name: "%B %d, %Y" datetime: distance_in_words: about_x_hours: "%{count}u" @@ -340,6 +1201,7 @@ ga: about_x_years: "%{count}b" almost_x_years: "%{count}b" half_a_minute: DĂ­reach anois + less_than_x_minutes: "%{count}m" less_than_x_seconds: DĂ­reach anois over_x_years: "%{count}b" x_days: "%{count}l" @@ -347,45 +1209,243 @@ ga: x_months: "%{count}m" x_seconds: "%{count}s" deletes: + challenge_not_passed: NĂ­ raibh an fhaisnĂ©is a d'iontrĂ¡il tĂº ceart + confirm_password: Cuir isteach do phasfhocal reatha chun d'aitheantas a fhĂ­orĂº + confirm_username: Cuir isteach d'ainm ĂºsĂ¡ideora chun an nĂ³s imeachta a dhearbhĂº proceed: Scrios cuntas + success_msg: Scriosadh do chuntas go rathĂºil + warning: + before: 'Sula dtĂ©ann tĂº ar aghaidh, lĂ©igh na nĂ³taĂ­ seo go cĂºramach le do thoil:' + caches: Seans go seasfaidh inneachar atĂ¡ i dtaisce ag freastalaithe eile + data_removal: Bainfear do phostĂ¡lacha agus sonraĂ­ eile go buan + email_change_html: Is fĂ©idir leat do sheoladh rĂ­omhphoist a athrĂº gan do chuntas a scriosadh + email_contact_html: Mura dtagann sĂ© fĂ³s, is fĂ©idir leat rĂ­omhphost a chur chuig %{email} chun cabhair a fhĂ¡il + email_reconfirmation_html: Mura bhfuil an rĂ­omhphost deimhnithe Ă¡ fhĂ¡il agat, is fĂ©idir Ă© a iarraidh arĂ­s + irreversible: NĂ­ bheidh tĂº in ann do chuntas a aischur nĂ³ a athghnĂ­omhachtĂº + more_details_html: Le haghaidh tuilleadh sonraĂ­, fĂ©ach an polasaĂ­ prĂ­obhĂ¡ideachais. + username_available: Cuirfear d'ainm ĂºsĂ¡ideora ar fĂ¡il arĂ­s + username_unavailable: NĂ­ bheidh d'ainm ĂºsĂ¡ideora ar fĂ¡il fĂ³s disputes: strikes: + action_taken: GnĂ­omh dĂ©anta + appeal: Achomharc + appeal_approved: D’éirigh le hachomharc a dhĂ©anamh ar an stailc seo agus nĂ­l sĂ© bailĂ­ a thuilleadh + appeal_rejected: DiĂºltaĂ­odh don achomharc appeal_submitted_at: Achomharc curtha isteach appealed_msg: Cuireadh isteach d'achomharc. MĂ¡ ceadĂ³far Ă©, cuirfear ar an eolas tĂº. appeals: submit: Cuir achomharc isteach + approve_appeal: Achomharc a cheadĂº + associated_report: TuarascĂ¡il ghaolmhar + created_at: DĂ¡taithe + description_html: Is gnĂ­omhartha iad seo a rinneadh i gcoinne do chuntais agus rabhaidh a sheol foireann %{instance} chugat. + recipient: Seolta chuig + reject_appeal: DiĂºltĂº achomharc + status: 'PostĂ¡il # %{id}' + status_removed: Baineadh an postĂ¡il den chĂ³ras cheana fĂ©in + title: "%{action} Ă³ %{date}" title_actions: + delete_statuses: Post a bhaint + disable: Reo cuntais + mark_statuses_as_sensitive: PostĂ¡lacha a mharcĂ¡il mar Ă­ogair none: Rabhadh + sensitive: An cuntas a mharcĂ¡il mar Ă­ogair + silence: Teorainn le cuntas + suspend: Cuntas a fhionraĂ­ + your_appeal_approved: TĂ¡ d’achomharc ceadaithe your_appeal_pending: Chuir tĂº achomharc isteach + your_appeal_rejected: DiĂºltaĂ­odh do d'achomharc + domain_validator: + invalid_domain: nach ainm fearainn bailĂ­ Ă© + edit_profile: + basic_information: Eolas bunĂºsach + hint_html: "Saincheap a bhfeiceann daoine ar do phrĂ³ifĂ­l phoiblĂ­ agus in aice le do phostĂ¡lacha. Is dĂ³ichĂ­ go leanfaidh daoine eile ar ais tĂº agus go n-idirghnĂ­omhĂ³idh siad leat nuair a bhĂ­onn prĂ³ifĂ­l lĂ­onta agus pictiĂºr prĂ³ifĂ­le agat." + other: Eile + errors: + '400': BhĂ­ an t-iarratas a chuir tĂº isteach neamhbhailĂ­ nĂ³ mĂ­chumtha. + '403': NĂ­l cead agat an leathanach seo a fheiceĂ¡il. + '404': NĂ­l an leathanach atĂ¡ uait anseo. + '406': NĂ­l an leathanach seo ar fĂ¡il san fhormĂ¡id iarrtha. + '410': NĂ­l an leathanach a bhĂ­ Ă¡ lorg agat ann a thuilleadh. + '422': + content: Theip ar fhĂ­orĂº slĂ¡ndĂ¡la. An bhfuil tĂº ag cur bac ar fhianĂ¡in? + title: Theip ar fhĂ­orĂº slĂ¡ndĂ¡la + '429': An iomarca iarratas + '500': + content: TĂ¡ brĂ³n orainn, ach chuaigh rud Ă©igin mĂ­cheart ar Ă¡r deireadh. + title: NĂ­l an leathanach seo ceart + '503': NĂ­orbh fhĂ©idir an leathanach a sheirbheĂ¡il mar gheall ar theip shealadach ar an bhfreastalaĂ­. + noscript_html: Chun feidhmchlĂ¡r grĂ©asĂ¡in Mastodon a ĂºsĂ¡id, cumasaigh JavaScript le do thoil. NĂ³, bain triail as ceann de na aipeanna dĂºchasacha do Mastodon do d'ardĂ¡n. + existing_username_validator: + not_found: nĂ­orbh fhĂ©idir ĂºsĂ¡ideoir Ă¡itiĂºil a aimsiĂº leis an ainm ĂºsĂ¡ideora sin + not_found_multiple: nĂ­orbh fhĂ©idir %{usernames} a aimsiĂº exports: archive_takeout: date: DĂ¡ta + download: Ăosluchtaigh cartlann do rang + hint_html: Is fĂ©idir leat cartlann de do postĂ¡lacha agus meĂ¡in uaslĂ³dĂ¡ilte a iarraidh. Beidh na sonraĂ­ easpĂ³rtĂ¡ilte i bhformĂ¡id ActivityPub, inlĂ©ite ag aon bhogearraĂ­ comhlĂ­ontacha. Is fĂ©idir leat cartlann a iarraidh gach 7 lĂ¡. + in_progress: Do chartlann Ă¡ tiomsĂº... + request: Iarr do chartlann size: MĂ©id + blocks: Bac leat + bookmarks: Leabharmharcanna + csv: CSV + domain_blocks: Bloic fearainn lists: LiostaĂ­ + mutes: BalbhaĂ­onn tĂº + storage: StĂ³rĂ¡il meĂ¡in + featured_tags: + add_new: Cuir nua leis + errors: + limit: TĂ¡ uaslĂ­on na hashtags le feiceĂ¡il agat cheana fĂ©in + hint_html: "Ăirigh na haischlibeanna is tĂ¡bhachtaĂ­ ar do phrĂ³ifĂ­l. Uirlis iontach chun sĂºil a choinneĂ¡il ar do shaothair chruthaitheacha agus do thionscadail fhadtĂ©armacha, taispeĂ¡ntar haischlibeanna faoi thrĂ¡cht in Ă¡it fheiceĂ¡lach ar do phrĂ³ifĂ­l agus ceadaĂ­onn siad rochtain thapa ar do phostĂ¡lacha fĂ©in." filters: contexts: + account: PrĂ³ifĂ­lĂ­ home: Baile agus liostaĂ­ notifications: FĂ³graĂ­ + public: AmlĂ­nte poiblĂ­ thread: ComhrĂ¡ite edit: add_keyword: Cruthaigh eochairfhocal keywords: Eochairfhocal + statuses: Poist aonair + statuses_hint_html: Baineann an scagaire seo le postĂ¡lacha aonair a roghnĂº is cuma mĂ¡ mheaitseĂ¡lann siad leis na heochairfhocail thĂ­os. DĂ©an postĂ¡lacha a athbhreithniĂº nĂ³ a bhaint den scagaire. + title: Cuir an scagaire in eagar + errors: + deprecated_api_multiple_keywords: NĂ­ fĂ©idir na paraimĂ©adair seo a athrĂº Ă³n bhfeidhmchlĂ¡r seo toisc go mbaineann siad le nĂ­os mĂ³ nĂ¡ eochairfhocal scagaire amhĂ¡in. ĂsĂ¡id feidhmchlĂ¡r nĂ­os dĂ©anaĂ­ nĂ³ an comhĂ©adan grĂ©asĂ¡in. + invalid_context: NĂ­or solĂ¡thraĂ­odh aon cheann nĂ³ comhthĂ©acs neamhbhailĂ­ index: + contexts: ScagairĂ­ i %{contexts} delete: Scrios empty: NĂ­l aon scagairĂ­ agat. + expires_in: In Ă©ag i %{distance} + expires_on: Rachaidh sĂ© in Ă©ag ar %{date} + keywords: + few: "%{count} eochairfhocal" + many: "%{count} eochairfhocal" + one: "%{count} eochairfhocal" + other: "%{count} eochairfhocal" + two: "%{count} eochairfhocal" + statuses: + few: "%{count} postĂ¡il" + many: "%{count} postĂ¡il" + one: "%{count} postĂ¡il" + other: "%{count} postĂ¡il" + two: "%{count} postĂ¡il" + statuses_long: + few: "%{count} postĂ¡il aonair folaithe" + many: "%{count} postĂ¡il aonair folaithe" + one: "%{count} postĂ¡il aonair i bhfolach" + other: "%{count} postĂ¡il aonair folaithe" + two: "%{count} postĂ¡il aonair folaithe" title: ScagairĂ­ + new: + save: SĂ¡bhĂ¡il scagaire nua + title: Cuir scagaire nua leis + statuses: + back_to_filter: Ar ais go dtĂ­ an scagaire + batch: + remove: Bain as an scagaire + index: + hint: Baineann an scagaire seo le poist aonair a roghnĂº beag beann ar chritĂ©ir eile. Is fĂ©idir leat tuilleadh postĂ¡lacha a chur leis an scagaire seo Ă³n gcomhĂ©adan grĂ©asĂ¡in. + title: PostĂ¡lacha scagtha generic: + all: Gach + all_items_on_page_selected_html: + few: TĂ¡ gach %{count} mĂ­r ar an leathanach seo roghnaithe. + many: TĂ¡ gach %{count} mĂ­r ar an leathanach seo roghnaithe. + one: TĂ¡ %{count} mĂ­r ar an leathanach seo roghnaithe. + other: TĂ¡ gach %{count} mĂ­r ar an leathanach seo roghnaithe. + two: TĂ¡ gach %{count} mĂ­r ar an leathanach seo roghnaithe. + all_matching_items_selected_html: + few: TĂ¡ gach %{count} mĂ­r a thagann le do chuardach roghnaithe. + many: TĂ¡ gach %{count} mĂ­r a thagann le do chuardach roghnaithe. + one: TĂ¡ %{count} mĂ­r a thagann le do chuardach roghnaithe. + other: TĂ¡ gach %{count} mĂ­r a thagann le do chuardach roghnaithe. + two: TĂ¡ gach %{count} mĂ­r a thagann le do chuardach roghnaithe. + cancel: Cealaigh + changes_saved_msg: SĂ¡bhĂ¡ladh na hathruithe! + confirm: Deimhnigh copy: CĂ³ipeĂ¡il delete: Scrios + deselect: DĂ­roghnaigh go lĂ©ir + none: Dada + order_by: OrdĂº le + save_changes: SabhĂ¡il na hathruithe + select_all_matching_items: + few: Roghnaigh gach %{count} mĂ­r a thagann le do chuardach. + many: Roghnaigh gach %{count} mĂ­r a thagann le do chuardach. + one: Roghnaigh %{count} mĂ­r a thagann le do chuardach. + other: Roghnaigh gach %{count} mĂ­r a thagann le do chuardach. + two: Roghnaigh gach %{count} mĂ­r a thagann le do chuardach. today: inniu + validation_errors: + few: NĂ­l rud Ă©igin ceart go leor fĂ³s! DĂ©an athbhreithniĂº ar %{count} earrĂ¡id thĂ­os + many: NĂ­l rud Ă©igin ceart go leor fĂ³s! DĂ©an athbhreithniĂº ar %{count} earrĂ¡id thĂ­os + one: NĂ­l rud Ă©igin ceart go leor fĂ³s! DĂ©an athbhreithniĂº ar an earrĂ¡id thĂ­os + other: NĂ­l rud Ă©igin ceart go leor fĂ³s! DĂ©an athbhreithniĂº ar %{count} earrĂ¡id thĂ­os + two: NĂ­l rud Ă©igin ceart go leor fĂ³s! DĂ©an athbhreithniĂº ar %{count} earrĂ¡id thĂ­os imports: + errors: + empty: Comhad CSV folamh + incompatible_type: Neamh-chomhoiriĂºnach leis an gcineĂ¡l iompĂ³rtĂ¡la roghnaithe + invalid_csv_file: 'Comhad CSV neamhbhailĂ­. EarrĂ¡id: %{error}' + over_rows_processing_limit: nĂ­os mĂ³ nĂ¡ %{count} sraitheanna + too_large: TĂ¡ an comhad rĂ³-mhĂ³r + failures: Teipeanna + imported: IompĂ³rtĂ¡ilte + mismatched_types_warning: Is cosĂºil gur roghnaigh tĂº an cineĂ¡l mĂ­cheart don iompĂ³rtĂ¡il seo, seiceĂ¡il arĂ­s le do thoil. modes: merge: Cumaisc + merge_long: Coinnigh taifid atĂ¡ ann cheana fĂ©in agus cuir cinn nua leis overwrite: ForscrĂ­obh + overwrite_long: Cuir na cinn nua in ionad na dtaifead reatha + overwrite_preambles: + blocking_html: TĂ¡ tĂº ar tĂ­ do liosta bloc a chur in ionad suas le %{total_items} cuntas Ă³ %{filename}. + bookmarks_html: TĂ¡ tĂº ar tĂ­ do leabharmharcanna a chur in ionad suas le %{total_items} postĂ¡il Ă³ %{filename}. + domain_blocking_html: TĂ¡ tĂº ar tĂ­ do liosta bloc fearainn a chur in ionad suas le %{total_items} fearainn Ă³ %{filename}. + following_html: TĂ¡ tĂº ar tĂ­ leanĂºint suas go dtĂ­ %{total_items} cuntas Ă³ %{filename} agus stop a leanĂºint aon duine eile. + lists_html: TĂ¡ tĂº ar tĂ­ do liostaĂ­ a chur in ionad inneachair %{filename}. Cuirfear suas le %{total_items} cuntas le liostaĂ­ nua. + muting_html: TĂ¡ tĂº ar tĂ­ do liosta cuntas balbhaithe a chur in ionad suas le %{total_items} cuntas Ă³ %{filename}. + preambles: + blocking_html: TĂ¡ tĂº ar tĂ­ bloc suas le %{total_items} cuntas Ă³ %{filename}. + bookmarks_html: TĂ¡ tĂº ar tĂ­ %{total_items} postĂ¡il Ă³ %{filename} a chur le do leabharmharcanna. + domain_blocking_html: TĂ¡ tĂº ar tĂ­ bloc suas le %{total_items} fearainn Ă³ %{filename}. + following_html: TĂ¡ tĂº ar tĂ­ leanĂºint suas go dtĂ­ %{total_items} cuntas Ă³ %{filename}. + lists_html: TĂ¡ tĂº ar tĂ­ %{total_items} cuntas Ă³ %{filename} a chur le do liostaĂ­. CruthĂ³far liostaĂ­ nua mura bhfuil aon liosta le cur leis. + muting_html: TĂ¡ tĂº ar tĂ­ balbhĂº suas le %{total_items} cuntas Ă³ %{filename}. + preface: Is fĂ©idir leat sonraĂ­ a d’easpĂ³rtĂ¡il tĂº a allmhairiĂº Ă³ fhreastalaĂ­ eile, mar shampla liosta de na daoine a bhfuil tĂº ag leanĂºint nĂ³ ag cur bac orthu. + recent_imports: AllmhairĂ­ le dĂ©anaĂ­ + states: + finished: CrĂ­ochnaithe + in_progress: Ar siĂºl + scheduled: Sceidealta + unconfirmed: Neamhdhearbhaithe + status: StĂ¡das + success: UaslĂ³dĂ¡ladh do shonraĂ­ go rathĂºil agus prĂ³iseĂ¡lfar iad in am trĂ¡tha + time_started: Thosaigh ag + titles: + blocking: Cuntais bhlocĂ¡ilte Ă¡ n-iompĂ³rtĂ¡il + bookmarks: Leabharmharcanna Ă¡ n-iompĂ³rtĂ¡il + domain_blocking: Fearainn blocĂ¡ilte Ă¡ n-iompĂ³rtĂ¡il + following: Cuntais leanta Ă¡ n-iompĂ³rtĂ¡il + lists: LiostaĂ­ Ă¡ n-iompĂ³rtĂ¡il + muting: Cuntais bhalbhaithe Ă¡ n-iompĂ³rtĂ¡il + type: CineĂ¡l iompĂ³rtĂ¡la + type_groups: + constructive: Seo a leanas & Leabharmharcanna + destructive: Bloic agus balbhaigh types: + blocking: Liosta blocĂ¡la bookmarks: Leabharmharcanna + domain_blocking: Liosta blocĂ¡la fearainn + following: Liosta ina dhiaidh sin + lists: LiostaĂ­ + muting: Liosta muting upload: UaslĂ³dĂ¡il invites: + delete: DĂ­ghnĂ­omhachtaigh expired: As feidhm expires_in: '1800': 30 nĂ³imĂ©id @@ -395,43 +1455,230 @@ ga: '604800': Seachtain amhĂ¡in '86400': LĂ¡ amhĂ¡in expires_in_prompt: In am ar bith + generate: Gin nasc cuireadh + invalid: NĂ­l an cuireadh seo bailĂ­ + invited_by: 'Fuair ​​tĂº cuireadh Ă³:' + max_uses: + few: ĂsĂ¡ideann %{count} + many: ĂsĂ¡ideann %{count} + one: 1 ĂºsĂ¡id + other: ĂsĂ¡ideann %{count} + two: ĂsĂ¡ideann %{count} + max_uses_prompt: Gan teorainn + prompt: Gin agus roinn naisc le daoine eile chun rochtain a dheonĂº ar an bhfreastalaĂ­ seo + table: + expires_at: In Ă©ag + uses: ĂsĂ¡idĂ­ + title: Tabhair cuireadh do dhaoine + lists: + errors: + limit: TĂ¡ uaslĂ­on na liostaĂ­ sroichte agat login_activities: authentication_methods: + otp: app fĂ­ordheimhnithe dhĂ¡-fachtĂ³ir password: pasfhocal + sign_in_token: cĂ³d slĂ¡ndĂ¡la rĂ­omhphoist webauthn: eochracha slĂ¡ndĂ¡la + description_html: MĂ¡ fheiceann tĂº gnĂ­omhaĂ­ocht nach n-aithnĂ­onn tĂº, smaoinigh ar do phasfhocal a athrĂº agus fĂ­ordheimhniĂº dhĂ¡ fhachtĂ³ir a chumasĂº. + empty: NĂ­l aon stair fĂ­ordheimhnithe ar fĂ¡il + failed_sign_in_html: Theip ar iarracht sĂ­niĂº isteach le %{method} Ă³ %{ip} (%{browser}) + successful_sign_in_html: D'Ă©irigh le sĂ­niĂº isteach le %{method} Ă³ %{ip} (%{browser}) + title: Stair fĂ­ordheimhnithe + mail_subscriptions: + unsubscribe: + action: Sea, dĂ­liostĂ¡il + complete: Gan liostĂ¡il + confirmation_html: An bhfuil tĂº cinnte gur mhaith leat dĂ­liostĂ¡il Ă³ %{type} a fhĂ¡il do Mastodon ar %{domain} chuig do rĂ­omhphost ag %{email}? Is fĂ©idir leat liostĂ¡il arĂ­s i gcĂ³naĂ­ Ă³ do socruithe fĂ³gra rĂ­omhphoist. + emails: + notification_emails: + favourite: r-phoist fĂ³gra is fearr leat + follow: r-phoist fĂ³gra a leanĂºint + follow_request: r-phoist iarratais a leanĂºint + mention: trĂ¡cht ar r-phoist fĂ³gra + reblog: r-phoist fĂ³gra a threisiĂº + resubscribe_html: MĂ¡ dhĂ­liostĂ¡il tĂº de dhearmad, is fĂ©idir leat liostĂ¡il arĂ­s Ă³ do socruithe fĂ³gra rĂ­omhphoist. + success_html: NĂ­ bhfaighidh tĂº %{type} le haghaidh Mastodon ar %{domain} chuig do rĂ­omhphost ag %{email} a thuilleadh. + title: DĂ­liostĂ¡il + media_attachments: + validations: + images_and_video: NĂ­ fĂ©idir fĂ­seĂ¡n a cheangal le postĂ¡il a bhfuil Ă­omhĂ¡nna ann cheana fĂ©in + not_ready: NĂ­ fĂ©idir comhaid nach bhfuil prĂ³iseĂ¡il crĂ­ochnaithe acu a cheangal. Bain triail eile as i gceann nĂ³imĂ©ad! + too_many: NĂ­ fĂ©idir nĂ­os mĂ³ nĂ¡ 4 chomhad a cheangal + migrations: + acct: Bogtha go + cancel: Cealaigh atreorĂº + cancel_explanation: MĂ¡ chuirtear an t-atreorĂº ar ceal, dĂ©anfar do chuntas reatha a athghnĂ­omhĂº, ach nĂ­ thabharfaidh sĂ© seo leantĂ³irĂ­ a aistrĂ­odh chuig an gcuntas sin ar ais. + cancelled_msg: D'Ă©irigh leis an atreorĂº a chealĂº. + errors: + already_moved: an cuntas cĂ©anna ar bhog tĂº chuige cheana + missing_also_known_as: nach ailias den chuntas seo Ă© + move_to_self: nĂ­ fĂ©idir Ă© a bheith ina chuntas reatha + not_found: nĂ­orbh fhĂ©idir a fhĂ¡il + on_cooldown: TĂ¡ tĂº ar fuarĂº + followers_count: LeantĂ³irĂ­ ag am aistrithe + incoming_migrations: Ag bogadh Ă³ chuntas eile + incoming_migrations_html: Chun bogadh Ă³ chuntas eile go dtĂ­ an ceann seo, nĂ­ mĂ³r duit ailias cuntais a chruthĂº ar dtĂºs. + moved_msg: TĂ¡ do chuntas Ă¡ atreorĂº chuig %{acct} anois agus tĂ¡ do leantĂ³irĂ­ Ă¡ bhogadh anonn. + not_redirecting: NĂ­l do chuntas Ă¡ atreorĂº chuig aon chuntas eile faoi lĂ¡thair. + on_cooldown: D'aistrigh tĂº do chuntas le dĂ©anaĂ­. Beidh an fheidhm seo ar fĂ¡il arĂ­s i gceann %{count} lĂ¡. + past_migrations: Imirce san am a chuaigh thart + proceed_with_move: Bog leantĂ³irĂ­ + redirected_msg: TĂ¡ do chuntas Ă¡ atreorĂº chuig %{acct} anois. + redirecting_to: TĂ¡ do chuntas Ă¡ atreorĂº chuig %{acct}. + set_redirect: Socraigh atreorĂº + warning: + backreference_required: NĂ­ mĂ³r an cuntas nua a chumrĂº ar dtĂºs chun cĂºltagairt a dhĂ©anamh don cheann seo + before: 'Sula dtĂ©ann tĂº ar aghaidh, lĂ©igh na nĂ³taĂ­ seo go cĂºramach le do thoil:' + cooldown: Tar Ă©is bogadh tĂ¡ trĂ©imhse feithimh ann nach mbeidh tĂº in ann bogadh arĂ­s + disabled_account: NĂ­ bheidh do chuntas reatha inĂºsĂ¡idte go hiomlĂ¡n ina dhiaidh sin. Mar sin fĂ©in, beidh rochtain agat ar onnmhairiĂº sonraĂ­ chomh maith le hathghnĂ­omhĂº. + followers: Bogfaidh an gnĂ­omh seo gach leantĂ³ir Ă³n gcuntas reatha go dtĂ­ an cuntas nua + only_redirect_html: NĂ³, nĂ­ fĂ©idir leat ach atreorĂº a chur suas ar do phrĂ³ifĂ­l. + other_data: NĂ­ bhogfar aon sonraĂ­ eile go huathoibrĂ­och + redirect: DĂ©anfar prĂ³ifĂ­l do chuntais reatha a nuashonrĂº le fĂ³gra atreoraithe agus fĂ¡gfar as an Ă¡ireamh Ă© Ă³ chuardaigh + moderation: + title: Measarthacht + move_handler: + carry_blocks_over_text: Bhog an t-ĂºsĂ¡ideoir seo Ă³ %{acct}, rud a chuir tĂº bac air. + carry_mutes_over_text: Bhog an t-ĂºsĂ¡ideoir seo Ă³ %{acct}, rud a bhalbhaigh tĂº. + copy_account_note_text: 'Bhog an ĂºsĂ¡ideoir seo Ă³ %{acct}, seo do nĂ³taĂ­ roimhe seo fĂºthu:' + navigation: + toggle_menu: ScorĂ¡naigh roghchlĂ¡r notification_mailer: admin: report: subject: Chuir %{name} tuairisc isteach + sign_up: + subject: ChlĂ¡raigh %{name} + favourite: + body: 'B''fhearr le %{name} do phostĂ¡il:' + subject: B'fhearr le %{name} do phostĂ¡il + title: Nua is fearr leat follow: body: TĂ¡ %{name} do do leanĂºint anois! subject: TĂ¡ %{name} do do leanĂºint anois title: LeantĂ³irĂ­ nua + follow_request: + action: Bainistigh iarratais leantacha + body: D'iarr %{name} tĂº a leanĂºint + subject: 'LeantĂ³ir ar feitheamh: %{name}' + title: Iarratas leantach nua mention: action: Freagair + body: 'Luaigh %{name} thĂº i:' + subject: Luaigh %{name} thĂº + title: Lua nua + poll: + subject: ThĂ¡inig deireadh le vĂ³taĂ­ocht le %{name} reblog: + body: 'TreisĂ­odh do phostĂ¡il le %{name}:' subject: Mhol %{name} do phostĂ¡il title: Moladh nua + status: + subject: TĂ¡ %{name} dĂ­reach postĂ¡ilte + update: + subject: Chuir %{name} postĂ¡il in eagar + notifications: + administration_emails: FĂ³graĂ­ r-phoist admin + email_events: ImeachtaĂ­ le haghaidh fĂ³graĂ­ rĂ­omhphoist + email_events_hint: 'Roghnaigh imeachtaĂ­ ar mhaith leat fĂ³graĂ­ a fhĂ¡il ina leith:' + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T otp_authentication: + code_hint: Cuir isteach an cĂ³d ginte ag d'aip fĂ­ordheimhnitheora le deimhniĂº + description_html: MĂ¡ chumasaĂ­onn tĂº fĂ­ordheimhniĂº dhĂ¡ fhachtĂ³ir ag baint ĂºsĂ¡ide as aip fĂ­ordheimhneora, beidh ort do ghuthĂ¡n a bheith i seilbh logĂ¡il isteach, rud a ghinfidh comharthaĂ­ chun tĂº a chur isteach. enable: Cumasaigh + instructions_html: "Scan an cĂ³d QR seo isteach i Google Authenticator nĂ³ aip eile TOTP ar do ghuthĂ¡n. As seo amach, ginfidh an aip sin comharthaĂ­ a chaithfidh tĂº a chur isteach agus tĂº ag logĂ¡il isteach." + manual_instructions: 'Mura fĂ©idir leat an cĂ³d QR a scanadh agus mĂ¡s gĂ¡ duit Ă© a chur isteach de lĂ¡imh, seo an rĂºn gnĂ¡th-thĂ©acs:' + setup: Socraigh suas + wrong_code: BhĂ­ an cĂ³d a iontrĂ¡ladh neamhbhailĂ­! An bhfuil am freastalaĂ­ agus am glĂ©is ceart? pagination: newer: NĂ­os nuaĂ­ next: An cĂ©ad eile older: NĂ­os sine prev: Ceann roimhe seo + truncate: "…" + polls: + errors: + already_voted: TĂ¡ tĂº tar Ă©is vĂ³tĂ¡il ar an vĂ³taĂ­ocht seo cheana fĂ©in + duplicate_options: go bhfuil mĂ­reanna dĂºblacha + duration_too_long: rĂ³fhada amach anseo + duration_too_short: rĂ³-luath + expired: TĂ¡ deireadh leis an vĂ³taĂ­ocht cheana fĂ©in + invalid_choice: NĂ­l an rogha vĂ³tĂ¡la roghnaithe ann + over_character_limit: nĂ­ fĂ©idir leis a bheith nĂ­os faide nĂ¡ %{max} carachtar an ceann + self_vote: NĂ­ fĂ©idir leat vĂ³tĂ¡il i do phobalbhreith fĂ©in + too_few_options: caithfidh nĂ­os mĂ³ nĂ¡ mĂ­r amhĂ¡in a bheith ann + too_many_options: nĂ­ fĂ©idir nĂ­os mĂ³ nĂ¡ %{max} mĂ­r a bheith ann preferences: other: Eile + posting_defaults: RĂ©amhshocruithe Ă¡ bpostĂ¡il + public_timelines: AmlĂ­nte poiblĂ­ + privacy: + hint_html: "Saincheap conas is mian leat do phrĂ³ifĂ­l agus do phostĂ¡lacha a fhĂ¡il. Is fĂ©idir le gnĂ©ithe Ă©agsĂºla i Mastodon cabhrĂº leat teacht ar lucht fĂ©achana nĂ­os leithne nuair atĂ¡ tĂº cumasaithe. TĂ³g nĂ³imĂ©ad chun athbhreithniĂº a dhĂ©anamh ar na socruithe seo chun a chinntiĂº go n-oireann siad do do chĂ¡s ĂºsĂ¡ide." + privacy: PrĂ­obhĂ¡ideacht + privacy_hint_html: RialĂº ar an mĂ©id is mian leat a nochtadh ar mhaithe le daoine eile. AimsĂ­onn daoine prĂ³ifĂ­lĂ­ suimiĂºla agus aipeanna fionnuara trĂ­ na haipeanna seo a leanas a bhrabhsĂ¡il agus a fheiceĂ¡il cĂ© na haipeanna a bpostĂ¡lann siad, ach b’fhĂ©idir gurbh fhearr leat Ă© a choinneĂ¡il faoi cheilt. + reach: Shroich + reach_hint_html: Smacht a fhĂ¡il ar cĂ© acu is mian leat a fhĂ¡il amach agus daoine nua a leanĂºint. Ar mhaith leat do phostĂ¡lacha a thaispeĂ¡int ar an scĂ¡ileĂ¡n Explore? Ar mhaith leat go bhfeicfeadh daoine eile tĂº sna moltaĂ­ a leanann siad? Ar mhaith leat glacadh le gach leantĂ³ir nua go huathoibrĂ­och, nĂ³ smacht grĂ¡inneach a bheith agat ar gach leantĂ³ir? + search: Cuardach + search_hint_html: RialĂº conas ba mhaith leat a fhĂ¡il. Ar mhaith leat go bhfaighidh daoine tĂº trĂ­d an rud a chuir tĂº suas go poiblĂ­ faoi? Ar mhaith leat go bhfaighidh daoine lasmuigh de Mastodon do phrĂ³ifĂ­l agus iad ag cuardach an ghrĂ©asĂ¡in? Tabhair faoi deara le do thoil nach fĂ©idir eisiamh iomlĂ¡n Ă³ gach inneall cuardaigh a chinntiĂº mar fhaisnĂ©is don phobal. + title: PrĂ­obhĂ¡ideacht agus teacht + privacy_policy: + title: Beartas PrĂ­obhĂ¡ideachais + reactions: + errors: + limit_reached: Teorainn frithghnĂ­omhartha Ă©agsĂºla bainte amach + unrecognized_emoji: nĂ­ emoji aitheanta Ă© + redirects: + prompt: MĂ¡ tĂ¡ muinĂ­n agat as an nasc seo, cliceĂ¡il air chun leanĂºint ar aghaidh. + title: TĂ¡ tĂº ag fĂ¡gĂ¡il %{instance}. relationships: + activity: GnĂ­omhaĂ­ocht chuntais + confirm_follow_selected_followers: An bhfuil tĂº cinnte gur mhaith leat na leantĂ³irĂ­ roghnaithe a leanĂºint? + confirm_remove_selected_followers: An bhfuil tĂº cinnte gur mhaith leat na leantĂ³irĂ­ roghnaithe a bhaint? + confirm_remove_selected_follows: An bhfuil tĂº cinnte gur mhaith leat na nithe seo a leanas roghnaithe a bhaint? + dormant: DĂ­omhaoin + follow_failure: NĂ­orbh fhĂ©idir cuid de na cuntais roghnaithe a leanĂºint. follow_selected_followers: Lean leantĂ³irĂ­ roghnaithe followers: LeantĂ³irĂ­ following: Ag leanĂºint + invited: Cuireadh + last_active: GnĂ­omhach seo caite + most_recent: Is dĂ©anaĂ­ + moved: Ar athraĂ­odh a ionad + mutual: FrithphĂ¡irteach primary: PrĂ­omha + relationship: Gaol + remove_selected_domains: Remove all followers from the selected domains remove_selected_followers: Bain leantĂ³irĂ­ roghnaithe remove_selected_follows: DĂ­-lean ĂºsĂ¡ideoirĂ­ roghnaithe status: StĂ¡das cuntais + remote_follow: + missing_resource: NĂ­orbh fhĂ©idir an URL atreoraithe riachtanach do do chuntas a aimsiĂº + reports: + errors: + invalid_rules: nĂ­ thagraĂ­onn sĂ© do rialacha bailĂ­ rss: content_warning: 'Rabhadh Ă¡bhair:' + descriptions: + account: PostĂ¡lacha poiblĂ­ Ă³ @%{acct} + tag: 'PostĂ¡lacha poiblĂ­ clibĂ¡ilte # %{hashtag}' + scheduled_statuses: + over_daily_limit: TĂ¡ an teorainn de %{limit} postĂ¡il sceidealaithe sĂ¡raithe agat don lĂ¡ atĂ¡ inniu ann + over_total_limit: TĂ¡ an teorainn de %{limit} postĂ¡il sceidealaithe sĂ¡raithe agat + too_soon: Caithfidh an dĂ¡ta sceidealta a bheith sa todhchaĂ­ + self_destruct: + lead_html: Ar an drochuair, tĂ¡ %{domain} ag dĂºnadh sĂ­os go buan. MĂ¡ bhĂ­ cuntas agat ann, nĂ­ bheidh tĂº in ann leanĂºint ar aghaidh Ă¡ ĂºsĂ¡id, ach is fĂ©idir leat cĂºltaca de do shonraĂ­ a iarraidh fĂ³s. + title: TĂ¡ an freastalaĂ­ seo ag dĂºnadh sessions: + activity: An ghnĂ­omhaĂ­ocht dheireanach browser: BrabhsĂ¡laĂ­ browsers: alipay: Alipay @@ -441,41 +1688,162 @@ ga: electron: Electron firefox: Firefox generic: BrabhsĂ¡laĂ­ anaithnid + huawei_browser: BrabhsĂ¡laĂ­ Huawei + ie: Internet Explorer + micro_messenger: MicreascannĂ¡n + nokia: Nokia s40 Ovi BrabhsĂ¡laĂ­ + opera: Opera + otter: DobharchĂº + phantom_js: PhantomJS + qq: BrabhsĂ¡laĂ­ QQ + safari: Safari + uc_browser: BrabhsĂ¡laĂ­ UC + unknown_browser: BrabhsĂ¡laĂ­ Anaithnid + weibo: Weibo + current_session: SeisiĂºn reatha + date: DĂ¡ta + description: "%{browser} ar %{platform}" + explanation: Seo iad na brabhsĂ¡laithe grĂ©asĂ¡in atĂ¡ logĂ¡ilte isteach i do chuntas Mastodon faoi lĂ¡thair. + ip: IP platforms: + adobe_air: Adobe Air android: Android blackberry: BlackBerry chrome_os: ChromeOS firefox_os: Firefox OS ios: iOS + kai_os: KaiOS linux: Linux mac: macOS + unknown_platform: ArdĂ¡n Anaithnid windows: Windows windows_mobile: Windows Mobile windows_phone: Windows Phone + revoke: Aisghair + revoke_success: SeisiĂºn aisghairthe go rathĂºil title: SeisiĂºin + view_authentication_history: FĂ©ach ar stair fĂ­ordheimhnithe do chuntais settings: account: Cuntas account_settings: Socruithe cuntais + aliases: Ailiasanna cuntais appearance: Cuma + authorized_apps: Aipeanna Ăºdaraithe back: Ar ais go Mastodon + delete: Scriosadh cuntais development: Forbairt edit_profile: Cuir an phrĂ³ifĂ­l in eagar + export: EaspĂ³rtĂ¡il sonraĂ­ + featured_tags: Haischlib faoi thrĂ¡cht import: IompĂ³rtĂ¡il + import_and_export: IompĂ³rtĂ¡il agus easpĂ³rtĂ¡il + migrate: Imirce cuntais + notifications: FĂ³graĂ­ rĂ­omhphoist preferences: Sainroghanna pearsanta profile: PrĂ³ifĂ­l + relationships: LeantĂ³irĂ­ agus leanĂºna + severed_relationships: Caidrimh dhearfa + statuses_cleanup: Uathscriosadh postĂ¡la + strikes: Stailceanna measarthachta + two_factor_authentication: Ădar dhĂ¡-fhachtĂ³ir webauthn_authentication: Eochracha slĂ¡ndĂ¡la + severed_relationships: + download: ĂoslĂ³dĂ¡il (%{count}) + event_type: + account_suspension: FionraĂ­ cuntais (%{target_name}) + domain_block: FreastalaĂ­ ar fionraĂ­ (%{target_name}) + user_domain_block: Chuir tĂº bac ar %{target_name} + lost_followers: LeanĂºna caillte + lost_follows: Seo a leanas caillte + preamble: Seans go gcaillfidh tĂº seo a leanas agus a leantĂ³irĂ­ nuair a bhacĂ¡lann tĂº fearann ​​nĂ³ nuair a shocraĂ­onn do mhodhnĂ³irĂ­ cianfhreastalaĂ­ a chur ar fionraĂ­. Nuair a tharlaĂ­onn sĂ© sin, beidh tĂº in ann liostaĂ­ de chaidreamh deighilte a Ă­oslĂ³dĂ¡il, lena n-iniĂºchadh agus b'fhĂ©idir iompĂ³rtĂ¡il ar fhreastalaĂ­ eile. + purged: Glanadh faisnĂ©is faoin bhfreastalaĂ­ seo ag riarthĂ³irĂ­ do fhreastalaĂ­. + type: Imeacht statuses: + attached: + audio: + few: "%{count} fuaime" + many: "%{count} fuaime" + one: "%{count} fuaime" + other: "%{count} fuaime" + two: "%{count} fuaime" + description: 'Ceangailte: %{attached}' + image: + few: "%{count} hĂ­omhĂ¡nna" + many: "%{count} hĂ­omhĂ¡nna" + one: "%{count} Ă­omhĂ¡" + other: "%{count} hĂ­omhĂ¡nna" + two: "%{count} hĂ­omhĂ¡nna" + video: + few: "%{count} fĂ­seĂ¡in" + many: "%{count} fĂ­seĂ¡in" + one: "%{count} fĂ­seĂ¡n" + other: "%{count} fĂ­seĂ¡in" + two: "%{count} fĂ­seĂ¡in" boosted_from_html: Molta Ă³ %{acct_link} content_warning: 'Rabhadh Ă¡bhair: %{warning}' + default_language: Mar an gcĂ©anna le teanga an chomhĂ©adain + disallowed_hashtags: + few: 'bhĂ­ na Haischlib dĂ­cheadaithe: %{tags}' + many: 'bhĂ­ na Haischlib dĂ­cheadaithe: %{tags}' + one: 'bhĂ­ haischlib dĂ­cheadaithe: %{tags}' + other: 'bhĂ­ na Haischlib dĂ­cheadaithe: %{tags}' + two: 'bhĂ­ na Haischlib dĂ­cheadaithe: %{tags}' + edited_at_html: "%{date} curtha in eagar" + errors: + in_reply_not_found: Is cosĂºil nach ann don phostĂ¡il a bhfuil tĂº ag iarraidh freagra a thabhairt air. + open_in_web: Oscail i ngrĂ©asĂ¡n + over_character_limit: teorainn carachtar %{max} sĂ¡raithe + pin_errors: + direct: NĂ­ fĂ©idir postĂ¡lacha nach bhfuil le feiceĂ¡il ach ag ĂºsĂ¡ideoirĂ­ luaite a phinnĂ¡il + limit: TĂ¡ uaslĂ­on na bpostĂ¡lacha pinn agat cheana fĂ©in + ownership: NĂ­ fĂ©idir postĂ¡il duine Ă©igin eile a phionnĂ¡il + reblog: NĂ­ fĂ©idir treisiĂº a phinnĂ¡il poll: + total_people: + few: "%{count} daoine" + many: "%{count} daoine" + one: "%{count} duine" + other: "%{count} daoine" + two: "%{count} daoine" + total_votes: + few: "%{count} vĂ³taĂ­" + many: "%{count} vĂ³taĂ­" + one: "%{count} vĂ³ta" + other: "%{count} vĂ³taĂ­" + two: "%{count} vĂ³taĂ­" vote: VĂ³tĂ¡il show_more: TaispeĂ¡in nĂ­os mĂ³ show_thread: TaispeĂ¡in snĂ¡ithe + title: '%{name}: "%{quote}"' visibilities: + direct: DĂ­reach private: LeantĂ³irĂ­ amhĂ¡in private_long: TaispeĂ¡in do leantĂ³irĂ­ amhĂ¡in + public: PoiblĂ­ + public_long: Is fĂ©idir le gach duine a fheiceĂ¡il + unlisted: Neamhliostaithe + unlisted_long: Is fĂ©idir le gach duine a fheiceĂ¡il, ach nach bhfuil liostaithe ar amlĂ­nte poiblĂ­ statuses_cleanup: + enabled: Scrios seanphostĂ¡lacha go huathoibrĂ­och + enabled_hint: Scriostar do phostĂ¡lacha go huathoibrĂ­och nuair a shroicheann siad tairseach aoise sonraithe, ach amhĂ¡in mĂ¡ thagann siad le ceann de na heisceachtaĂ­ thĂ­os + exceptions: EisceachtaĂ­ + explanation: Toisc gur oibrĂ­ocht chostasach Ă© postĂ¡lacha a scriosadh, dĂ©antar Ă© seo go mall le himeacht ama nuair nach mbĂ­onn an freastalaĂ­ gnĂ³thach ar bhealach eile. Ar an Ă¡bhar sin, d’fhĂ©adfadh sĂ© go scriosfar do phostĂ¡lacha tamall tar Ă©is dĂ³ibh an tairseach aoise a bhaint amach. ignore_favs: Tabhair neamhaird ar toghanna + ignore_reblogs: DĂ©an neamhaird de boosts + interaction_exceptions: EisceachtaĂ­ bunaithe ar idirghnĂ­omhaĂ­ochtaĂ­ + interaction_exceptions_explanation: Tabhair faoi deara nach bhfuil aon rĂ¡thaĂ­ocht go scriosfar postĂ¡lacha mĂ¡ thĂ©ann siad faoi bhun na tairsĂ­ is ansa leat nĂ³ an teanndĂ¡ileog tar Ă©is dĂ³ibh dul thar iad uair amhĂ¡in. + keep_direct: Coinnigh teachtaireachtaĂ­ dĂ­reacha + keep_direct_hint: NĂ­ scriosann sĂ© aon cheann de do theachtaireachtaĂ­ dĂ­reacha + keep_media: Coinnigh postĂ¡lacha le ceangaltĂ¡in meĂ¡n + keep_media_hint: NĂ­ scriosann sĂ© aon cheann de do phostĂ¡lacha a bhfuil ceangaltĂ¡in meĂ¡n acu + keep_pinned: Coinnigh postĂ¡lacha pinn + keep_pinned_hint: NĂ­ scriosann sĂ© aon cheann de do phostĂ¡lacha pinn + keep_polls: Coinnigh pobalbhreith + keep_polls_hint: NĂ­ scriosann sĂ© aon cheann de do vĂ³taĂ­ochtaĂ­ + keep_self_bookmark: Coinnigh postĂ¡lacha leabharmharcĂ¡ilte agat + keep_self_bookmark_hint: NĂ­ scriosann sĂ© do phostĂ¡lacha fĂ©in mĂ¡ tĂ¡ leabharmharcĂ¡ilte agat + keep_self_fav: Coinnigh na poist a thaitin leat + keep_self_fav_hint: NĂ­ scriosann sĂ© do phostĂ¡lacha fĂ©in mĂ¡s fearr leat iad min_age: '1209600': CoicĂ­s '15778476': 6 mhĂ­ @@ -485,20 +1853,182 @@ ga: '604800': Seachtain amhĂ¡in '63113904': 2 bhliain '7889238': 3 mhĂ­ + min_age_label: Tairseach aoise + min_favs: Coinnigh na poist is fearr leat ar a laghad + min_favs_hint: NĂ­ scriosann sĂ© aon cheann de do phostĂ¡lacha a fuair ar a laghad an lĂ­on ceanĂ¡n seo. FĂ¡g bĂ¡n chun postĂ¡lacha a scriosadh beag beann ar lĂ­on na gceanĂ¡n atĂ¡ acu + min_reblogs: Coinnigh postĂ¡lacha treisithe ar a laghad + min_reblogs_hint: NĂ­ scriosann sĂ© aon cheann de do phostĂ¡lacha a cuireadh leis an lĂ­on seo uaireanta ar a laghad. FĂ¡g bĂ¡n chun postĂ¡lacha a scriosadh beag beann ar a lĂ­on teanndĂ¡ileog stream_entries: sensitive_content: Ăbhar Ă­ogair + strikes: + errors: + too_late: TĂ¡ sĂ© rĂ³-dhĂ©anach achomharc a dhĂ©anamh faoin stailc seo + tags: + does_not_match_previous_name: nach meaitseĂ¡lann an t-ainm roimhe seo + themes: + contrast: Mastodon (Codarsnacht ard) + default: Mastodon (Dorcha) + mastodon-light: Mastodon (Solas) + system: UathoibrĂ­och (ĂºsĂ¡id tĂ©ama cĂ³rais) + time: + formats: + default: "%b %d, %Y, %H:%M" + month: "%b %Y" + time: "%H:%M" + with_time_zone: "%b %d, %Y, %H:%M %Z" + translation: + errors: + quota_exceeded: SĂ¡raĂ­odh an cuĂ³ta ĂºsĂ¡ide uile-fhreastalaĂ­ don tseirbhĂ­s aistriĂºchĂ¡in. + too_many_requests: TĂ¡ an iomarca iarratas ar an tseirbhĂ­s aistriĂºchĂ¡in le dĂ©anaĂ­. two_factor_authentication: + add: Cuir + disable: DĂ­chumasaigh 2FA + disabled_success: D'Ă©irigh le fĂ­ordheimhniĂº dhĂ¡-fhachtĂ³ir a dhĂ­chumasĂº edit: Cuir in eagar + enabled: TĂ¡ fĂ­ordheimhniĂº dhĂ¡ fhachtĂ³ir cumasaithe + enabled_success: D'Ă©irigh le fĂ­ordheimhniĂº dhĂ¡ fhachtĂ³ir a chumasĂº + generate_recovery_codes: Gin cĂ³id athshlĂ¡naithe + lost_recovery_codes: Ligeann cĂ³id athshlĂ¡naithe duit rochtain a fhĂ¡il ar do chuntas arĂ­s mĂ¡ chailleann tĂº do ghuthĂ¡n. MĂ¡ tĂ¡ do chĂ³id athshlĂ¡naithe caillte agat, is fĂ©idir leat iad a athnuachan anseo. DĂ©anfar do sheanchĂ³id athshlĂ¡naithe a neamhbhailĂ­ochtĂº. + methods: Modhanna dhĂ¡-fhachtĂ³ir + otp: Aip fĂ­ordheimhnitheora + recovery_codes: CĂ³id aisghabhĂ¡la cĂºltaca + recovery_codes_regenerated: D'Ă©irigh le hathghiniĂºint cĂ³id athshlĂ¡naithe + recovery_instructions_html: MĂ¡ chailleann tĂº rochtain ar do ghuthĂ¡n riamh, is fĂ©idir leat ceann de na cĂ³id athshlĂ¡naithe thĂ­os a ĂºsĂ¡id chun rochtain a fhĂ¡il ar do chuntas arĂ­s. Coinnigh na cĂ³id athshlĂ¡naithe slĂ¡n. Mar shampla, is fĂ©idir leat iad a phriontĂ¡il agus iad a stĂ³rĂ¡il le doicimĂ©id thĂ¡bhachtacha eile. webauthn: Eochracha slĂ¡ndĂ¡la user_mailer: + appeal_approved: + action: Socruithe cuntas + explanation: CeadaĂ­odh achomharc na stailce i gcoinne do chuntais ar %{strike_date} a chuir tĂº isteach ar %{appeal_date}. TĂ¡ seasamh maith ag do chuntas arĂ­s. + subject: CeadaĂ­odh d'achomharc Ă³ %{date} + subtitle: TĂ¡ seasamh maith ag do chuntas arĂ­s. + title: Achomharc ceadaithe + appeal_rejected: + explanation: DiĂºltaĂ­odh d'achomharc na stailce in aghaidh do chuntais ar %{strike_date} a chuir tĂº isteach ar %{appeal_date}. + subject: DiĂºltaĂ­odh do d'achomharc Ă³ %{date} + subtitle: DiĂºltaĂ­odh do d'achomharc. + title: DiĂºltaĂ­odh don achomharc + backup_ready: + explanation: D'iarr tĂº cĂºltaca iomlĂ¡n de do chuntas Mastodon. + extra: TĂ¡ sĂ© rĂ©idh le hĂ­oslĂ³dĂ¡il anois! + subject: TĂ¡ do chartlann rĂ©idh le hĂ­oslĂ³dĂ¡il + title: TĂ³gĂ¡il cartlainne + failed_2fa: + details: 'Seo sonraĂ­ na hiarrachta sĂ­niĂº isteach:' + explanation: Rinne duine Ă©igin iarracht sĂ­niĂº isteach ar do chuntas ach sholĂ¡thair sĂ© fachtĂ³ir fĂ­ordheimhnithe dara neamhbhailĂ­. + further_actions_html: Mura tusa a bhĂ­ ann, molaimid duit %{action} a dhĂ©anamh lĂ¡ithreach toisc go bhfĂ©adfadh sĂ© a bheith i gcontĂºirt. + subject: Teip fĂ­ordheimhnithe dara fachtĂ³ir + title: Theip ar fhĂ­ordheimhniĂº an dara fachtĂ³ir + suspicious_sign_in: + change_password: do phasfhocal a athrĂº + details: 'Seo sonraĂ­ faoin sĂ­niĂº isteach:' + explanation: Bhraitheamar sĂ­niĂº isteach ar do chuntas Ă³ sheoladh IP nua. + further_actions_html: Mura tusa a bhĂ­ ann, molaimid duit %{action} a dhĂ©anamh lĂ¡ithreach agus fĂ­ordheimhniĂº dhĂ¡ fhachtĂ³ir a chumasĂº chun do chuntas a choinneĂ¡il slĂ¡n. + subject: Fuarthas rochtain ar do chuntas Ă³ sheoladh IP nua + title: SĂ­niĂº isteach nua warning: appeal: Cuir achomharc isteach + appeal_description: MĂ¡ chreideann tĂº gur earrĂ¡id Ă© seo, is fĂ©idir leat achomharc a chur isteach chuig foireann %{instance}. categories: spam: Turscar + violation: SĂ¡raĂ­onn Ă¡bhar na treoirlĂ­nte pobail seo a leanas + explanation: + delete_statuses: Fuarthas amach gur shĂ¡raigh roinnt de do chuid postĂ¡lacha treoirlĂ­nte pobail amhĂ¡in nĂ³ nĂ­os mĂ³ agus bhain modhnĂ³irĂ­ %{instance} iad ina dhiaidh sin. + disable: NĂ­ fĂ©idir leat do chuntas a ĂºsĂ¡id a thuilleadh, ach fanann do phrĂ³ifĂ­l agus sonraĂ­ eile slĂ¡n. Is fĂ©idir leat cĂºltaca de do shonraĂ­ a iarraidh, socruithe cuntais a athrĂº nĂ³ do chuntas a scriosadh. + mark_statuses_as_sensitive: TĂ¡ cuid de do chuid postĂ¡lacha marcĂ¡ilte mar Ă­ogair ag modhnĂ³irĂ­ %{instance}. CiallaĂ­onn sĂ© seo go mbeidh ar dhaoine na meĂ¡in a thapĂ¡il sna poist sula dtaispeĂ¡nfar rĂ©amhamharc. Is fĂ©idir leat na meĂ¡in a mharcĂ¡il mar Ă­ogair tĂº fĂ©in agus tĂº ag postĂ¡il amach anseo. + sensitive: As seo amach, beidh gach do chomhaid meĂ¡n uaslĂ³dĂ¡ilte a mharcĂ¡il mar Ă­ogair agus i bhfolach taobh thiar de rabhadh cliceĂ¡il-trĂ­. + silence: Is fĂ©idir leat do chuntas a ĂºsĂ¡id go fĂ³ill ach nĂ­ fheicfidh ach na daoine atĂ¡ ag leanĂºint ort cheana fĂ©in do phostĂ¡lacha ar an bhfreastalaĂ­ seo, agus seans go mbeidh tĂº eisiata Ă³ ghnĂ©ithe Ă©agsĂºla fionnachtana. FĂ©adfaidh daoine eile tĂº a leanĂºint de lĂ¡imh, Ă¡fach. + suspend: NĂ­ fĂ©idir leat do chuntas a ĂºsĂ¡id a thuilleadh, agus nĂ­l rochtain ar do phrĂ³ifĂ­l nĂ¡ ar shonraĂ­ eile a thuilleadh. Is fĂ©idir leat logĂ¡il isteach fĂ³s chun cĂºltaca de do shonraĂ­ a iarraidh go dtĂ­ go mbaintear na sonraĂ­ go hiomlĂ¡n i gceann thart ar 30 lĂ¡, ach coinneoimid roinnt sonraĂ­ bunĂºsacha chun cosc ​​a chur ort an fionraĂ­ a sheachaint. reason: 'FĂ¡th:' + statuses: 'PostĂ¡lacha a luadh:' subject: + delete_statuses: Baineadh do phostĂ¡lacha ar %{acct} + disable: TĂ¡ do chuntas %{acct} reoite + mark_statuses_as_sensitive: MarcĂ¡ladh do phostĂ¡lacha ar %{acct} mar Ă­ogair none: Rabhadh do %{acct} + sensitive: MarcĂ¡lfar do phostĂ¡lacha ar %{acct} mar Ă­ogair as seo amach + silence: TĂ¡ do chuntas %{acct} teoranta + suspend: TĂ¡ do chuntas %{acct} curtha ar fionraĂ­ title: + delete_statuses: Baineadh postĂ¡lacha + disable: Cuntas reoite + mark_statuses_as_sensitive: PostĂ¡lacha marcĂ¡ilte mar Ă­ogair none: Rabhadh + sensitive: Cuntas marcĂ¡ilte mar Ă­ogair + silence: Cuntas teoranta + suspend: Cuntas ar fionraĂ­ + welcome: + apps_android_action: Faigh Ă© ar Google Play + apps_ios_action: ĂoslĂ³dĂ¡il ar an App Store + apps_step: ĂoslĂ³dĂ¡il Ă¡r n-aipanna oifigiĂºla. + apps_title: Aipeanna Mastodon + checklist_subtitle: 'Cuirimis tĂºs leat ar an teorainn shĂ³isialta nua seo:' + checklist_title: Seicliosta FĂ¡ilte + edit_profile_action: PearsanĂº + edit_profile_step: Cuir le d'idirghnĂ­omhaĂ­ochtaĂ­ trĂ­ phrĂ³ifĂ­l chuimsitheach a bheith agat. + edit_profile_title: DĂ©an do phrĂ³ifĂ­l a phearsantĂº + explanation: Seo roinnt leideanna chun tĂº a chur ar bun + feature_action: Foghlaim nĂ­os mĂ³ + feature_audience: SolĂ¡thraĂ­onn Mastodon deis uathĂºil duit do lucht fĂ©achana a bhainistiĂº gan fir lĂ¡r. Ligeann Mastodon a imlonnaĂ­tear ar do bhonneagar fĂ©in duit leanĂºint agus leanĂºint Ă³ aon fhreastalaĂ­ Mastodon eile ar lĂ­ne agus nĂ­l sĂ© faoi smacht aon duine ach mise. + feature_audience_title: TĂ³g do lucht fĂ©achana faoi rĂºn + feature_control: Is fearr a fhios agat cad ba mhaith leat a fheiceĂ¡il ar do bheathĂº baile. Gan algartam nĂ³ fĂ³graĂ­ chun do chuid ama a chur amĂº. Lean aon duine ar fud aon fhreastalaĂ­ Mastodon Ă³ chuntas amhĂ¡in agus faigh a gcuid post in ord croineolaĂ­och, agus dĂ©an do chĂºinne den idirlĂ­on beagĂ¡n nĂ­os mĂ³ cosĂºil leatsa. + feature_control_title: Coinnigh smacht ar d’amlĂ­ne fĂ©in + feature_creativity: TacaĂ­onn Mastodon le postĂ¡lacha fuaime, fĂ­se agus pictiĂºr, tuairiscĂ­ inrochtaineachta, pobalbhreitheanna, rabhaidh inneachair, avatars beoite, emojis saincheaptha, rialĂº barr mionsamhlacha, agus nĂ­os mĂ³, chun cabhrĂº leat tĂº fĂ©in a chur in iĂºl ar lĂ­ne. CibĂ© an bhfuil do chuid ealaĂ­ne, do cheol nĂ³ do phodchraoladh Ă¡ fhoilsiĂº agat, tĂ¡ Mastodon ann duit. + feature_creativity_title: Cruthaitheacht gan sĂ¡rĂº + feature_moderation: Cuireann Mastodon cinnteoireacht ar ais i do lĂ¡mha. CruthaĂ­onn gach freastalaĂ­ a rialacha agus a rialachĂ¡in fĂ©in, a chuirtear i bhfeidhm go hĂ¡itiĂºil agus nach bhfuil Ă³ bharr anuas cosĂºil le meĂ¡in shĂ³isialta chorparĂ¡ideacha, rud a fhĂ¡gann gurb Ă© an ceann is solĂºbtha Ă© chun freagairt do riachtanais grĂºpaĂ­ Ă©agsĂºla daoine. BĂ­ ar fhreastalaĂ­ leis na rialacha a n-aontaĂ­onn tĂº leo, nĂ³ do chuid fĂ©in a Ă³stĂ¡il. + feature_moderation_title: Ag maolĂº ar an mbealach ar cheart dĂ³ a bheith + follow_action: Lean + follow_step: Is Ă©ard atĂ¡ i gceist le daoine suimiĂºla a leanĂºint nĂ¡ Mastodon. + follow_title: Cuir do chuid fotha baile in oiriĂºint duit fĂ©in + follows_subtitle: Lean cuntais aitheanta + follows_title: CĂ© a leanĂºint + follows_view_more: FĂ©ach ar nĂ­os mĂ³ daoine a leanĂºint + hashtags_recent_count: + few: "%{people} daoine le 2 lĂ¡ anuas" + many: "%{people} daoine le 2 lĂ¡ anuas" + one: "%{people} duine le 2 lĂ¡ anuas" + other: "%{people} daoine le 2 lĂ¡ anuas" + two: "%{people} daoine le 2 lĂ¡ anuas" + hashtags_subtitle: DĂ©an iniĂºchadh ar a bhfuil ag dul chun cinn le 2 lĂ¡ anuas + hashtags_title: Haischlib treochta + hashtags_view_more: FĂ©ach ar nĂ­os mĂ³ Haischlib treochta + post_action: Cum + post_step: Abair hello leis an domhan le tĂ©acs, grianghraif, fĂ­seĂ¡in, nĂ³ pobalbhreith. + post_title: DĂ©an do chĂ©ad phostĂ¡il + share_action: Comhroinn + share_step: Cuir in iĂºl do do chairde conas tĂº a aimsiĂº ar Mastodon. + share_title: Roinn do phrĂ³ifĂ­l Mastodon + sign_in_action: SĂ­nigh isteach + subject: FĂ¡ilte go Mastodon + title: FĂ¡ilte ar bord, %{name}! + users: + follow_limit_reached: NĂ­ fĂ©idir leat nĂ­os mĂ³ nĂ¡ %{limit} duine a leanĂºint + go_to_sso_account_settings: TĂ©igh chuig socruithe cuntais do sholĂ¡thraĂ­ aitheantais + invalid_otp_token: CĂ³d dhĂ¡-fhachtĂ³ir neamhbhailĂ­ + otp_lost_help_html: MĂ¡ chaill tĂº rochtain ar an dĂ¡ cheann, is fĂ©idir leat dul i dteagmhĂ¡il le %{email} + rate_limited: An iomarca iarrachtaĂ­ fĂ­ordheimhnithe, bain triail eile as ar ball. + seamless_external_login: TĂ¡ tĂº logĂ¡ilte isteach trĂ­ sheirbhĂ­s sheachtrach, mar sin nĂ­l socruithe pasfhocail agus rĂ­omhphoist ar fĂ¡il. + signed_in_as: 'SĂ­nithe isteach mar:' + verification: + extra_instructions_html: Leid: Is fĂ©idir an nasc ar do shuĂ­omh GrĂ©asĂ¡in a bheith dofheicthe. Is Ă­ an chuid thĂ¡bhachtach nĂ¡ rel="me" a chuireann cosc ​​ar phearsanĂº ar shuĂ­mh GhrĂ©asĂ¡in a bhfuil inneachar a ghintear leis an ĂºsĂ¡ideoir. Is fĂ©idir leat fiĂº clib nasc a ĂºsĂ¡id i gceanntĂ¡sc an leathanaigh in ionad a, ach caithfidh an HTML a bheith inrochtana gan JavaScript a chur i gcrĂ­ch. + here_is_how: Seo Ă© an chaoi + hint_html: "Is do chĂ¡ch Ă© d'aitheantas a fhĂ­orĂº ar Mastodon. Bunaithe ar chaighdeĂ¡in oscailte grĂ©asĂ¡in, saor in aisce anois agus go deo. NĂ­l uait ach lĂ¡ithreĂ¡n grĂ©asĂ¡in pearsanta a aithnĂ­onn daoine thĂº. Nuair a nascann tĂº leis an suĂ­omh GrĂ©asĂ¡in seo Ă³ do phrĂ³ifĂ­l, seiceĂ³imid go bhfuil nasc idir an suĂ­omh GrĂ©asĂ¡in agus do phrĂ³ifĂ­l agus taispeĂ¡nfaimid tĂ¡scaire amhairc air." + instructions_html: CĂ³ipeĂ¡il agus greamaigh an cĂ³d thĂ­os isteach i HTML do shuĂ­omh GrĂ©asĂ¡in. Ansin cuir seoladh do shuĂ­omh GrĂ©asĂ¡in isteach i gceann de na rĂ©imsĂ­ breise ar do phrĂ³ifĂ­l Ă³n gcluaisĂ­n "Cuir prĂ³ifĂ­l in eagar" agus sĂ¡bhĂ¡il athruithe. + verification: FĂ­orĂº + verified_links: Do naisc fhĂ­oraithe webauthn_credentials: + add: Cuir eochair shlĂ¡ndĂ¡la nua leis + create: + error: BhĂ­ fadhb ann agus d'eochair shlĂ¡ndĂ¡la Ă¡ cur leis. ArĂ­s, le d'thoil. + success: Cuireadh d'eochair shlĂ¡ndĂ¡la leis. delete: Scrios + delete_confirmation: An bhfuil tĂº cinnte gur mhaith leat an eochair shlĂ¡ndĂ¡la seo a scriosadh? + description_html: MĂ¡ chumasaĂ­onn tĂº fĂ­ordheimhniĂº eochrach slĂ¡ndĂ¡la, beidh ort ceann de na heochracha slĂ¡ndĂ¡la a ĂºsĂ¡id chun logĂ¡il isteach. + destroy: + error: BhĂ­ fadhb ann agus d'eochair shlĂ¡ndĂ¡la Ă¡ scriosadh. ArĂ­s, le d'thoil. + success: Scriosadh d'eochair shlĂ¡ndĂ¡la go rathĂºil. + invalid_credential: Eochair shlĂ¡ndĂ¡la neamhbhailĂ­ + nickname_hint: Cuir isteach leasainm d'eochair shlĂ¡ndĂ¡la nua + not_enabled: NĂ­l WebAuthn cumasaithe agat fĂ³s + not_supported: This browser doesn't support security keys + otp_required: To use security keys please enable two-factor authentication first. + registered_on: Registered on %{date} diff --git a/config/locales/gl.yml b/config/locales/gl.yml index ad4744e15b3e7b..d1c8633badd602 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -31,18 +31,18 @@ gl: created_msg: Nota de moderaciĂ³n creada correctamente! destroyed_msg: Nota de moderaciĂ³n eliminada de xeito correcto! accounts: - add_email_domain_block: Bloquear o dominio do email + add_email_domain_block: Bloquear o dominio do enderezo approve: Aprobar approved_msg: Aprobada a solicitude de rexistro de %{username} are_you_sure: EstĂ¡ segura? avatar: Imaxe de perfil by_domain: Dominio change_email: - changed_msg: Email mudado de xeito correcto! - current_email: Email actual - label: Mudar email - new_email: Novo email - submit: Mudar email + changed_msg: Correo cambiado de xeito correcto! + current_email: Enderezo actual + label: Cambiar de enderezo + new_email: Novo enderezo + submit: Cambiar de enderezo title: Mudar email de %{username} change_role: changed_msg: Rol mudado correctamente! @@ -64,10 +64,10 @@ gl: display_name: Nome a amosar domain: Dominio edit: Editar - email: Email - email_status: Estado do email + email: Enderezo de correo + email_status: Estado do correo enable: Activar - enable_sign_in_token_auth: Activar autenticaciĂ³n cun token no email + enable_sign_in_token_auth: Activar autenticaciĂ³n cun token no correo enabled: Activado enabled_msg: Desbloqueada a conta de %{username} followers: Seguidoras @@ -132,7 +132,7 @@ gl: resubscribe: Resubscribir role: Rol search: Procurar - search_same_email_domain: Outras usuarias co mesmo dominio de email + search_same_email_domain: Outras usuarias co mesmo dominio de correo search_same_ip: Outras usuarias co mesmo IP security: Seguridade security_measures: @@ -154,9 +154,9 @@ gl: suspension_irreversible: EliminĂ¡ronse de xeito irreversible os datos desta conta. Podes reactivar a conta para facela usable novamente pero non recuperarĂ¡ os datos eliminados. suspension_reversible_hint_html: Esta conta foi suspendida, e os datos serĂ¡n totalmente eliminados o %{date}. Ata entĂ³n, a conta pode ser restaurada sen danos. Se desexas eliminar agora mesmo todos os datos da conta, podes facelo aquĂ­ embaixo. title: Contas - unblock_email: Desbloquear enderezo de email - unblocked_email_msg: Enderezo de email de %{username} desbloqueado - unconfirmed_email: Email non confirmado + unblock_email: Desbloquear enderezo de correo + unblocked_email_msg: Enderezo de correo de %{username} desbloqueado + unconfirmed_email: Enderezo de correo sen confirmar undo_sensitized: Desmarcar como sensible undo_silenced: Desfacer acalar undo_suspension: Desfacer suspensiĂ³n @@ -173,12 +173,12 @@ gl: approve_appeal: Aprobar apelaciĂ³n approve_user: Aprobar Usuaria assigned_to_self_report: Asignar denuncia - change_email_user: Editar email da usuaria + change_email_user: Editar correo electrĂ³nico da usuaria change_role_user: Cambiar Rol da Usuaria confirm_user: Confirmar usuaria create_account_warning: Crear aviso create_announcement: Crear anuncio - create_canonical_email_block: Crear Bloqueo de email + create_canonical_email_block: Crear Bloqueo de correo electrĂ³nico create_custom_emoji: Crear emoticonas personalizadas create_domain_allow: Crear Dominio Permitido create_domain_block: Crear bloquedo do Dominio @@ -188,7 +188,7 @@ gl: create_user_role: Crear Rol demote_user: Degradar usuaria destroy_announcement: Eliminar anuncio - destroy_canonical_email_block: Eliminar Bloqueo de email + destroy_canonical_email_block: Eliminar Bloqueo de correo electrĂ³nico destroy_custom_emoji: Eliminar emoticona personalizada destroy_domain_allow: Eliminar Dominio permitido destroy_domain_block: Eliminar bloqueo do Dominio @@ -200,7 +200,7 @@ gl: destroy_user_role: Eliminar Rol disable_2fa_user: Desactivar 2FA disable_custom_emoji: Desactivar emoticona personalizada - disable_sign_in_token_auth_user: Desactivar AutenticaciĂ³n por token no email para Usuaria + disable_sign_in_token_auth_user: Desactivar AutenticaciĂ³n con token no correo para Usuaria disable_user: Desactivar usuaria enable_custom_emoji: Activar emoticona personalizada enable_sign_in_token_auth_user: Activar AutenticaciĂ³n con token no email para Usuaria @@ -211,14 +211,14 @@ gl: reject_user: Rexeitar Usuaria remove_avatar_user: Eliminar avatar reopen_report: Reabrir denuncia - resend_user: Reenviar o email de confirmaciĂ³n + resend_user: Reenviar o correo de confirmaciĂ³n reset_password_user: Restabelecer contrasinal resolve_report: Resolver denuncia sensitive_account: Marca o multimedia da tĂºa conta como sensible silence_account: Silenciar conta suspend_account: Suspender conta unassigned_report: Desasignar denuncia - unblock_email_account: Desbloquear enderezo de email + unblock_email_account: Desbloquear enderezo de correo unsensitive_account: Retira a marca de sensible do multimedia da conta unsilence_account: Deixar de silenciar conta unsuspend_account: Retirar suspensiĂ³n de conta @@ -226,6 +226,7 @@ gl: update_custom_emoji: Actualizar emoticona personalizada update_domain_block: Actualizar bloqueo do dominio update_ip_block: Actualizar regra IP + update_report: ActualizaciĂ³n da denuncia update_status: Actualizar publicaciĂ³n update_user_role: Actualizar Rol actions: @@ -638,6 +639,7 @@ gl: report: 'Denuncia #%{id}' reported_account: Conta denunciada reported_by: Denunciado por + reported_with_application: Denunciado coa aplicaciĂ³n resolved: Resolto resolved_msg: Resolveuse con Ă©xito a denuncia! skip_to_actions: Ir a acciĂ³ns @@ -660,7 +662,7 @@ gl: delete_data_html: Eliminar o perfil e contidos de @%{acct} para os prĂ³ximos 30 dĂ­as a non ser que sexa suspendida nese perĂ­odo preview_preamble_html: "@%{acct} vai recibir un aviso co seguinte contido:" record_strike_html: Anotar un aviso contra @%{acct} para axudarche a xestionar futuros problemas con esta conta - send_email_html: Enviar un email de aviso a @%{acct} + send_email_html: Enviar un correo de aviso a @%{acct} warning_placeholder: RazĂ³ns adicionais optativas para a acciĂ³n de moderaciĂ³n. target_origin: Orixe da conta denunciada title: Denuncias @@ -1060,7 +1062,7 @@ gl: redirect_to_app_html: Ămoste redirixir Ă¡ app %{app_name}. Se iso non acontece, proba %{clicking_this_link} ou volve ti manualmente Ă¡ app. registration_complete: Completouse a creaciĂ³n da conta en %{domain}! welcome_title: Benvida, %{name}! - wrong_email_hint: Se o enderezo de email non Ă© correcto, podes cambialo nos axustes da conta. + wrong_email_hint: Se o enderezo de correo non Ă© correcto, podes cambialo nos axustes da conta. delete_account: Eliminar conta delete_account_html: Se queres eliminar a tĂºa conta, podes facelo aquĂ­. DeberĂ¡s confirmar a acciĂ³n. description: diff --git a/config/locales/he.yml b/config/locales/he.yml index 3ba823f99bc685..ecafbec960ba00 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -232,6 +232,7 @@ he: update_custom_emoji: עדכון ס×לון ×ות×× ×ישית update_domain_block: עדכון חסי×ת ×©× ××ª×—× update_ip_block: עדכון כלל IP + update_report: עדכון דו"×— עבירה update_status: סטטוס עדכון update_user_role: עדכון תפקיד actions: diff --git a/config/locales/hi.yml b/config/locales/hi.yml index b67de192f2563e..0bfc30027abef7 100644 --- a/config/locales/hi.yml +++ b/config/locales/hi.yml @@ -32,6 +32,8 @@ hi: silence: सीमा silenced: सीमित title: खाते + reports: + reported_with_application: à¤à¤ªà¥à¤²à¥€à¤•à¥‡à¤¶à¤¨ से रिपोरà¥à¤Ÿ किया गया system_checks: upload_check_privacy_error: message_html: " आपके वेब सरà¥à¤µà¤° का कनà¥à¤«à¤¿à¤—रेशन सही नहीं है। उपयोगकरà¥à¤¤à¤¾à¤“ं की निजता खतरे में है। " diff --git a/config/locales/hu.yml b/config/locales/hu.yml index 19076910e2992c..df32bd39d116f7 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -226,6 +226,7 @@ hu: update_custom_emoji: EgyĂ©ni emodzsi frissĂ­tĂ©se update_domain_block: Domain tiltĂ¡s frissĂ­tĂ©se update_ip_block: IP-szabĂ¡ly frissĂ­tĂ©se + update_report: BejelentĂ©s frissĂ­tĂ©se update_status: BejegyzĂ©s frissĂ­tĂ©se update_user_role: Szerepkör frissĂ­tĂ©se actions: @@ -638,6 +639,7 @@ hu: report: "#%{id} szĂ¡mĂº jelentĂ©s" reported_account: Bejelentett fiĂ³k reported_by: 'Jelentette:' + reported_with_application: AlkalmazĂ¡ssal bejelentve resolved: Megoldott resolved_msg: A bejelentĂ©st sikeresen megoldottuk! skip_to_actions: TovĂ¡bb az intĂ©zkedĂ©sekhez diff --git a/config/locales/it.yml b/config/locales/it.yml index 1e17c5cbd0c721..68e1608d9c1990 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -226,6 +226,7 @@ it: update_custom_emoji: Aggiorna Emoji Personalizzata update_domain_block: Aggiorna Blocco del Dominio update_ip_block: Aggiorna regola IP + update_report: Aggiorna segnalazione update_status: Aggiorna Toot update_user_role: Aggiorna Ruolo actions: @@ -638,6 +639,7 @@ it: report: 'Rapporto #%{id}' reported_account: Account segnalato reported_by: Inviato da + reported_with_application: Segnalato con applicazione resolved: Risolto resolved_msg: Rapporto risolto! skip_to_actions: Passa alle azioni diff --git a/config/locales/ja.yml b/config/locales/ja.yml index ec6963517abdcb..5142b550321c48 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -290,6 +290,7 @@ ja: filter_by_action: ă‚¢ă‚¯ă‚·ăƒ§ăƒ³ă§ăƒ•ă‚£ăƒ«ă‚¿ăƒ¼ filter_by_user: ăƒ¦ăƒ¼ă‚¶ăƒ¼ă§ăƒ•ă‚£ăƒ«ă‚¿ăƒ¼ title: æ“作履歴 + unavailable_instance: "(ăƒ‰ăƒ¡ă‚¤ăƒ³åăŒåˆ©ç”¨ă§ăă¾ă›ă‚“)" announcements: destroyed_msg: ăçŸ¥ă‚‰ă›ăŒå‰é™¤ă•ă‚Œă¾ă—ăŸ edit: diff --git a/config/locales/ko.yml b/config/locales/ko.yml index a8e2ade61df8e5..632bd7c097647f 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -223,6 +223,7 @@ ko: update_custom_emoji: ́»¤́¤í…€ ́—모́§€ ́—…ë°́´í¸ update_domain_block: ë„ë©”́¸ ́°¨ë‹¨ ê°±́‹  update_ip_block: IP ê·œ́¹™ ́ˆ˜́ • + update_report: ́‹ ê³  ́—…ë°́´í¸ update_status: 게́‹œë¬¼ ́ˆ˜́ • update_user_role: ́—­í•  ́ˆ˜́ • actions: @@ -1741,7 +1742,7 @@ ko: contrast: 마́¤í† ëˆ (고대비) default: 마́¤í† ëˆ (́–´ë‘́›€) mastodon-light: 마́¤í† ëˆ (ë°́Œ) - system: ́ë™ ́„ íƒ (́‹œ́¤í…œ 테마 ́´́©) + system: ́ë™ (́‹œ́¤í…œ 테마 ́‚¬́©) time: formats: default: "%Y-%m-%d %H:%M" diff --git a/config/locales/lt.yml b/config/locales/lt.yml index e731deedc8e64b..004f5b4d043410 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -542,6 +542,8 @@ lt: manage_taxonomies_description: Leidžia naudotojams peržiÅ«rÄ—ti tendencingÄ… turinį ir atnaujinti saitažodžių nustatymus manage_user_access_description: Leidžia naudotojams iÅ¡jungti kitų naudotojų dvigubo tapatybÄ—s nustatymÄ…, pakeisti el. paÅ¡to adresÄ… ir iÅ¡ naujo nustatyti slaptažodį. settings: + branding: + title: Firminio ženklo kÅ«rimas captcha_enabled: desc_html: Tai priklauso nuo hCaptcha iÅ¡orinių skriptų, kurie gali kelti susirÅ«pinimÄ… dÄ—l saugumo ir privatumo. Be to, dÄ—l to registracijos procesas kai kuriems žmonÄ—ms (ypaÄ neįgaliesiems) gali bÅ«ti gerokai sunkiau prieinami. DÄ—l Å¡ių priežasÄių apsvarstyk alternatyvias priemones, pavyzdžiui, patvirtinimu arba kvietimu grindžiamÄ… registracijÄ…. content_retention: @@ -663,7 +665,19 @@ lt: edit_preset: Keisti įspÄ—jimo nustatymus title: Ä®spÄ—jamieji numatytieji webhooks: + add_new: PridÄ—ti galutinį taÅ¡kÄ… + delete: IÅ¡trinti description_html: "Webhook leidžia Mastodon siųsti realaus laiko praneÅ¡imus apie pasirinktus įvykius į tavo programÄ…, kad programa galÄ—tų automatiÅ¡kai paleisti reakcijas." + disable: IÅ¡jungti + disabled: IÅ¡jungta + edit: Redaguoti galutinį taÅ¡kÄ… + enable: Ä®jungti + enabled: Aktyvi + enabled_events: + few: "%{count} įjungti įvykiai" + many: "%{count} įjungto įvykio" + one: "%{count} įjungtas įvykis" + other: "%{count} įjungtų įvykių" events: Ä®vykiai admin_mailer: auto_close_registrations: @@ -909,6 +923,7 @@ lt: login_activities: authentication_methods: otp: dvigubas tapatybÄ—s nustatymo programÄ—lÄ— + webauthn: saugumo raktai description_html: Jei pastebÄ—jei neatpažįstamÄ… veiklÄ…, apsvarstyk galimybÄ™ pakeisti slaptažodį ir įjungti dvigubÄ… tapatybÄ—s nustatymÄ…. empty: TapatybÄ—s nustatymas istorijos nÄ—ra title: TapatybÄ—s nustatymo istorija @@ -1049,6 +1064,7 @@ lt: relationships: Sekimai ir sekÄ—jai severed_relationships: NutrÅ«kÄ™ sÄ…ryÅ¡iai two_factor_authentication: Dvigubas tapatybÄ—s nustatymas + webauthn_authentication: Saugumo raktai severed_relationships: download: Atsisiųsti (%{count}) preamble: Užblokavus domenÄ… arba prižiÅ«rÄ—tojams nusprendus pristabdyti nuotolinio serverio veiklÄ…, gali prarasti sekimus ir sekÄ—jus. Kai taip atsitiks, galÄ—si atsisiųsti nutrauktų sÄ…ryÅ¡ių sÄ…raÅ¡us, kad juos patikrinti ir galbÅ«t importuoti į kitÄ… serverį. @@ -1110,6 +1126,7 @@ lt: recovery_codes: Atsarginio atkÅ«rimo kodai recovery_codes_regenerated: AtkÅ«rimo kodai sÄ—kmingai sugeneruoti recovery_instructions_html: Jeigu prarandate prieiga prie telefono, jÅ«s galite naudoti atkÅ«rimo kodus esanÄius žemiau, kad atgautumÄ—te priega prie savo paskyros.Laikykite atkÅ«rimo kodus saugiai Pavyzdžiui, galite norÄ—ti juos iÅ¡spausdinti, ir laikyti kartu su kitais svarbiais dokumentais. + webauthn: Saugumo raktai user_mailer: appeal_approved: action: Paskyros nustatymai @@ -1196,9 +1213,11 @@ lt: verification: Patvirtinimas verified_links: Tavo patikrintos nuorodos webauthn_credentials: + add: PridÄ—ti naujÄ… saugumo raktÄ… create: error: Kilo problema pridedant saugumo raktÄ…. Bandyk dar kartÄ…. success: Tavo saugumo raktas buvo sÄ—kmingai pridÄ—tas. + delete: IÅ¡trinti delete_confirmation: Ar tikrai nori iÅ¡trinti šį saugumo raktÄ…? description_html: Jei įjungsi saugumo rakto tapatybÄ—s nustatymÄ…, prisijungiant reikÄ—s naudoti vienÄ… iÅ¡ savo saugumo raktų. destroy: diff --git a/config/locales/nl.yml b/config/locales/nl.yml index baab2cb587a0e7..3b88dd95282de0 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -226,6 +226,7 @@ nl: update_custom_emoji: Lokale emoji bijwerken update_domain_block: Domeinblokkade bijwerken update_ip_block: IP-regel bijwerken + update_report: Rapportage bijwerken update_status: Bericht bijwerken update_user_role: Rol bijwerken actions: diff --git a/config/locales/nn.yml b/config/locales/nn.yml index 2da30e6627184a..ec77a2edf8792d 100644 --- a/config/locales/nn.yml +++ b/config/locales/nn.yml @@ -226,6 +226,7 @@ nn: update_custom_emoji: Oppdater tilpassa emoji update_domain_block: Oppdater domene-sperring update_ip_block: Oppdater IP-regel + update_report: Oppdater rapport update_status: Oppdater tut update_user_role: Oppdater rolla actions: @@ -638,6 +639,7 @@ nn: report: 'Rapporter #%{id}' reported_account: Rapportert konto reported_by: Rapportert av + reported_with_application: Rapportert med app resolved: Oppløyst resolved_msg: Rapporten er løyst! skip_to_actions: GĂ¥ til handlingar diff --git a/config/locales/pt-PT.yml b/config/locales/pt-PT.yml index 839ae2184edfc2..1df423bb7de93f 100644 --- a/config/locales/pt-PT.yml +++ b/config/locales/pt-PT.yml @@ -226,6 +226,7 @@ pt-PT: update_custom_emoji: Atualizar Emoji Personalizado update_domain_block: Atualizar Bloqueio de DomĂ­nio update_ip_block: Atualizar regra de IP + update_report: Atualizar RelatĂ³rio update_status: Atualizar Estado update_user_role: Atualizar FunĂ§Ă£o actions: @@ -638,6 +639,7 @@ pt-PT: report: 'DenĂºncia #%{id}' reported_account: Conta denunciada reported_by: Denunciado por + reported_with_application: Reportado com a aplicaĂ§Ă£o resolved: Resolvido resolved_msg: DenĂºncia correctamente resolvida! skip_to_actions: Passar para as ações diff --git a/config/locales/ro.yml b/config/locales/ro.yml index cd54d51051d838..79bc2a275f4045 100644 --- a/config/locales/ro.yml +++ b/config/locales/ro.yml @@ -116,6 +116,8 @@ ro: redownloaded_msg: S-a reĂ®mprospătat cu succes profilul %{username} de la origine reject: Respinge rejected_msg: S-a respins cu succes cererea de Ă®nregistrare a utilizatorului %{username} + remote_suspension_irreversible: Datele acestui cont au fost È™terse Ă®n mod ireversibil. + remote_suspension_reversible_hint_html: Contul a fost suspendat pe server-ul respectiv, iar datele vor fi È™terse complet pe %{date}. PĂ¢nă atunci, server-ul remote poate restabili acest cont fără consecinÈ›e negative. Dacă doreÈ™ti să elimini toate datele contului numaidecĂ¢t, poÈ›i face acest lucru mai jos. remove_avatar: Elimină avatar remove_header: Elimină antet removed_avatar_msg: S-a Ă®ndepărtat cu succes poza de profil a utilizatorului %{username} diff --git a/config/locales/ry.yml b/config/locales/ry.yml index 6fe57b65cdb30e..e384b7f1b74810 100644 --- a/config/locales/ry.yml +++ b/config/locales/ry.yml @@ -1 +1,21 @@ +--- ry: + accounts: + follow: ĐŸÑƒĐ´Đ¿Đ¸ÑĐ°Ñ‚Đ¸ ÑÑ + following: ĐŸÑƒĐ´Đ¿Đ¸ÑĐºÑ‹ + posts: + few: ĐŸÑƒĐ±Đ»Đ¸ĐºĐ°Ñ†Ñ–Ñ— + one: ĐŸÑƒĐ±Đ»Đ¸ĐºĐ°Ñ†Ñ–Ñ + other: ĐŸÑƒĐ±Đ»Đ¸ĐºĐ°Ñ†Ñ–Ñ— + posts_tab_heading: ĐŸÑƒĐ±Đ»Đ¸ĐºĐ°Ñ†Ñ–Ñ— + imports: + titles: + following: Đ†Đ¼Đ¿Đ¾Ñ€Ñ‚Đ¾Đ²Đ°Đ½Ñ Đ¿ÑƒĐ´Đ¿Đ¸ÑĐ¾Đº + types: + following: Đ˜ÑĐ¿Đ¸Ñ Đ¿ÑƒĐ´Đ¿Đ¸ÑĐ¾Đº + notification_mailer: + follow: + body: "%{name} ÑÑ Đ¿ÑƒĐ´Đ¿Đ¸Ñує ÑÑ Đ½Đ° Đ²Đ°Ñ!" + subject: "%{name} ÑÑ Đ¿ÑƒĐ´Đ¿Đ¸Ñує ÑÑ Đ½Đ° Đ²Đ°Ñ" + relationships: + following: ĐŸÑƒĐ´Đ¿Đ¸ÑĐºÑ‹ diff --git a/config/locales/simple_form.bg.yml b/config/locales/simple_form.bg.yml index f14a21b0c70036..564f72e8c21231 100644 --- a/config/locales/simple_form.bg.yml +++ b/config/locales/simple_form.bg.yml @@ -211,6 +211,7 @@ bg: setting_default_privacy: ĐŸĐ¾Đ²ĐµÑ€Đ¸Ñ‚ĐµĐ»Đ½Đ¾ÑÑ‚ Đ½Đ° Đ¿ÑƒĐ±Đ»Đ¸ĐºÑƒĐ²Đ°Đ½Đµ setting_default_sensitive: Đ’Ñе Đ´Đ° Ñе бележи Đ¼ÑƒĐ»Ñ‚Đ¸Đ¼ĐµĐ´Đ¸ÑÑ‚Đ° ĐºĐ°Ñ‚Đ¾ Đ´ĐµĐ»Đ¸ĐºĐ°Ñ‚Đ½Đ° setting_delete_modal: ĐŸĐ¾ĐºĐ°Đ·Đ²Đ°Đ½Đµ Đ½Đ° Đ¿Ñ€Đ¾Đ·Đ¾Ñ€Ñ‡Đµ Đ·Đ° Đ¿Đ¾Ñ‚Đ²ÑÑ€Đ¶Đ´ĐµĐ½Đ¸Đµ Đ¿Ñ€ĐµĐ´Đ¸ Đ¸Đ·Ñ‚Ñ€Đ¸Đ²Đ°Đ½Đµ Đ½Đ° Đ¿ÑƒĐ±Đ»Đ¸ĐºĐ°Ñ†Đ¸Ñ + setting_disable_hover_cards: Đ˜Đ·ĐºĐ»ÑÑ‡Đ²Đ°Đ½Đµ Đ½Đ° Đ¿Ñ€ĐµĐ³Đ»ĐµĐ´Đ° Đ½Đ° Đ¿Ñ€Đ¾Ñ„Đ¸Đ»Đ°, Đ¿Ñ€ĐµĐ¼ĐµÑÑ‚Đ²Đ°Đ¹ĐºĐ¸ Đ¿Đ¾ĐºĐ°Đ·Đ°Đ»ĐµÑ†Đ° Đ¾Ñ‚Đ³Đ¾Ñ€Đµ setting_disable_swiping: Đ”ĐµĐ°ĐºÑ‚Đ¸Đ²Đ¸Ñ€Đ°Đ½Đµ Đ½Đ° бÑÑ€Đ·Đ¾ Đ¿Đ»ÑĐ·Đ³Đ°Ñ‰Đ¸ Đ´Đ²Đ¸Đ¶ĐµĐ½Đ¸Ñ setting_display_media: ĐŸĐ¾ĐºĐ°Đ·Đ²Đ°Đ½Đµ Đ½Đ° Đ¼ÑƒĐ»Ñ‚Đ¸Đ¼ĐµĐ´Đ¸Ñ setting_display_media_default: Đ¡Ñ‚Đ°Đ½Đ´Đ°Ñ€Ñ‚Đ½Đ¾ @@ -242,11 +243,13 @@ bg: warn: Đ¡ĐºÑ€Đ¸Đ²Đ°Đ½Đµ Đ·Đ°Đ´ Đ¿Ñ€ĐµĐ´ÑƒĐ¿Ñ€ĐµĐ¶Đ´ĐµĐ½Đ¸Đµ form_admin_settings: activity_api_enabled: ĐŸÑƒĐ±Đ»Đ¸ĐºÑƒĐ²Đ°Đ½Đµ Đ½Đ° Đ°Đ³Ñ€ĐµĐ³Đ°Ñ‚Đ½Đ° ÑÑ‚Đ°Ñ‚Đ¸ÑÑ‚Đ¸ĐºĐ° Đ¾Ñ‚Đ½Đ¾ÑĐ½Đ¾ Đ¿Đ¾Ñ‚Ñ€ĐµĐ±Đ¸Ñ‚ĐµĐ»ÑĐºĐ°Ñ‚Đ° Đ´ĐµĐ¹Đ½Đ¾ÑÑ‚ Đ² API + app_icon: Đ˜ĐºĐ¾Đ½Đ° Đ½Đ° Đ¿Ñ€Đ¸Đ»Đ¾Đ¶ĐµĐ½Đ¸Đµ backups_retention_period: ĐŸĐµÑ€Đ¸Đ¾Đ´ Đ·Đ° ÑÑÑ…Ñ€Đ°Đ½ĐµĐ½Đ¸Đµ Đ½Đ° Đ¿Đ¾Ñ‚Ñ€ĐµĐ±Đ¸Ñ‚ĐµĐ»ÑĐºĐ¸Ñ Đ°Ñ€Ñ…Đ¸Đ² bootstrap_timeline_accounts: Đ’Đ¸Đ½Đ°Đ³Đ¸ Đ´Đ° Ñе Đ¿Ñ€ĐµĐ¿Đ¾Ñ€ÑÑ‡Đ²Đ°Ñ‚ ÑĐ»ĐµĐ´Đ½Đ¸Ñ‚Đµ Đ°ĐºĐ°ÑƒĐ½Ñ‚Đ¸ Đ½Đ° Đ½Đ¾Đ²Đ¸ Đ¿Đ¾Ñ‚Ñ€ĐµĐ±Đ¸Ñ‚ĐµĐ»Đ¸ closed_registrations_message: Đ¡ÑĐ¾Đ±Ñ‰ĐµĐ½Đ¸Đµ Đ¿Ñ€Đ¸ Đ½ĐµĐ½Đ°Đ»Đ¸Ñ‡Đ½Đ° Ñ€ĐµĐ³Đ¸ÑÑ‚Ñ€Đ°Ñ†Đ¸Ñ content_cache_retention_period: ĐŸĐµÑ€Đ¸Đ¾Đ´ Đ½Đ° Đ·Đ°Đ¿Đ°Đ·Đ²Đ°Đ½Đµ Đ½Đ° Đ¾Ñ‚Đ´Đ°Đ»ĐµÑ‡ĐµĐ½Đ¾ ÑÑĐ´ÑÑ€Đ¶Đ°Đ½Đ¸Đµ custom_css: ĐŸĐµÑ€ÑĐ¾Đ½Đ°Đ»Đ¸Đ·Đ¸Ñ€Đ°Đ½ CSS + favicon: Đ¡Đ°Đ¹Ñ‚Đ¾Đ¸ĐºĐ¾Đ½Đ° mascot: ĐŸĐ»Đ°ÑˆĐ¸Đ»Đ¾ Ñ‚Đ°Đ»Đ¸ÑĐ¼Đ°Đ½ Đ¿Đ¾ Đ¸Đ·Đ±Đ¾Ñ€ (Đ¾ÑÑ‚Đ°Ñ€ÑĐ»Đ¾) media_cache_retention_period: ĐŸĐµÑ€Đ¸Đ¾Đ´ Đ½Đ° Đ·Đ°Đ¿Đ°Đ·Đ²Đ°Đ½Đµ Đ½Đ° Đ¼ÑƒĐ»Ñ‚Đ¸Đ¼ĐµĐ´Đ¸Đ¹Đ½Đ¸Ñ ĐºĐµÑˆ peers_api_enabled: ĐŸÑƒĐ±Đ»Đ¸ĐºÑƒĐ²Đ°Đ½Đµ Đ½Đ° ÑĐ¿Đ¸ÑÑĐºĐ° Ñ Đ¾Ñ‚ĐºÑ€Đ¸Ñ‚Đ¸ ÑÑÑ€Đ²ÑÑ€Đ¸ Đ² API diff --git a/config/locales/simple_form.ca.yml b/config/locales/simple_form.ca.yml index d3dc4b13f113f2..2e0199d7fd5b06 100644 --- a/config/locales/simple_form.ca.yml +++ b/config/locales/simple_form.ca.yml @@ -211,6 +211,7 @@ ca: setting_default_privacy: Privacitat dels tuts setting_default_sensitive: Marcar sempre el contingut grĂ fic com a sensible setting_delete_modal: Mostra la finestra de confirmaciĂ³ abans d'esborrar un tut + setting_disable_hover_cards: Deshabilita la vista prèvia del perfil en passar-hi per sobre setting_disable_swiping: Desactiva les animacions setting_display_media: VisualitzaciĂ³ multimèdia setting_display_media_default: Per defecte @@ -242,11 +243,13 @@ ca: warn: Oculta amb un avĂ­s form_admin_settings: activity_api_enabled: Publica a l'API estadĂ­stiques agregades sobre l'activitat dels usuaris + app_icon: Icona de l'aplicaciĂ³ backups_retention_period: PerĂ­ode de retenciĂ³ del arxiu d'usuari bootstrap_timeline_accounts: Recomana sempre aquests comptes als nous usuaris closed_registrations_message: Missatge personalitzat quan el registre no Ă©s accessible content_cache_retention_period: PerĂ­ode de retenciĂ³ del contingut remot custom_css: CSS personalitzat + favicon: Icona de preferits mascot: Mascota personalitzada (llegat) media_cache_retention_period: PerĂ­ode de retenciĂ³ del cau multimèdia peers_api_enabled: Publica a l'API la llista de servidors descoberts diff --git a/config/locales/simple_form.cy.yml b/config/locales/simple_form.cy.yml index 5e8fd85293f75a..cd5bc1add788b8 100644 --- a/config/locales/simple_form.cy.yml +++ b/config/locales/simple_form.cy.yml @@ -242,11 +242,13 @@ cy: warn: Cuddio Ă¢ rhybudd form_admin_settings: activity_api_enabled: Cyhoeddi ystadegau cyfanredol am weithgarwch defnyddwyr yn yr API + app_icon: Eicon ap backups_retention_period: Cyfnod cadw archif defnyddwyr bootstrap_timeline_accounts: Argymhellwch y cyfrifon hyn i ddefnyddwyr newydd bob amser closed_registrations_message: Neges bersonol pan nad yw cofrestriadau ar gael content_cache_retention_period: Cyfnod cadw cynnwys o bell custom_css: CSS cyfaddas + favicon: Favicon mascot: Mascot cyfaddas (hen) media_cache_retention_period: Cyfnod cadw storfa cyfryngau peers_api_enabled: Cyhoeddi rhestr o weinyddion a ddarganfuwyd yn yr API diff --git a/config/locales/simple_form.da.yml b/config/locales/simple_form.da.yml index 0719e26430dd4c..9e949d16839f7d 100644 --- a/config/locales/simple_form.da.yml +++ b/config/locales/simple_form.da.yml @@ -211,6 +211,7 @@ da: setting_default_privacy: Fortrolighed for indlæg setting_default_sensitive: MarkĂ©r altid medier som sensitive setting_delete_modal: Vis bekræftelsesdialog før et indlæg slettes + setting_disable_hover_cards: DeaktivĂ©r profilforhĂ¥ndsvisning ved svæv (hover) setting_disable_swiping: DeaktivĂ©r strygebevægelser setting_display_media: Medievisning setting_display_media_default: Standard @@ -242,11 +243,13 @@ da: warn: Skjul bag en advarsel form_admin_settings: activity_api_enabled: Offentliggør samlede statistikker vedr. brugeraktivitet i API'en + app_icon: App-ikon backups_retention_period: Brugerarkivs opbevaringsperiode bootstrap_timeline_accounts: Anbefal altid disse konti til nye brugere closed_registrations_message: Tilpasset besked, nĂ¥r tilmelding er utilgængelig content_cache_retention_period: Opbevaringsperiode for eksternt indhold custom_css: Tilpasset CSS + favicon: Favikon mascot: Tilpasset maskot (ældre funktion) media_cache_retention_period: Media-cache opbevaringsperiode peers_api_enabled: Udgiv liste over fundne server i API'en diff --git a/config/locales/simple_form.de.yml b/config/locales/simple_form.de.yml index 7d397866977712..332d9513952126 100644 --- a/config/locales/simple_form.de.yml +++ b/config/locales/simple_form.de.yml @@ -211,6 +211,7 @@ de: setting_default_privacy: Beitragssichtbarkeit setting_default_sensitive: Medien immer mit einer Inhaltswarnung versehen setting_delete_modal: Bestätigungsdialog beim Löschen eines Beitrags anzeigen + setting_disable_hover_cards: Profilvorschau deaktivieren, wenn die Maus Ă¼ber das Profil bewegt wird setting_disable_swiping: Wischgesten deaktivieren setting_display_media: Darstellung von Medien setting_display_media_default: Standard @@ -242,11 +243,13 @@ de: warn: Mit einer Inhaltswarnung ausblenden form_admin_settings: activity_api_enabled: Aggregierte Nutzungsdaten Ă¼ber die API veröffentlichen + app_icon: App-Symbol backups_retention_period: Aufbewahrungsfrist fĂ¼r Archive bootstrap_timeline_accounts: Neuen Nutzern immer diese Konten empfehlen closed_registrations_message: Nachricht, falls Registrierungen deaktiviert sind content_cache_retention_period: Aufbewahrungsfrist fĂ¼r externe Inhalte custom_css: Eigenes CSS + favicon: Favicon mascot: Benutzerdefiniertes Maskottchen (Legacy) media_cache_retention_period: Aufbewahrungsfrist fĂ¼r Medien im Cache peers_api_enabled: Die entdeckten Server im Fediverse Ă¼ber die API veröffentlichen diff --git a/config/locales/simple_form.en-GB.yml b/config/locales/simple_form.en-GB.yml index eaf0501a27ba9e..c1f2a015e94b27 100644 --- a/config/locales/simple_form.en-GB.yml +++ b/config/locales/simple_form.en-GB.yml @@ -211,6 +211,7 @@ en-GB: setting_default_privacy: Posting privacy setting_default_sensitive: Always mark media as sensitive setting_delete_modal: Show confirmation dialogue before deleting a post + setting_disable_hover_cards: Disable profile preview on hover setting_disable_swiping: Disable swiping motions setting_display_media: Media display setting_display_media_default: Default @@ -242,11 +243,13 @@ en-GB: warn: Hide with a warning form_admin_settings: activity_api_enabled: Publish aggregate statistics about user activity in the API + app_icon: App icon backups_retention_period: User archive retention period bootstrap_timeline_accounts: Always recommend these accounts to new users closed_registrations_message: Custom message when sign-ups are not available content_cache_retention_period: Remote content retention period custom_css: Custom CSS + favicon: Favicon mascot: Custom mascot (legacy) media_cache_retention_period: Media cache retention period peers_api_enabled: Publish list of discovered servers in the API diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml index fdc9f61813d9c7..6bc7c6ac525e9f 100644 --- a/config/locales/simple_form.en.yml +++ b/config/locales/simple_form.en.yml @@ -211,6 +211,7 @@ en: setting_default_privacy: Posting privacy setting_default_sensitive: Always mark media as sensitive setting_delete_modal: Show confirmation dialog before deleting a post + setting_disable_hover_cards: Disable profile preview on hover setting_disable_swiping: Disable swiping motions setting_display_media: Media display setting_display_media_default: Default @@ -242,11 +243,13 @@ en: warn: Hide with a warning form_admin_settings: activity_api_enabled: Publish aggregate statistics about user activity in the API + app_icon: App icon backups_retention_period: User archive retention period bootstrap_timeline_accounts: Always recommend these accounts to new users closed_registrations_message: Custom message when sign-ups are not available content_cache_retention_period: Remote content retention period custom_css: Custom CSS + favicon: Favicon mascot: Custom mascot (legacy) media_cache_retention_period: Media cache retention period peers_api_enabled: Publish list of discovered servers in the API diff --git a/config/locales/simple_form.eo.yml b/config/locales/simple_form.eo.yml index e83f71a2cb5210..021be93b5d74cb 100644 --- a/config/locales/simple_form.eo.yml +++ b/config/locales/simple_form.eo.yml @@ -203,6 +203,7 @@ eo: setting_default_privacy: Privateco de afiÅado setting_default_sensitive: Ĉiam marki plurmediojn kiel tiklaj setting_delete_modal: Montri konfirman fenestron antaÅ­ ol forigi mesaÄon + setting_disable_hover_cards: Malebligi profilan antaÅ­montron kiam oni musumas setting_disable_swiping: Malebligi svingajn movojn setting_display_media: Montrado de plurmedioj setting_display_media_default: Implicita @@ -234,6 +235,7 @@ eo: warn: KaÅi malantaÅ­ averto form_admin_settings: activity_api_enabled: Publikigi entutajn statistikojn pri uzantagado en la API + app_icon: Apbildo backups_retention_period: Uzantoarkivretendauro bootstrap_timeline_accounts: Ĉiam rekomendi ĉi tiujn kontojn al novaj uzantoj closed_registrations_message: Kutima mesaÄo kiam registroj ne estas disponeblaj diff --git a/config/locales/simple_form.es-AR.yml b/config/locales/simple_form.es-AR.yml index e346a23a0282e8..71d9726b079423 100644 --- a/config/locales/simple_form.es-AR.yml +++ b/config/locales/simple_form.es-AR.yml @@ -211,6 +211,7 @@ es-AR: setting_default_privacy: Privacidad de mensajes setting_default_sensitive: Siempre marcar medios como sensibles setting_delete_modal: Mostrar diĂ¡logo de confirmaciĂ³n antes de eliminar un mensaje + setting_disable_hover_cards: Deshabilitar previsualizaciĂ³n del perfil al pasar el cursor setting_disable_swiping: Deshabilitar movimientos de deslizamiento setting_display_media: VisualizaciĂ³n de medios setting_display_media_default: Predeterminada @@ -242,11 +243,13 @@ es-AR: warn: Ocultar con una advertencia form_admin_settings: activity_api_enabled: Publicar estadĂ­sticas agregadas sobre la actividad de la cuenta en la API + app_icon: Ăcono de la aplicaciĂ³n backups_retention_period: PerĂ­odo de retenciĂ³n del archivo historial del usuario bootstrap_timeline_accounts: Siempre recomendar estas cuentas a usuarios nuevos closed_registrations_message: Mensaje personalizado cuando los registros no estĂ¡n disponibles content_cache_retention_period: PerĂ­odo de retenciĂ³n de contenido remoto custom_css: CSS personalizado + favicon: FavicĂ³n mascot: Mascota personalizada (legado) media_cache_retention_period: PerĂ­odo de retenciĂ³n de la cachĂ© de medios peers_api_enabled: Publicar lista de servidores descubiertos en la API diff --git a/config/locales/simple_form.es-MX.yml b/config/locales/simple_form.es-MX.yml index b3c8a857e83411..730e9b265b335a 100644 --- a/config/locales/simple_form.es-MX.yml +++ b/config/locales/simple_form.es-MX.yml @@ -211,6 +211,7 @@ es-MX: setting_default_privacy: Privacidad de publicaciones setting_default_sensitive: Marcar siempre imĂ¡genes como sensibles setting_delete_modal: Mostrar diĂ¡logo de confirmaciĂ³n antes de borrar un toot + setting_disable_hover_cards: Desactivar vista previa del perfil al pasar el cursor setting_disable_swiping: Deshabilitar movimientos de deslizamiento setting_display_media: VisualizaciĂ³n multimedia setting_display_media_default: Por defecto @@ -242,11 +243,13 @@ es-MX: warn: Ocultar con una advertencia form_admin_settings: activity_api_enabled: Publicar estadĂ­sticas locales acerca de la actividad de usuario en la API + app_icon: Icono de la app backups_retention_period: PerĂ­odo de retenciĂ³n del archivo de usuario bootstrap_timeline_accounts: Recomendar siempre estas cuentas a nuevos usuarios closed_registrations_message: Mensaje personalizado cuando los registros no estĂ¡n disponibles content_cache_retention_period: PerĂ­odo de retenciĂ³n de contenido remoto custom_css: CSS personalizado + favicon: Favicon mascot: Mascota personalizada (legado) media_cache_retention_period: PerĂ­odo de retenciĂ³n de cachĂ© multimedia peers_api_enabled: Publicar lista de servidores descubiertos en la API diff --git a/config/locales/simple_form.es.yml b/config/locales/simple_form.es.yml index 2fb5cab987f793..f2d91349adad6b 100644 --- a/config/locales/simple_form.es.yml +++ b/config/locales/simple_form.es.yml @@ -211,6 +211,7 @@ es: setting_default_privacy: Privacidad de publicaciones setting_default_sensitive: Marcar siempre imĂ¡genes como sensibles setting_delete_modal: Mostrar diĂ¡logo de confirmaciĂ³n antes de borrar una publicaciĂ³n + setting_disable_hover_cards: Desactivar vista previa del perfil al pasar el cursor setting_disable_swiping: Deshabilitar movimientos de deslizamiento setting_display_media: VisualizaciĂ³n multimedia setting_display_media_default: Por defecto @@ -242,11 +243,13 @@ es: warn: Ocultar con una advertencia form_admin_settings: activity_api_enabled: Publicar estadĂ­sticas agregadas sobre la actividad del usuario con la API + app_icon: Icono de la app backups_retention_period: PerĂ­odo de retenciĂ³n del archivo de usuario bootstrap_timeline_accounts: Recomendar siempre estas cuentas a nuevos usuarios closed_registrations_message: Mensaje personalizado cuando los registros no estĂ¡n disponibles content_cache_retention_period: PerĂ­odo de retenciĂ³n de contenido remoto custom_css: CSS personalizado + favicon: Favicon mascot: Mascota personalizada (legado) media_cache_retention_period: PerĂ­odo de retenciĂ³n de cachĂ© multimedia peers_api_enabled: Publicar lista de servidores descubiertos en la API diff --git a/config/locales/simple_form.fi.yml b/config/locales/simple_form.fi.yml index b0bc8c735b4881..de099a21be2e1a 100644 --- a/config/locales/simple_form.fi.yml +++ b/config/locales/simple_form.fi.yml @@ -211,6 +211,7 @@ fi: setting_default_privacy: Julkaisun näkyvyys setting_default_sensitive: Merkitse media aina arkaluonteiseksi setting_delete_modal: Kysy vahvistusta ennen julkaisun poistamista + setting_disable_hover_cards: Poista käytöstä profiilin esikatselu osoitettaessa setting_disable_swiping: Poista pyyhkäisyeleet käytöstä setting_display_media: Median näyttäminen setting_display_media_default: Oletus @@ -242,11 +243,13 @@ fi: warn: Piilota varoittaen form_admin_settings: activity_api_enabled: Julkaise yhteenlasketut tilastot käyttäjätoiminnasta ohjelmointirajapinnassa + app_icon: Sovelluskuvake backups_retention_period: Käyttäjän arkiston säilytysaika bootstrap_timeline_accounts: Suosittele aina näitä tilejä uusille käyttäjille closed_registrations_message: Mukautettu viesti, kun rekisteröityminen ei ole saatavilla content_cache_retention_period: Etäsisällön säilytysaika custom_css: Mukautettu CSS + favicon: Suosikkikuvake mascot: Mukautettu maskotti (vanhentunut ominaisuus) media_cache_retention_period: Mediasisältövälimuistin säilytysaika peers_api_enabled: Julkaise löydettyjen palvelinten luettelo ohjelmointirajapinnassa diff --git a/config/locales/simple_form.fo.yml b/config/locales/simple_form.fo.yml index 7d4da2b51ee38e..b334d4f034ac5f 100644 --- a/config/locales/simple_form.fo.yml +++ b/config/locales/simple_form.fo.yml @@ -211,6 +211,7 @@ fo: setting_default_privacy: Hvussu privatir eru postar? setting_default_sensitive: Merk altĂ­Ă° miĂ°lafĂ­lur sum viĂ°kvæmar setting_delete_modal: VĂ­s vĂ¡ttanarmynd, Ă¡Ă°renn postar verĂ°a strikaĂ°ir + setting_disable_hover_cards: Ger undanvĂ­sing, tĂ¡ mĂºsin verĂ°ur flutt yvir vangan, Ă³virkna setting_disable_swiping: Ger sveipurørslur Ă³virknar setting_display_media: VĂ­stir miĂ°lar setting_display_media_default: SjĂ¡lvvirĂ°i @@ -242,11 +243,13 @@ fo: warn: Fjal viĂ° eini Ă¡varing form_admin_settings: activity_api_enabled: Ătgev samantald hagtøl um brĂºkaravirksemi Ă­ API'num + app_icon: App ikon backups_retention_period: Hvussu leingi verĂ°a brĂºkarasøvn goymd bootstrap_timeline_accounts: Mæl altĂ­Ă° nĂ½ggjum brĂºkarum at fylgja hesar kontur closed_registrations_message: Serskild boĂ°, tĂ¡ taĂ° ikki er møguligt at tilmelda seg content_cache_retention_period: TĂ­Ă°arskeiĂ° fyri varĂ°veiĂ°slu av fjartilfari custom_css: Serskilt CSS + favicon: Favikon mascot: Serskildur maskottur (arvur) media_cache_retention_period: TĂ­Ă°arskeiĂ°, har miĂ°lagoymslur verĂ°a varĂ°veittar peers_api_enabled: Kunnger lista viĂ° uppdagaĂ°um ambætarum Ă­ API'num diff --git a/config/locales/simple_form.ga.yml b/config/locales/simple_form.ga.yml index 3597544ce3a623..2effe1a10cc7a0 100644 --- a/config/locales/simple_form.ga.yml +++ b/config/locales/simple_form.ga.yml @@ -2,47 +2,239 @@ ga: simple_form: hints: + account: + discoverable: Seans go mbeidh do phostĂ¡lacha poiblĂ­ agus do phrĂ³ifĂ­l le feiceĂ¡il nĂ³ molta i rĂ©imsĂ­ Ă©agsĂºla de Mastodon agus is fĂ©idir do phrĂ³ifĂ­l a mholadh dâ€™ĂºsĂ¡ideoirĂ­ eile. + display_name: D'ainm iomlĂ¡n nĂ³ d'ainm spraoi. + fields: Do leathanach baile, forainmneacha, aois, rud ar bith is mian leat. + indexable: Seans go mbeidh do phostĂ¡lacha poiblĂ­ le feiceĂ¡il sna torthaĂ­ cuardaigh ar Mastodon. Seans go mbeidh daoine a d’idirghnĂ­omhaigh le do phostĂ¡lacha in ann iad a chuardach beag beann ar. + note: 'Is fĂ©idir leat @trĂ¡ a dhĂ©anamh ar dhaoine eile nĂ³ #hashtags.' + show_collections: Beidh daoine in ann brabhsĂ¡il trĂ­ do seo a leanas agus do leanĂºna. Feicfidh na daoine a leanann tĂº go leanann tĂº iad beag beann ar. + unlocked: Beidh daoine in ann tĂº a leanĂºint gan cead a iarraidh. DĂ­thiceĂ¡il an dteastaĂ­onn uait athbhreithniĂº a dhĂ©anamh ar iarratais leantacha agus roghnaigh cĂ© acu an nglacfaidh nĂ³ an diĂºltĂ³idh tĂº do leantĂ³irĂ­ nua. account_alias: acct: Sonraigh ainm@fearann don chuntas ar mhaith leat aistriĂº uaidh account_migration: acct: Sonraigh ainm@fearann don chuntas ar mhaith leat aistriĂº chuige + account_warning_preset: + text: Is fĂ©idir leat comhrĂ©ir na bpost a ĂºsĂ¡id, mar URLanna, hashtags agus lua + title: Roghnach. NĂ­l sĂ© le feiceĂ¡il ag an bhfaighteoir admin_account_action: + include_statuses: Feicfidh an t-ĂºsĂ¡ideoir cĂ© na poist ba chĂºis leis an ngnĂ­omh modhnĂ³ireachta nĂ³ leis an rabhadh + send_email_notification: Gheobhaidh an t-ĂºsĂ¡ideoir mĂ­niĂº ar an mĂ©id a tharla lena chuntas + text_html: Roghnach. Is fĂ©idir leat comhrĂ©ir phoist a ĂºsĂ¡id. Is fĂ©idir leat rĂ©amhshocruithe rabhaidh a chur leis chun am a shĂ¡bhĂ¡il + type_html: Roghnaigh cad atĂ¡ le dĂ©anamh le %{acct} types: disable: Cuir cosc ar an ĂºsĂ¡ideoir a chuntas a ĂºsĂ¡id, ach nĂ¡ scrios nĂ¡ folaigh a bhfuil ann. + none: Bain ĂºsĂ¡id as seo chun rabhadh a sheoladh chuig an ĂºsĂ¡ideoir, gan aon ghnĂ­omh eile a spreagadh. + sensitive: Iallach a chur ar cheangaltĂ¡in meĂ¡n an ĂºsĂ¡ideora seo go lĂ©ir a bheith Ă­ogair. + silence: Cosc a chur ar an ĂºsĂ¡ideoir Ă³ bheith in ann postĂ¡il le hinfheictheacht phoiblĂ­, a gcuid postĂ¡lacha agus fĂ³graĂ­ a cheilt ar dhaoine nach leanann iad. DĂºnann sĂ© gach tuairisc i gcoinne an chuntais seo. + suspend: Cosc ar aon idirghnĂ­omhaĂ­ocht Ă³n gcuntas seo nĂ³ chuig an gcuntas seo agus scrios a bhfuil ann. InchĂºlaithe laistigh de 30 lĂ¡. DĂºnann sĂ© gach tuairisc i gcoinne an chuntais seo. + warning_preset_id: Roghnach. Is fĂ©idir leat tĂ©acs saincheaptha a chur le deireadh an rĂ©amhshocraithe fĂ³s + announcement: + all_day: Nuair a dhĂ©antar iad a sheiceĂ¡il, nĂ­ thaispeĂ¡nfar ach dĂ¡taĂ­ an raon ama + ends_at: Roghnach. Beidh an fĂ³gra neamhfhoilsithe go huathoibrĂ­och ag an am seo + scheduled_at: FĂ¡g bĂ¡n chun an fĂ³gra a fhoilsiĂº lĂ¡ithreach + starts_at: Roghnach. I gcĂ¡s go bhfuil d'fhĂ³gra ceangailte le raon ama ar leith + text: Is fĂ©idir leat comhrĂ©ir phoist a ĂºsĂ¡id. Tabhair aird ar an spĂ¡s a ghlacfaidh an fĂ³gra ar scĂ¡ileĂ¡n an ĂºsĂ¡ideora + appeal: + text: NĂ­ fĂ©idir leat achomharc a dhĂ©anamh ach uair amhĂ¡in ar stailc defaults: + autofollow: Leanfaidh daoine a chlĂ¡raĂ­onn trĂ­d an gcuireadh thĂº go huathoibrĂ­och + avatar: WEBP, PNG, GIF nĂ³ JPG. %{size} ar a mhĂ©ad. ĂoslaghdĂ³far Ă© go %{dimensions}px + bot: Cuir in iĂºl do dhaoine eile go ndĂ©anann an cuntas gnĂ­omhartha uathoibrithe den chuid is mĂ³ agus go mb’fhĂ©idir nach ndĂ©anfar monatĂ³ireacht air + context: ComhthĂ©acs amhĂ¡in nĂ³ comhthĂ©acsanna iolracha inar cheart go mbeadh feidhm ag an scagaire + current_password: Chun crĂ­ocha slĂ¡ndĂ¡la cuir isteach pasfhocal an chuntais reatha + current_username: Le deimhniĂº, cuir isteach ainm ĂºsĂ¡ideora an chuntais reatha + digest: Seoltar Ă© tar Ă©is trĂ©imhse fhada neamhghnĂ­omhaĂ­ochta amhĂ¡in agus sa chĂ¡s sin amhĂ¡in go bhfuil aon teachtaireachtaĂ­ pearsanta faighte agat agus tĂº as lĂ¡thair + email: Seolfar rĂ­omhphost deimhnithe chugat + header: WEBP, PNG, GIF nĂ³ JPG. %{size} ar a mhĂ©ad. ĂoslaghdĂ³far Ă© go %{dimensions}px + inbox_url: CĂ³ipeĂ¡il an URL Ă³ leathanach tosaigh an athsheachadĂ¡in is mian leat a ĂºsĂ¡id + irreversible: Imeoidh postĂ¡lacha scagtha go dochĂºlaithe, fiĂº mĂ¡ bhaintear an scagaire nĂ­os dĂ©anaĂ­ + locale: Teanga an chomhĂ©adain ĂºsĂ¡ideora, r-phoist agus fĂ³graĂ­ brĂº + password: ĂsĂ¡id ar a laghad 8 gcarachtar + phrase: DĂ©anfar Ă© a mheaitseĂ¡il beag beann ar chĂ¡sĂ¡il an tĂ©acs nĂ³ ar an Ă¡bhar atĂ¡ ag tabhairt folĂ¡ireamh do phostĂ¡il + scopes: CĂ© na APIanna a mbeidh cead ag an bhfeidhmchlĂ¡r rochtain a fhĂ¡il orthu. MĂ¡ roghnaĂ­onn tĂº raon feidhme barrleibhĂ©il, nĂ­ gĂ¡ duit cinn aonair a roghnĂº. + setting_aggregate_reblogs: NĂ¡ taispeĂ¡in treisithe nua do phoist a treisĂ­odh le dĂ©anaĂ­ (nĂ­ dhĂ©anann difear ach do threisithe nuafhaighte) + setting_always_send_emails: Go hiondĂºil nĂ­ sheolfar fĂ³graĂ­ rĂ­omhphoist agus tĂº ag ĂºsĂ¡id Mastodon go gnĂ­omhach + setting_default_sensitive: TĂ¡ meĂ¡in Ă­ogair i bhfolach de rĂ©ir rĂ©amhshocraithe agus is fĂ©idir iad a nochtadh le cliceĂ¡il + setting_display_media_default: Folaigh meĂ¡in atĂ¡ marcĂ¡ilte mar Ă­ogair setting_display_media_hide_all: Folaigh meĂ¡in i gcĂ³naĂ­ setting_display_media_show_all: TaispeĂ¡in meĂ¡in i gcĂ³naĂ­ + setting_use_blurhash: TĂ¡ grĂ¡dĂ¡in bunaithe ar dhathanna na n-amharcanna ceilte ach cuireann siad salach ar aon mhionsonraĂ­ + setting_use_pending_items: Folaigh nuashonruithe amlĂ­ne taobh thiar de chlic seachas an fotha a scrollĂº go huathoibrĂ­och + username: Is fĂ©idir leat litreacha, uimhreacha, agus bĂ©im a ĂºsĂ¡id + whole_word: Nuair a bhĂ­onn an eochairfhocal nĂ³ frĂ¡sa alfa-uimhriĂºil amhĂ¡in, nĂ­ chuirfear i bhfeidhm Ă© ach amhĂ¡in mĂ¡ mheaitseĂ¡lann sĂ© an focal iomlĂ¡n + domain_allow: + domain: Beidh an fearann ​​seo in ann sonraĂ­ a fhĂ¡il Ă³n bhfreastalaĂ­ seo agus dĂ©anfar sonraĂ­ a thagann isteach uaidh a phrĂ³iseĂ¡il agus a stĂ³rĂ¡il + email_domain_block: + domain: Is fĂ©idir gurb Ă© seo an t-ainm fearainn a thaispeĂ¡nann sa seoladh rĂ­omhphoist nĂ³ sa taifead MX a ĂºsĂ¡ideann sĂ©. DĂ©anfar iad a sheiceĂ¡il nuair a chlĂ¡raĂ­tear iad. + with_dns_records: DĂ©anfar iarracht taifid DNS an fhearainn tugtha a rĂ©iteach agus cuirfear bac ar na torthaĂ­ freisin + featured_tag: + name: 'Seo cuid de na hashtags a dâ€™ĂºsĂ¡id tĂº le dĂ©anaĂ­:' + filters: + action: Roghnaigh an gnĂ­omh ba cheart a dhĂ©anamh nuair a mheaitseĂ¡lann postĂ¡il an scagaire + actions: + hide: Cuir an t-Ă¡bhar scagtha i bhfolach go hiomlĂ¡n, ag iompar amhail is nach raibh sĂ© ann + warn: Folaigh an t-Ă¡bhar scagtha taobh thiar de rabhadh a luann teideal an scagaire + form_admin_settings: + activity_api_enabled: Ăireamh na bpost a foilsĂ­odh go hĂ¡itiĂºil, ĂºsĂ¡ideoirĂ­ gnĂ­omhacha, agus clĂ¡rĂºchĂ¡in nua i buicĂ©id seachtainiĂºla + app_icon: WEBP, PNG, GIF nĂ³ JPG. SĂ¡raĂ­onn sĂ© an deilbhĂ­n rĂ©amhshocraithe aipe ar ghlĂ©asanna soghluaiste le deilbhĂ­n saincheaptha. + backups_retention_period: TĂ¡ an cumas ag ĂºsĂ¡ideoirĂ­ cartlanna dĂ¡ gcuid post a ghiniĂºint le hĂ­oslĂ³dĂ¡il nĂ­os dĂ©anaĂ­. Nuair a bheidh luach dearfach socraithe, scriosfar na cartlanna seo go huathoibrĂ­och Ă³ do stĂ³r tar Ă©is an lĂ­on sonraithe laethanta. + bootstrap_timeline_accounts: Cuirfear na cuntais seo ar bharr na moltaĂ­ a leanann ĂºsĂ¡ideoirĂ­ nua. + closed_registrations_message: Ar taispeĂ¡int nuair a dhĂºntar clĂ¡rĂºchĂ¡in + content_cache_retention_period: Scriosfar gach postĂ¡il Ă³ fhreastalaithe eile (lena n-Ă¡irĂ­tear treisithe agus freagraĂ­) tar Ă©is an lĂ­on sonraithe laethanta, gan aird ar aon idirghnĂ­omhaĂ­ocht ĂºsĂ¡ideora Ă¡itiĂºil leis na postĂ¡lacha sin. ĂirĂ­tear leis seo postĂ¡lacha ina bhfuil ĂºsĂ¡ideoir Ă¡itiĂºil tar Ă©is Ă© a mharcĂ¡il mar leabharmharcanna nĂ³ mar cheanĂ¡in. Caillfear tagairtĂ­ prĂ­obhĂ¡ideacha idir ĂºsĂ¡ideoirĂ­ Ă³ chĂ¡sanna Ă©agsĂºla freisin agus nĂ­ fĂ©idir iad a athchĂ³iriĂº. TĂ¡ ĂºsĂ¡id an tsocraithe seo beartaithe le haghaidh cĂ¡sanna sainchuspĂ³ra agus sĂ¡raĂ­tear go leor ionchais ĂºsĂ¡ideoirĂ­ nuair a chuirtear i bhfeidhm Ă© le haghaidh ĂºsĂ¡id ghinearĂ¡lta. + custom_css: Is fĂ©idir leat stĂ­leanna saincheaptha a chur i bhfeidhm ar an leagan grĂ©asĂ¡in de Mastodon. + favicon: WEBP, PNG, GIF nĂ³ JPG. SĂ¡raĂ­onn sĂ© an favicon Mastodon rĂ©amhshocraithe le deilbhĂ­n saincheaptha. + mascot: SĂ¡raĂ­onn sĂ© an lĂ©arĂ¡id san ardchomhĂ©adan grĂ©asĂ¡in. + media_cache_retention_period: DĂ©antar comhaid meĂ¡n Ă³ phoist a dhĂ©anann cianĂºsĂ¡ideoirĂ­ a thaisceadh ar do fhreastalaĂ­. Nuair a bheidh luach dearfach socraithe, scriosfar na meĂ¡in tar Ă©is an lĂ­on sonraithe laethanta. MĂ¡ iarrtar na sonraĂ­ meĂ¡n tar Ă©is Ă© a scriosadh, dĂ©anfar Ă© a ath-Ă­oslĂ³dĂ¡il, mĂ¡ tĂ¡ an t-Ă¡bhar foinse fĂ³s ar fĂ¡il. Mar gheall ar shrianta ar cĂ© chomh minic is atĂ¡ cĂ¡rtaĂ­ rĂ©amhamhairc ag vĂ³taĂ­ocht do shuĂ­omhanna trĂ­Ăº pĂ¡irtĂ­, moltar an luach seo a shocrĂº go 14 lĂ¡ ar a laghad, nĂ³ nĂ­ dhĂ©anfar cĂ¡rtaĂ­ rĂ©amhamhairc naisc a nuashonrĂº ar Ă©ileamh roimh an am sin. + peers_api_enabled: Liosta de na hainmneacha fearainn ar thĂ¡inig an freastalaĂ­ seo orthu sa choinbhleacht. NĂ­l aon sonraĂ­ san Ă¡ireamh anseo faoi cĂ© acu an ndĂ©anann tĂº cĂ³nascadh le freastalaĂ­ ar leith, dĂ­reach go bhfuil a fhios ag do fhreastalaĂ­ faoi. ĂsĂ¡ideann seirbhĂ­sĂ­ a bhailĂ­onn staitisticĂ­ ar chĂ³naidhm go ginearĂ¡lta Ă© seo. + profile_directory: LiostaĂ­onn an t-eolaire prĂ³ifĂ­le na hĂºsĂ¡ideoirĂ­ go lĂ©ir a roghnaigh isteach le bheith in-aimsithe. + require_invite_text: Nuair a bhĂ­onn faomhadh lĂ¡imhe ag teastĂ¡il le haghaidh clĂ¡rĂºchĂ¡in, dĂ©an an "CĂ©n fĂ¡th ar mhaith leat a bheith pĂ¡irteach?" ionchur tĂ©acs Ă©igeantach seachas roghnach + site_contact_email: Conas is fĂ©idir le daoine dul i dteagmhĂ¡il leat le haghaidh fiosrĂºchĂ¡n dlĂ­thiĂºil nĂ³ tacaĂ­ochta. + site_contact_username: Conas is fĂ©idir le daoine dul i dteagmhĂ¡il leat ar Mastodon. + site_extended_description: Aon fhaisnĂ©is bhreise a d’fhĂ©adfadh a bheith ĂºsĂ¡ideach do chuairteoirĂ­ agus dâ€™ĂºsĂ¡ideoirĂ­. Is fĂ©idir Ă© a struchtĂºrĂº le comhrĂ©ir Markdown. + site_short_description: Cur sĂ­os gairid chun cabhrĂº le do fhreastalaĂ­ a aithint go uathĂºil. CĂ© atĂ¡ Ă¡ rith, cĂ© dĂ³ a bhfuil sĂ©? + site_terms: Bain ĂºsĂ¡id as do pholasaĂ­ prĂ­obhĂ¡ideachta fĂ©in nĂ³ fĂ¡g bĂ¡n Ă© chun an rĂ©amhshocrĂº a ĂºsĂ¡id. Is fĂ©idir Ă© a struchtĂºrĂº le comhrĂ©ir Markdown. + site_title: Conas is fĂ©idir le daoine tagairt a dhĂ©anamh do do fhreastalaĂ­ seachas a ainm fearainn. + status_page_url: URL leathanach inar fĂ©idir le daoine stĂ¡das an fhreastalaĂ­ seo a fheiceĂ¡il le linn briseadh amach + theme: TĂ©ama a fheiceann cuairteoirĂ­ logĂ¡ilte amach agus ĂºsĂ¡ideoirĂ­ nua. + thumbnail: ĂomhĂ¡ thart ar 2:1 ar taispeĂ¡int taobh le faisnĂ©is do fhreastalaĂ­. + timeline_preview: Beidh cuairteoirĂ­ logĂ¡ilte amach in ann na postĂ¡lacha poiblĂ­ is dĂ©anaĂ­ atĂ¡ ar fĂ¡il ar an bhfreastalaĂ­ a bhrabhsĂ¡il. + trendable_by_default: LĂ©im ar athbhreithniĂº lĂ¡imhe ar Ă¡bhar treochta. Is fĂ©idir mĂ­reanna aonair a bhaint as treochtaĂ­ fĂ³s tar Ă©is an fhĂ­ric. + trends: LĂ©irĂ­onn treochtaĂ­ cĂ© na postĂ¡lacha, hashtags agus scĂ©alta nuachta atĂ¡ ag tarraingt ar do fhreastalaĂ­. + trends_as_landing_page: TaispeĂ¡in inneachar treochta d'ĂºsĂ¡ideoirĂ­ agus do chuairteoirĂ­ atĂ¡ logĂ¡ilte amach in ionad cur sĂ­os ar an bhfreastalaĂ­ seo. ÉilĂ­onn treochtaĂ­ a chumasĂº. + form_challenge: + current_password: TĂ¡ tĂº ag dul isteach i limistĂ©ar slĂ¡n + imports: + data: Comhad CSV easpĂ³rtĂ¡ilte Ă³ fhreastalaĂ­ Mastodon eile + invite_request: + text: CabhrĂ³idh sĂ© seo linn d’iarratas a athbhreithniĂº + ip_block: + comment: Roghnach. Cuimhnigh cĂ©n fĂ¡th ar chuir tĂº an riail seo leis. + expires_in: Is acmhainn chrĂ­ochta iad seoltaĂ­ IP, uaireanta roinntear iad agus is minic a athraĂ­onn lĂ¡mha. Ar an gcĂºis seo, nĂ­ mholtar bloic IP Ă©iginnte. + ip: Cuir isteach seoladh IPv4 nĂ³ IPv6. Is fĂ©idir leat raonta iomlĂ¡na a bhlocĂ¡il ag baint ĂºsĂ¡ide as an chomhrĂ©ir CIDR. BĂ­ cĂºramach gan tĂº fĂ©in a ghlasĂ¡il amach! + severities: + no_access: Cuir bac ar rochtain ar na hacmhainnĂ­ go lĂ©ir + sign_up_block: NĂ­ bheidh clĂ¡rĂº nua indĂ©anta + sign_up_requires_approval: Beidh do cheadĂº ag teastĂ¡il le haghaidh clĂ¡rĂºchĂ¡in nua + severity: Roghnaigh cad a tharlĂ³idh le hiarratais Ă³n IP seo + rule: + hint: Roghnach. Tabhair tuilleadh sonraĂ­ faoin riail + text: DĂ©an cur sĂ­os ar riail nĂ³ riachtanas d'ĂºsĂ¡ideoirĂ­ ar an bhfreastalaĂ­ seo. DĂ©an iarracht Ă© a choinneĂ¡il gearr agus simplĂ­ + sessions: + otp: 'Cuir isteach an cĂ³d dhĂ¡ fhachtĂ³ir ginte ag d''aip ghuthĂ¡in nĂ³ ĂºsĂ¡id ceann de do chĂ³id athshlĂ¡naithe:' + webauthn: MĂ¡s eochair USB atĂ¡ ann dĂ©an cinnte Ă© a chur isteach agus, mĂ¡s gĂ¡, tapĂ¡il Ă­. + settings: + indexable: Seans go mbeidh do leathanach prĂ³ifĂ­le le feiceĂ¡il i dtorthaĂ­ cuardaigh ar Google, Bing agus eile. + show_application: Beidh tĂº in ann a fheiceĂ¡il i gcĂ³naĂ­ cĂ©n aip a d’fhoilsigh do phostĂ¡il beag beann ar. + tag: + name: NĂ­ fĂ©idir leat ach cĂ¡sĂ¡il na litreacha a athrĂº, mar shampla, chun Ă© a dhĂ©anamh nĂ­os inlĂ©ite + user: + chosen_languages: Nuair a dhĂ©antar iad a sheiceĂ¡il, nĂ­ thaispeĂ¡nfar ach postĂ¡lacha i dteangacha roghnaithe in amlĂ­nte poiblĂ­ + role: RialaĂ­onn an rĂ³l na ceadanna atĂ¡ ag an ĂºsĂ¡ideoir + user_role: + color: Dath le hĂºsĂ¡id don rĂ³l ar fud an ChomhĂ©adain, mar RGB i bhformĂ¡id heicsidheachĂºlach + highlighted: DĂ©anann sĂ© seo an rĂ³l le feiceĂ¡il go poiblĂ­ + name: Ainm poiblĂ­ an rĂ³il, mĂ¡ tĂ¡ an rĂ³l socraithe le taispeĂ¡int mar shuaitheantas + permissions_as_keys: Beidh rochtain ag ĂºsĂ¡ideoirĂ­ a bhfuil an rĂ³l seo acu ar... + position: Cinneann rĂ³l nĂ­os airde rĂ©iteach coinbhleachta i gcĂ¡sanna Ă¡irithe. NĂ­ fĂ©idir gnĂ­omhartha Ă¡irithe a dhĂ©anamh ach amhĂ¡in ar rĂ³il a bhfuil tosaĂ­ocht nĂ­os Ă­sle acu + webhook: + events: Roghnaigh imeachtaĂ­ le seoladh + template: Cum do phĂ¡lasta JSON fĂ©in ag baint ĂºsĂ¡ide as idirshuĂ­omh athrĂ³g. FĂ¡g bĂ¡n le haghaidh JSON rĂ©amhshocraithe. + url: An Ă¡it a seolfar imeachtaĂ­ chuig labels: account: + discoverable: PrĂ³ifĂ­l gnĂ© agus postĂ¡lacha in halgartaim fionnachtana fields: name: LipĂ©ad + value: Ăbhar + indexable: Cuir postĂ¡lacha poiblĂ­ san Ă¡ireamh sna torthaĂ­ cuardaigh + show_collections: TaispeĂ¡in seo a leanas agus leanĂºna ar phrĂ³ifĂ­l + unlocked: Glac le leantĂ³irĂ­ nua go huathoibrĂ­och + account_alias: + acct: LĂ¡imhseĂ¡il an seanchuntais + account_migration: + acct: LĂ¡imhseĂ¡il an chuntais nua account_warning_preset: + text: TĂ©acs rĂ©amhshocraithe title: Teideal admin_account_action: + include_statuses: Cuir postĂ¡lacha tuairiscithe san Ă¡ireamh sa rĂ­omhphost + send_email_notification: Cuir an t-ĂºsĂ¡ideoir ar an eolas trĂ­ rĂ­omhphost text: Rabhadh saincheaptha + type: GnĂ­omh types: disable: Reoigh none: Seol rabhadh + sensitive: Ăogair silence: Teorannaigh suspend: Cuir ar fionraĂ­ + warning_preset_id: Bain ĂºsĂ¡id as rĂ©amhshocrĂº rabhaidh announcement: + all_day: Imeacht uile-lae + ends_at: Deireadh an imeachta + scheduled_at: FoilsiĂº sceideal + starts_at: TĂºs na hĂ³cĂ¡ide text: FĂ³gra + appeal: + text: MĂ­nigh cĂ©n fĂ¡th ar cheart an cinneadh seo a fhreaschur defaults: + autofollow: Tabhair cuireadh do chuntas a leanĂºint avatar: AbhatĂ¡r + bot: Is cuntas uathoibrithe Ă© seo + chosen_languages: Scag teangacha + confirm_new_password: Deimhnigh pasfhocal nua + confirm_password: Deimhnigh Pasfhocal + context: ComhthĂ©acsanna a scagadh + current_password: Pasfhocal reatha data: SonraĂ­ display_name: Ainm taispeĂ¡na email: Seoladh rĂ­omhphoist + expires_in: In Ă©ag tar Ă©is + fields: RĂ©imsĂ­ breise header: CeanntĂ¡sc + honeypot: "%{label} (nĂ¡ lĂ­on isteach)" + inbox_url: URL an bhosca isteach sealaĂ­ochta + irreversible: Droim ar aghaidh in ionad bheith ag folaigh + locale: Teanga comhĂ©adan + max_uses: UaslĂ­on ĂºsĂ¡idĂ­ new_password: Pasfhocal nua note: BeathaisnĂ©is + otp_attempt: CĂ³d dhĂ¡-fhachtĂ³ir password: Pasfhocal + phrase: Eochairfhocal nĂ³ frĂ¡sa + setting_advanced_layout: Cumasaigh ardchomhĂ©adan grĂ©asĂ¡in + setting_aggregate_reblogs: Treisithe grĂºpa i lĂ­nte ama + setting_always_send_emails: Seol fĂ³graĂ­ rĂ­omhphoist i gcĂ³naĂ­ + setting_auto_play_gif: Gifs beoite go huathoibrĂ­och a imirt + setting_boost_modal: TaispeĂ¡in dialĂ³g deimhnithe roimh threisiĂº + setting_default_language: Teanga postĂ¡la + setting_default_privacy: PostĂ¡il prĂ­obhĂ¡ideachta + setting_default_sensitive: MarcĂ¡il na meĂ¡in mar Ă­ogair i gcĂ³naĂ­ + setting_delete_modal: TaispeĂ¡in dialĂ³g deimhnithe sula scriostar postĂ¡il + setting_disable_hover_cards: DĂ­chumasaigh rĂ©amhamharc prĂ³ifĂ­le ar ainlĂ­on + setting_disable_swiping: DĂ­chumasaigh gluaiseachtaĂ­ swiping + setting_display_media: TaispeĂ¡int meĂ¡in setting_display_media_default: RĂ©amhshocrĂº setting_display_media_hide_all: Cuir uile i bhfolach setting_display_media_show_all: TaispeĂ¡in uile + setting_expand_spoilers: MĂ©adaigh postĂ¡lacha atĂ¡ marcĂ¡ilte le rabhaidh inneachair i gcĂ³naĂ­ + setting_hide_network: Folaigh do ghraf sĂ³isialta + setting_reduce_motion: LaghdĂº ar an tairiscint i beochan + setting_system_font_ui: ĂsĂ¡id clĂ³ rĂ©amhshocraithe an chĂ³rais setting_theme: TĂ©ama suĂ­mh setting_trends: TaispeĂ¡in treochtaĂ­ an lae inniu + setting_unfollow_modal: TaispeĂ¡in dialĂ³g deimhnithe sula ndĂ­leanfaidh tĂº duine Ă©igin + setting_use_blurhash: TaispeĂ¡in grĂ¡dĂ¡in ildaite do mheĂ¡in fholaithe + setting_use_pending_items: Modh mall + severity: DĂ©ine + sign_in_token_attempt: CĂ³d slĂ¡ndĂ¡la title: Teideal + type: CineĂ¡l iompĂ³rtĂ¡la username: Ainm ĂºsĂ¡ideora + username_or_email: Ainm ĂsĂ¡ideora nĂ³ RĂ­omhphost + whole_word: Focal ar fad + email_domain_block: + with_dns_records: Cuir taifid MX agus IPanna an fhearainn san Ă¡ireamh featured_tag: name: Haischlib filters: @@ -50,27 +242,100 @@ ga: hide: Cuir i bhfolach go hiomlĂ¡n warn: Cuir i bhfolach le rabhadh form_admin_settings: + activity_api_enabled: Foilsigh staitisticĂ­ comhiomlĂ¡na faoi ghnĂ­omhaĂ­ocht ĂºsĂ¡ideoirĂ­ san API + app_icon: DeilbhĂ­n aip + backups_retention_period: TrĂ©imhse choinneĂ¡la cartlainne ĂºsĂ¡ideora + bootstrap_timeline_accounts: Mol na cuntais seo d'ĂºsĂ¡ideoirĂ­ nua i gcĂ³naĂ­ + closed_registrations_message: Teachtaireacht saincheaptha nuair nach bhfuil sĂ­nithe suas ar fĂ¡il + content_cache_retention_period: TrĂ©imhse choinneĂ¡la inneachair cianda + custom_css: CSS saincheaptha + favicon: Favicon + mascot: MascĂ³g saincheaptha (oidhreacht) + media_cache_retention_period: TrĂ©imhse choinneĂ¡la taisce meĂ¡n + peers_api_enabled: Foilsigh liosta de na freastalaithe aimsithe san API + profile_directory: Cumasaigh eolaire prĂ³ifĂ­le + registrations_mode: CĂ© atĂ¡ in ann clĂ¡rĂº + require_invite_text: A cheangal ar chĂºis a bheith pĂ¡irteach + show_domain_blocks: TaispeĂ¡in bloic fearainn + show_domain_blocks_rationale: TaispeĂ¡in cĂ©n fĂ¡th ar cuireadh bac ar fhearann + site_contact_email: R-phost teagmhĂ¡la + site_contact_username: Ainm ĂºsĂ¡ideora teagmhĂ¡la site_extended_description: Cur sĂ­os fada site_short_description: Cur sĂ­os freastalaĂ­ site_terms: PolasaĂ­ prĂ­obhĂ¡ideachais site_title: Ainm freastalaĂ­ + status_page_url: URL an leathanaigh stĂ¡dais + theme: TĂ©ama rĂ©amhshocraithe + thumbnail: Mionsamhail freastalaĂ­ + timeline_preview: Ceadaigh rochtain neamhdheimhnithe ar amlĂ­nte poiblĂ­ + trendable_by_default: Ceadaigh treochtaĂ­ gan athbhreithniĂº roimh rĂ© + trends: Cumasaigh treochtaĂ­ + trends_as_landing_page: ĂsĂ¡id treochtaĂ­ mar an leathanach tuirlingthe + interactions: + must_be_follower: Cuir bac ar fhĂ³graĂ­ Ă³ dhaoine nach leantĂ³irĂ­ iad + must_be_following: Cuir bac ar fhĂ³graĂ­ Ă³ dhaoine nach leanann tĂº + must_be_following_dm: Cuir bac ar theachtaireachtaĂ­ dĂ­reacha Ă³ dhaoine nach leanann tĂº invite: comment: RĂ¡iteas + invite_request: + text: CĂ©n fĂ¡th ar mhaith leat a bheith pĂ¡irteach? ip_block: comment: RĂ¡iteas ip: IP + severities: + no_access: Rochtain a bhlocĂ¡il + sign_up_block: Cuir bac ar chlĂ¡rĂºchĂ¡in + sign_up_requires_approval: Teorainn le clĂ¡rĂº severity: Riail notification_emails: + appeal: DĂ©anann duine Ă©igin achomharc i gcoinne chinneadh modhnĂ³ra + digest: Seol r-phoist achoimre + favourite: Is fearr le duine Ă©igin do phostĂ¡il follow: Lean duine Ă©igin tĂº + follow_request: D'iarr duine Ă©igin tĂº a leanĂºint + mention: Luaigh duine Ă©igin tĂº + pending_account: NĂ­ mĂ³r athbhreithniĂº a dhĂ©anamh ar chuntas nua reblog: Mhol duine Ă©igin do phostĂ¡il + report: TĂ¡ tuairisc nua curtha isteach + software_updates: + all: FĂ³gra a thabhairt ar gach nuashonrĂº + critical: FĂ³gra a thabhairt ar nuashonruithe rĂ­thĂ¡bhachtacha amhĂ¡in + label: TĂ¡ leagan nua Mastodon ar fĂ¡il + none: NĂ¡ cuir nuashonruithe ar an eolas choĂ­che (nĂ­ mholtar Ă©) + patch: FĂ³gra ar nuashonruithe bugfix + trending_tag: TeastaĂ­onn athbhreithniĂº ar threocht nua rule: + hint: Eolas breise text: Riail + settings: + indexable: Cuir leathanach prĂ³ifĂ­le san innill chuardaigh + show_application: TaispeĂ¡in cĂ©n aip Ă³nar sheol tĂº postĂ¡il tag: + listable: Lig don hashchlib seo a bheith le feiceĂ¡il i gcuardach agus i moltaĂ­ name: Haischlib + trendable: Lig don haischlib seo a bheith le feiceĂ¡il faoi threochtaĂ­ + usable: Lig do phostĂ¡lacha an hashchlib seo a ĂºsĂ¡id user: role: RĂ³l + time_zone: Crios ama user_role: + color: Dath suaitheantas + highlighted: TaispeĂ¡in rĂ³l mar shuaitheantas ar phrĂ³ifĂ­lĂ­ ĂºsĂ¡ideora name: Ainm + permissions_as_keys: Ceadanna + position: TosaĂ­ocht + webhook: + events: ImeachtaĂ­ cumasaithe + template: TeimplĂ©ad pĂ¡-ualach + url: URL crĂ­ochphointe + 'no': NĂ­l + not_recommended: NĂ­ mholtar + overridden: SĂ¡raithe recommended: Molta required: mark: "*" + text: ag teastĂ¡il + title: + sessions: + webauthn: ĂsĂ¡id ceann de d'eochracha slĂ¡ndĂ¡la chun sĂ­niĂº isteach + 'yes': TĂ¡ diff --git a/config/locales/simple_form.gl.yml b/config/locales/simple_form.gl.yml index 0411c45bc169f4..57bf31b42d2851 100644 --- a/config/locales/simple_form.gl.yml +++ b/config/locales/simple_form.gl.yml @@ -211,6 +211,7 @@ gl: setting_default_privacy: Privacidade da publicaciĂ³n setting_default_sensitive: Marcar sempre multimedia como sensible setting_delete_modal: Solicitar confirmaciĂ³n antes de eliminar unha publicaciĂ³n + setting_disable_hover_cards: Desactivar vista previa do perfil ao poñerse enriba setting_disable_swiping: Desactivar opciĂ³ns de desprazamento setting_display_media: Mostrar multimedia setting_display_media_default: Por defecto @@ -242,11 +243,13 @@ gl: warn: Agochar tras un aviso form_admin_settings: activity_api_enabled: Publicar na API estatĂ­sticas agregadas acerca da actividade das usuarias + app_icon: Icona da app backups_retention_period: PerĂ­odo de retenciĂ³n do arquivo da usuaria bootstrap_timeline_accounts: Recomendar sempre estas contas Ă¡s novas usuarias closed_registrations_message: Mensaxe personalizada para cando o rexistro estĂ¡ pechado content_cache_retention_period: PerĂ­odo de retenciĂ³n de contido remoto custom_css: CSS personalizado + favicon: Favicon mascot: Mascota propia (herdado) media_cache_retention_period: PerĂ­odo de retenciĂ³n da cachĂ© multimedia peers_api_enabled: Publicar na API unha lista dos servidores descubertos @@ -255,7 +258,7 @@ gl: require_invite_text: Pedir unha razĂ³n para unirse show_domain_blocks: Amosar dominios bloqueados show_domain_blocks_rationale: Explicar porque estĂ¡n bloqueados os dominios - site_contact_email: Email de contacto + site_contact_email: Correo de contacto site_contact_username: Nome do contacto site_extended_description: DescriciĂ³n ampla site_short_description: DescriciĂ³n do servidor diff --git a/config/locales/simple_form.he.yml b/config/locales/simple_form.he.yml index 65c6f6110fc2bf..f79ddb9b34e832 100644 --- a/config/locales/simple_form.he.yml +++ b/config/locales/simple_form.he.yml @@ -211,6 +211,7 @@ he: setting_default_privacy: פרטיות ההודעות setting_default_sensitive: ת×יד לתת סי×ון "רגיש" ל×דיה setting_delete_modal: להר×ות תיבת ×ישור לפני ×חיקת חיצרוץ + setting_disable_hover_cards: כבה הצצה ×קדי××” לפרופיל בעת ×עבר עכבר ×עליו setting_disable_swiping: ביטול החלקת-צד setting_display_media: תצוגת ×דיה setting_display_media_default: ברירת ×חדל @@ -242,11 +243,13 @@ he: warn: הסתרה ×¢× ×זהרה form_admin_settings: activity_api_enabled: ×¤×¨×¡×•× ×¡×˜×˜×™×¡×˜×™×§×•×ª ×קובצות עבור פעילות ×שת××©×™× ×‘××צעות ×נשק התוכנה + app_icon: ×ייקון יישו×ון backups_retention_period: תקופת הש×ירה של ×רכיון ×”×שת×ש bootstrap_timeline_accounts: ×”×לצה על חשבונות ×לה ל×שת××©×™× ×—×“×©×™× closed_registrations_message: הודעה ×יוחדת כשההרש××” ×œ× ××ופשרת content_cache_retention_period: תקופת הש×ירה על תוכן חיצוני custom_css: CSS בהת×××” ×ישית + favicon: ס×ל ××•×¢×“×¤×™× (Favicon) mascot: ס×ל השרת (ישן) media_cache_retention_period: תקופת ש×ירת ×ט×ון ×דיה peers_api_enabled: ×¤×¨×¡× ×¨×©×™××” של ×©×¨×ª×™× ×©× ×ª×’×œ×• ב××צעות ×”-API diff --git a/config/locales/simple_form.hu.yml b/config/locales/simple_form.hu.yml index 6ccca2bc847928..518a82ec163a99 100644 --- a/config/locales/simple_form.hu.yml +++ b/config/locales/simple_form.hu.yml @@ -211,6 +211,7 @@ hu: setting_default_privacy: BejegyzĂ©sek lĂ¡thatĂ³sĂ¡ga setting_default_sensitive: Minden mĂ©diafĂ¡jl megjelölĂ©se kĂ©nyeskĂ©nt setting_delete_modal: MegerÅ‘sĂ­tĂ©s kĂ©rĂ©se bejegyzĂ©s törlĂ©se elÅ‘tt + setting_disable_hover_cards: ProfilelÅ‘nĂ©zet letiltĂ¡sa fölĂ©hĂºzĂ¡s esetĂ©n setting_disable_swiping: ElhĂºzĂ¡s művelet kikapcsolĂ¡sa setting_display_media: MĂ©dia megjelenĂ­tĂ©se setting_display_media_default: AlapĂ©rtelmezĂ©s @@ -242,11 +243,13 @@ hu: warn: ElrejtĂ©s figyelmeztetĂ©ssel form_admin_settings: activity_api_enabled: Ă–sszesĂ­tett statisztikĂ¡k közzĂ©tĂ©tele az API-ban a felhasznĂ¡lĂ³k aktivitĂ¡sĂ¡rĂ³l + app_icon: AlkalmazĂ¡sikon backups_retention_period: FelhasznĂ¡lĂ³i archĂ­vum megtartĂ¡si idÅ‘szaka bootstrap_timeline_accounts: Mindig javasoljuk ezeket a fiĂ³kokat az Ăºj felhasznĂ¡lĂ³k szĂ¡mĂ¡ra closed_registrations_message: A feliratkozĂ¡skor megjelenÅ‘ egyĂ©ni Ă¼zenet nem Ă©rhetÅ‘ el content_cache_retention_period: TĂ¡voli tartalmak megtartĂ¡si idÅ‘szaka custom_css: EgyĂ©ni CSS + favicon: KönyvjelzÅ‘ikon mascot: EgyĂ©ni kabala (örökölt) media_cache_retention_period: MĂ©dia-gyorsĂ­tĂ³tĂ¡r megtartĂ¡si idÅ‘szaka peers_api_enabled: Felfedezett kiszolgĂ¡lĂ³k listĂ¡jĂ¡nak közzĂ©tĂ©tele az API-ban diff --git a/config/locales/simple_form.is.yml b/config/locales/simple_form.is.yml index 044e24deb03ac9..9e28ef9be695b9 100644 --- a/config/locales/simple_form.is.yml +++ b/config/locales/simple_form.is.yml @@ -211,6 +211,7 @@ is: setting_default_privacy: Gagnaleynd færslna setting_default_sensitive: Alltaf merkja myndefni sem viĂ°kvæmt setting_delete_modal: Birta staĂ°festingarglugga Ă¡Ă°ur en færslu er eytt + setting_disable_hover_cards: Gera Ă³virka forskoĂ°un notandasniĂ°s viĂ° yfirsvif setting_disable_swiping: Gera strokuhreyfingar Ă³virkar setting_display_media: Birting myndefnis setting_display_media_default: SjĂ¡lfgefiĂ° @@ -242,11 +243,13 @@ is: warn: Fela meĂ° aĂ°vörun form_admin_settings: activity_api_enabled: Birta samantektartölfræði um virkni notanda Ă­ API-kerfisviĂ°mĂ³tinu + app_icon: TĂ¡knmynd forrits backups_retention_period: TĂ­malengd sem safni notandans er haldiĂ° eftir bootstrap_timeline_accounts: Alltaf mæla meĂ° Ă¾essum notendaaĂ°göngum fyrir nĂ½ja notendur closed_registrations_message: SĂ©rsniĂ°in skilaboĂ° Ă¾egar ekki er hægt aĂ° nĂ½skrĂ¡ content_cache_retention_period: TĂ­mabil sem Ă¡ aĂ° geyma fjartengt efni custom_css: SĂ©rsniĂ°iĂ° CSS + favicon: AuĂ°kennismynd mascot: SĂ©rsniĂ°iĂ° gæludĂ½r (eldra) media_cache_retention_period: TĂ­malengd sem myndefni haldiĂ° peers_api_enabled: Birta lista yfir uppgötvaĂ°a netĂ¾jĂ³na Ă­ API-kerfisviĂ°mĂ³tinu diff --git a/config/locales/simple_form.it.yml b/config/locales/simple_form.it.yml index f5624344b9a3e7..eddc86b4e11ad8 100644 --- a/config/locales/simple_form.it.yml +++ b/config/locales/simple_form.it.yml @@ -211,6 +211,7 @@ it: setting_default_privacy: Privacy dei post setting_default_sensitive: Segna sempre i media come sensibili setting_delete_modal: Mostra dialogo di conferma prima di eliminare un post + setting_disable_hover_cards: Disabilita l'anteprima del profilo al passaggio del mouse setting_disable_swiping: Disabilita i movimenti di scorrimento setting_display_media: Visualizzazione dei media setting_display_media_default: Predefinita @@ -242,11 +243,13 @@ it: warn: Nascondi con avviso form_admin_settings: activity_api_enabled: Pubblica le statistiche aggregate sull'attivitĂ  degli utenti nell'API + app_icon: Icona app backups_retention_period: Periodo di conservazione dell'archivio utente bootstrap_timeline_accounts: Consiglia sempre questi account ai nuovi utenti closed_registrations_message: Messaggio personalizzato quando le iscrizioni non sono disponibili content_cache_retention_period: Periodo di ritenzione del contenuto remoto custom_css: Personalizza CSS + favicon: Favicon mascot: Personalizza mascotte (legacy) media_cache_retention_period: Periodo di conservazione della cache multimediale peers_api_enabled: Pubblica l'elenco dei server scoperti nell'API diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml index 664082dabc41ce..56b17ab000718b 100644 --- a/config/locales/simple_form.ja.yml +++ b/config/locales/simple_form.ja.yml @@ -211,6 +211,7 @@ ja: setting_default_privacy: æ•ç¨¿ă®å…¬é–‹ç¯„囲 setting_default_sensitive: ăƒ¡ăƒ‡ă‚£ă‚¢ă‚’å¸¸ă«é–²è¦§æ³¨æ„ă¨ă—ă¦ăƒăƒ¼ă‚¯ă™ă‚‹ setting_delete_modal: æ•ç¨¿ă‚’å‰é™¤ă™ă‚‹å‰ă«ç¢ºèªăƒ€ă‚¤ă‚¢ăƒ­ă‚°ă‚’表示ă™ă‚‹ + setting_disable_hover_cards: ăƒă‚¦ă‚¹ă‚ªăƒ¼ăƒăƒ¼ă§ăƒ—ăƒ­ăƒ•ă‚£ăƒ¼ăƒ«ă‚’ăƒăƒƒăƒ—ă‚¢ăƒƒăƒ—ă—ăªă„ setting_disable_swiping: ă‚¹ăƒ¯ă‚¤ăƒ—ă§ă®åˆ‡ă‚替ăˆă‚’ç„¡å¹ă«ă™ă‚‹ setting_display_media: ăƒ¡ăƒ‡ă‚£ă‚¢ă®è¡¨ç¤º setting_display_media_default: 標準 diff --git a/config/locales/simple_form.kab.yml b/config/locales/simple_form.kab.yml index 9461f16cd54577..63e2b9aacf1bf6 100644 --- a/config/locales/simple_form.kab.yml +++ b/config/locales/simple_form.kab.yml @@ -5,6 +5,7 @@ kab: account: display_name: Isem-ik·im ummid neÉ£ isem-ik·im n uqeṣṣer. fields: Asebter-ik·im agejdan, imqimen, leεmer, ayen tebÉ£iá¸. + note: 'TzemreḠad d-@tbedreḠimdanen niá¸en neÉ£ #ihacá¹­agen.' account_alias: acct: Sekcem isem n umseqdac@domain n umiá¸an s wansa itebγiḠad gujjeḠaccount_migration: @@ -27,6 +28,8 @@ kab: name: 'Ha-t-an kra seg ihacá¹­agen i tesseqdaceḠussan-a ineggura maá¸i :' imports: data: Afaylu CSV id yusan seg uqeddac-nniá¸en n Maṣṭudun + invite_request: + text: Aya ad aÉ£-iÉ›iwen ad nessenqed tuttra-k•m ip_block: comment: D afrayan. Cfu É£ef wayÉ£er i terniḠalugen-a. severities: @@ -36,6 +39,8 @@ kab: fields: name: Tabzimt value: Agbur + account_alias: + acct: Tansa n umiá¸an aqbur account_migration: acct: Tansa n umiá¸an amaynut account_warning_preset: @@ -51,6 +56,7 @@ kab: suspend: Ḥbes di leεá¸il announcement: ends_at: Tagara n tedyant + starts_at: Tazwara n tedyant text: AlÉ£u defaults: autofollow: Æreá¸-it-id ad yeá¸fer amiá¸an-ik·im @@ -59,18 +65,25 @@ kab: chosen_languages: Sizdeg tutlayin confirm_new_password: Sentem awal uffir amaynut confirm_password: Sentem awal uffir + context: Isatalen n umsizdeg current_password: Awal uffir n tura data: Isefka display_name: Isem ara d-yettwaskanen email: Tansa imayl expires_in: Ad yemmet + fields: Urtiyen niá¸en header: Ixef + honeypot: "%{label} (ur tettaÄÄar ara)" + inbox_url: URL n tbewwaá¸t n urmas yettwacudden + irreversible: Kkes deg wadeg n tuffra locale: Tutlayt n wegrudem max_uses: Amá¸an afellay n iseqdacen new_password: Awal uffir amaynut note: Tameddurt otp_attempt: Tangalt n snat n tarayin password: Awal uffir + phrase: Awal n tsarut neÉ£ tafyirt + setting_advanced_layout: Rmed agrudem n web leqqayen setting_default_language: Tutlayt n tira setting_default_privacy: Tabaá¸nit n tira setting_display_media_default: Akk-a kan @@ -88,8 +101,15 @@ kab: featured_tag: name: Ahacá¹­ag form_admin_settings: + custom_css: CSS udmawan + profile_directory: Rmed akaram n imaγnuten + site_contact_email: Imayl n unermas + site_short_description: Aglam n uqeddac site_terms: Tasertit tabaá¸nit site_title: Isem n uqeddac + status_page_url: URL n uusebter n waddaden + theme: Asentel amezwer + thumbnail: Tanfult n uqeddac interactions: must_be_follower: Ssewḥel ilÉ£a sÉ£ur wid akked tid ur yellin ara d imeá¸faren-ik·im must_be_following: Ssewḥel ilÉ£a sÉ£ur wid akked tid ur tettá¸afareḠara @@ -109,18 +129,25 @@ kab: follow: Yeá¸fer-ik·im-id walbÉ›aḠfollow_request: Ma yella win i d-yessutren ad k·em-yeá¸fer mention: Yuder-ik·em-id walbÉ›aḠ+ pending_account: Amiá¸an amaynut yesran asenqed reblog: Yella win yesselhan adda-dik·im + report: Aneqis amaynut yettwazen rule: hint: Isallen-nniá¸en text: Alugen tag: name: Ahacá¹­ag user: + role: Tamlilt time_zone: Tamnaá¸t tasragant user_role: name: Isem permissions_as_keys: Tisirag + webhook: + events: Tidyanin turmidin 'no': Ala + not_recommended: Ur yettuwelleh ara + overridden: YeÄÄur recommended: Yettuwelleh required: mark: "*" diff --git a/config/locales/simple_form.ko.yml b/config/locales/simple_form.ko.yml index 54d36eafe0393f..b94b4b3d40425b 100644 --- a/config/locales/simple_form.ko.yml +++ b/config/locales/simple_form.ko.yml @@ -211,6 +211,7 @@ ko: setting_default_privacy: 게́‹œë¬¼ 프ë¼́´ë²„́‹œ setting_default_sensitive: 미디́–´ë¥¼ ́–¸́ œë‚˜ 민ê°í•œ ́½˜í…́¸ ë¡œ ́„¤́ • setting_delete_modal: 게́‹œë¬¼ ́‚­́ œ ́ „ 확́¸ ́°½́„ í‘œ́‹œ + setting_disable_hover_cards: 호버́‹œ 프로필 미리보기를 비활́„±í™” setting_disable_swiping: ́¤́™€́´í”„ 모́…˜ 비활́„±í™” setting_display_media: 미디́–´ í‘œ́‹œ setting_display_media_default: 기본 @@ -242,11 +243,13 @@ ko: warn: 경고́™€ 함께 ́ˆ¨ê¸°ê¸° form_admin_settings: activity_api_enabled: APÍ— ́œ ́ € 활ë™́— 대한 통계 발행 + app_icon: ́•± ́•„́´́½˜ backups_retention_period: ́‚¬́©́ ́•„́¹´́´ë¸Œ ́œ ́§€ 기한 bootstrap_timeline_accounts: ́ƒˆë¡œ́´ ́‚¬́©́들́—게 ́¶”́²œí•  계́ •ë“¤ closed_registrations_message: ê°€́…́´ ë¶ˆê°€ë¥ í•  ë•Œ́˜ ́‚¬́©́ ́§€́ • ë©”́‹œ́§€ content_cache_retention_period: ë¦¬ëª¨í¸ ́½˜í…́¸  ë³´́œ  기간 custom_css: ́‚¬́©́ ́ •́˜ CSS + favicon: 파비́½˜ mascot: ́‚¬́©́ ́ •́˜ 마́¤́½”í¸ (legacy) media_cache_retention_period: 미디́–´ ́º́‹œ ́œ ́§€ 기한 peers_api_enabled: APÍ— 발견 ëœ ́„œë²„들́˜ ëª©ë¡ ë°œí–‰ diff --git a/config/locales/simple_form.lt.yml b/config/locales/simple_form.lt.yml index feec37ae003676..b31803409b3976 100644 --- a/config/locales/simple_form.lt.yml +++ b/config/locales/simple_form.lt.yml @@ -137,6 +137,7 @@ lt: setting_default_privacy: Skelbimo privatumas setting_default_sensitive: Visada žymÄ—ti medijÄ… kaip jautriÄ… setting_delete_modal: Rodyti patvirtinimo dialogÄ… prieÅ¡ iÅ¡trinant įraÅ¡Ä… + setting_disable_hover_cards: IÅ¡jungti profilio peržiÅ«rÄ… užvedus setting_disable_swiping: IÅ¡jungti perbraukimo judÄ—jimus setting_display_media: Medijos rodymas setting_display_media_hide_all: SlÄ—pti viskÄ… @@ -164,9 +165,11 @@ lt: warn: SlÄ—pti su įspÄ—jimu form_admin_settings: activity_api_enabled: Skelbti suvestinį statistikÄ… apie naudotojų veiklÄ… per API + app_icon: ProgramÄ—lÄ—s piktograma bootstrap_timeline_accounts: Visada rekomenduoti Å¡ias paskyras naujiems naudotojams content_cache_retention_period: Nuotolinio turinio saugojimo laikotarpis custom_css: Pasirinktinis CSS + favicon: SvetainÄ—s piktograma mascot: Pasirinktinis talismanas (pasenÄ™s) registrations_mode: Kas gali užsiregistruoti require_invite_text: Reikalauti priežasties prisijungti diff --git a/config/locales/simple_form.nl.yml b/config/locales/simple_form.nl.yml index 2271d7037efa45..56331934064401 100644 --- a/config/locales/simple_form.nl.yml +++ b/config/locales/simple_form.nl.yml @@ -211,6 +211,7 @@ nl: setting_default_privacy: Zichtbaarheid van nieuwe berichten setting_default_sensitive: Media altijd als gevoelig markeren setting_delete_modal: Vraag voor het verwijderen van een bericht een bevestiging + setting_disable_hover_cards: Profielvoorbeelden door eroverheen te zweven uitschakelen setting_disable_swiping: Swipebewegingen uitschakelen setting_display_media: Mediaweergave setting_display_media_default: Standaard @@ -242,11 +243,13 @@ nl: warn: Met een waarschuwing verbergen form_admin_settings: activity_api_enabled: Statistieken over gebruikersactiviteit via de API publiceren + app_icon: App-pictogram backups_retention_period: Bewaartermijn gebruikersarchief bootstrap_timeline_accounts: Accounts die altijd aan nieuwe gebruikers worden aanbevolen closed_registrations_message: Aangepast bericht wanneer registratie is uitgeschakeld content_cache_retention_period: Bewaartermijn voor externe inhoud custom_css: Aangepaste CSS + favicon: Favicon mascot: Aangepaste mascotte (legacy) media_cache_retention_period: Bewaartermijn mediacache peers_api_enabled: Lijst van bekende servers via de API publiceren diff --git a/config/locales/simple_form.nn.yml b/config/locales/simple_form.nn.yml index a200e1206e38e1..c9075a89c210e3 100644 --- a/config/locales/simple_form.nn.yml +++ b/config/locales/simple_form.nn.yml @@ -211,6 +211,7 @@ nn: setting_default_privacy: Privatliv setting_default_sensitive: Merk alltid media som nærtakande setting_delete_modal: Vis stadfesting før du slettar eit tut + setting_disable_hover_cards: Skru av profilvising nĂ¥r peikaren er over setting_disable_swiping: Skru av sveipebevegelser setting_display_media: Medievisning setting_display_media_default: Standard @@ -242,11 +243,13 @@ nn: warn: Gøym med ei Ă¥tvaring form_admin_settings: activity_api_enabled: Legg ut samla statistikk om brukaraktiviteten i APIet + app_icon: App-ikon backups_retention_period: Arkiveringsperiode for brukararkiv bootstrap_timeline_accounts: TilrĂ¥ alltid desse kontoane for nye brukarar closed_registrations_message: Eigendefinert melding nĂ¥r registrering ikkje er mogleg content_cache_retention_period: Oppbevaringstid for eksternt innhald custom_css: Egendefinert CSS + favicon: Favorittikon mascot: Eigendefinert maskot (eldre funksjon) media_cache_retention_period: Oppbevaringsperiode for mediebuffer peers_api_enabled: Legg ut ei liste over oppdaga tenarar i APIet diff --git a/config/locales/simple_form.pl.yml b/config/locales/simple_form.pl.yml index 9d82384af9d4a9..39e1814195f877 100644 --- a/config/locales/simple_form.pl.yml +++ b/config/locales/simple_form.pl.yml @@ -211,6 +211,7 @@ pl: setting_default_privacy: Widoczność wpisĂ³w setting_default_sensitive: Zawsze oznaczaj zawartość multimedialnÄ… jako wrażliwÄ… setting_delete_modal: Pytaj o potwierdzenie przed usuniÄ™ciem wpisu + setting_disable_hover_cards: WyÅ‚Ä…cz podglÄ…d profilu po najechaniu setting_disable_swiping: WyÅ‚Ä…cz ruchy przesuwania setting_display_media: WyÅ›wietlanie zawartoÅ›ci multimedialnej setting_display_media_default: DomyÅ›lne @@ -242,11 +243,13 @@ pl: warn: Ukryj z ostrzeżeniem form_admin_settings: activity_api_enabled: Publikuj zagregowane statystyki dotyczÄ…ce aktywnoÅ›ci użytkownika w API + app_icon: Ikona aplikacji backups_retention_period: Okres przechowywania archiwum użytkownika bootstrap_timeline_accounts: Zawsze rekomenduj te konta nowym użytkownikom closed_registrations_message: Niestandardowa wiadomość, gdy rejestracje nie sÄ… dostÄ™pne content_cache_retention_period: Okres zachowywania zdalnych treÅ›ci custom_css: Niestandardowy CSS + favicon: Favicon mascot: WÅ‚asna ikona media_cache_retention_period: Okres przechowywania pamiÄ™ci podrÄ™cznej peers_api_enabled: Opublikuj listÄ™ odkrytych serwerĂ³w w API diff --git a/config/locales/simple_form.pt-PT.yml b/config/locales/simple_form.pt-PT.yml index 7fcbb210c5b145..ef7dfd00a80fa2 100644 --- a/config/locales/simple_form.pt-PT.yml +++ b/config/locales/simple_form.pt-PT.yml @@ -211,6 +211,7 @@ pt-PT: setting_default_privacy: Privacidade da publicaĂ§Ă£o setting_default_sensitive: Marcar sempre os media como problemĂ¡ticos setting_delete_modal: Solicitar confirmaĂ§Ă£o antes de eliminar uma publicaĂ§Ă£o + setting_disable_hover_cards: Desativar visualizaĂ§Ă£o de perfil ao passar o cursor setting_disable_swiping: Desativar os movimentos de deslize setting_display_media: VisualizaĂ§Ă£o de media setting_display_media_default: PrĂ©-definiĂ§Ă£o @@ -242,11 +243,13 @@ pt-PT: warn: Ocultar com um aviso form_admin_settings: activity_api_enabled: Publicar estatĂ­sticas agregadas sobre a atividade dos utilizadores na API + app_icon: Ăcone da aplicaĂ§Ă£o backups_retention_period: PerĂ­odo de retenĂ§Ă£o de arquivos de utilizador bootstrap_timeline_accounts: Recomendar sempre estas contas para novos utilizadores closed_registrations_message: Mensagem personalizada quando as inscrições nĂ£o estiverem disponĂ­veis content_cache_retention_period: PerĂ­odo de retenĂ§Ă£o de conteĂºdos remotos custom_css: CSS personalizado + favicon: Ăcone de favoritos mascot: Mascote personalizada (legado) media_cache_retention_period: PerĂ­odo de retenĂ§Ă£o de ficheiros de media em cache peers_api_enabled: Publicar lista de servidores descobertos na API diff --git a/config/locales/simple_form.ro.yml b/config/locales/simple_form.ro.yml index dfb44c77453e56..5df411b9512d3e 100644 --- a/config/locales/simple_form.ro.yml +++ b/config/locales/simple_form.ro.yml @@ -2,6 +2,12 @@ ro: simple_form: hints: + account: + discoverable: Este posibil ca postările È™i profilul tău să fie recomandate Ă®n diferite zone ale Mastodon, iar profilul tău ar poate fi sugerat altor utilizatori. + fields: Pagina ta principală, pronumele tale, vĂ¢rsta, sau orice Ă®È›i doreÈ™ti. + indexable: Postările tale publice pot apărea Ă®n rezultatele căutărilor pe Mastodon. Persoanele care au interacÈ›ionat cu postările tale vor putea să le caute oricĂ¢nd. + note: 'PoÈ›i @menÈ›iona alte persoane sau #hashtag-uri.' + unlocked: Alte persoane vă vor putea urmări fără a solicita aprobare. DebifaÈ›i dacă doriÈ›i să revizuiÈ›i cererile È™i să alegeÈ›i dacă doriÈ›i să acceptaÈ›i sau să respingeÈ›i noii urmăritori. account_alias: acct: SpecificaÈ›i numele de utilizator@domeniu al contului de la care doriÈ›i să treceÈ›i account_migration: @@ -23,12 +29,14 @@ ro: text: PoÈ›i folosi sintaxa de postare. Te rugăm să fii atent la spaÈ›iul pe care anunÈ›ul Ă®l va ocupa pe ecranul utilizatorului defaults: autofollow: Persoanele care se Ă®nregistrează datorită invitaÈ›iei tale te vor urmări automat + avatar: WEBP, PNG, GIF sau JPG. Cel mult %{size}. Va fi redimensionată la %{dimensions}px bot: Acest cont performează Ă®n cea mai mare parte acÈ›iuni automate È™i nu poate fi monitorizat context: Contextele Ă®n care filtrul trebuie aplicat current_password: Ăn scopuri de securitate, vă rugăm să introduceÅ£i parola contului curent current_username: Pentru a confirma, vă rugăm să introduceÅ£i numele de utilizator al contului curent digest: Este trimis doar după o lungă perioadă de inactivitate È™i numai dacă primeÈ™ti mesaje personale Ă®n perioada de absență email: Vei primi un e-mail de confirmare + header: WEBP, PNG, GIF sau JPG. Cel mult %{size}. Va fi redimensionată la %{dimensions}px inbox_url: Copiază adresa URL de pe prima pagină a reului pe care vrei să Ă®l utilizezi irreversible: Postările sortate vor dispărea ireversibil, chiar dacă filtrul este ulterior È™ters locale: Limba interfaÈ›ei de utilizator, e-mailurile si notificările push @@ -36,17 +44,27 @@ ro: phrase: Vor fi potrivite indiferent de textul din casetă sau advertismentul unei postări scopes: La care API-uri aplicaÈ›ia are nevoie de acces. Dacă selectezi un scop principal nu mai e nevoie să selectezi fiecare sub-scop al acestuia. setting_aggregate_reblogs: Nu afiÈ™a impulsurile noi pentru postările care au fost deja recent impulsionate (afectează doar noile impulsuri primite) + setting_always_send_emails: Ăn mod normal, notificările prin e-mail nu vor fi trimise cĂ¢nd utilizaÈ›i Ă®n mod activ Mastodon setting_default_sensitive: FiÈ™ierele media sensibile sunt ascunse implicit È™i pot fi dezvăluite cu un clic setting_display_media_default: Ascunde conÈ›inutul media marcat ca sensibil (NSFW) setting_display_media_hide_all: Ăntotdeauna ascunde tot conÈ›inutul media setting_display_media_show_all: Ăntotdeauna afiÈ™ează conÈ›inutul media marcat ca sensibil setting_use_blurhash: GradienÈ›ii sunt bazaÈ›i pe culorile vizualelor ascunse, dar ofuscă orice detalii setting_use_pending_items: Ascunde actualizările cronologice din spatele unui click Ă®n loc de a derula automat fluxul + username: PoÈ›i folosi litere, numere sau liniuÈ›e de subliniere whole_word: CĂ¢nd fraza sau cuvĂ¢ntul este doar alfanumeric, acesta se aplică doar dacă există o potrivire completă domain_allow: domain: Acest domeniu va putea prelua date de pe acest server È™i datele primite de la el vor fi procesate È™i stocate email_domain_block: + domain: Acesta poate fi numele de domeniu care apare Ă®n adresa de e-mail sau Ă®n Ă®nregistrarea MX pe care o utilizează. Acestea vor fi verificate la Ă®nscriere. with_dns_records: Se va face o Ă®ncercare de a rezolva Ă®nregistrările DNS ale domeniului dat È™i rezultatele vor fi de asemenea afiÈ™ate pe lista neagră + featured_tag: + name: 'Iată cĂ¢teva dintre hashtag-urile pe care le-ai folosit cel mai recent:' + filters: + action: Alege ce acÅ£iune va fi efectuată atunci cĂ¢nd o postare corespunde filtrului + actions: + hide: Ascunde complet conÈ›inutul filtrat, ca È™i cum nu ar exista + warn: Ascunde conÈ›inutul filtrat Ă®n spatele unui avertisment care menÈ›ionează titlul filtrului form_challenge: current_password: AÈ›i intrat Ă®ntr-o zonă securizată imports: diff --git a/config/locales/simple_form.sl.yml b/config/locales/simple_form.sl.yml index 96b36307a5795d..a937f17206e465 100644 --- a/config/locales/simple_form.sl.yml +++ b/config/locales/simple_form.sl.yml @@ -211,6 +211,7 @@ sl: setting_default_privacy: Zasebnost objave setting_default_sensitive: Vedno oznaÄi medije kot obÄutljive setting_delete_modal: Pred brisanjem objave prikaži okno za pritrditev + setting_disable_hover_cards: OnemogoÄi predogled profila pod kazalcem setting_disable_swiping: OnemogoÄi poteze drsanja setting_display_media: Prikaz medijev setting_display_media_default: Privzeto @@ -242,11 +243,13 @@ sl: warn: Skrij z opozorilom form_admin_settings: activity_api_enabled: Objavi združeno statistiko o dejavnosti uporabnikov v API-ju + app_icon: Ikona programa backups_retention_period: Obdobje hrambe arhivov uporabnikov bootstrap_timeline_accounts: Vedno priporoÄaj te raÄune novim uporabnikom closed_registrations_message: SporoÄilo po meri, ko registracije niso na voljo content_cache_retention_period: Obdobje hranjenja vsebine z ostalih strežnikov custom_css: CSS po meri + favicon: Ikona spletne strani mascot: Maskota po meri (opuÅ¡Äeno) media_cache_retention_period: Obdobje hrambe predpomnilnika predstavnosti peers_api_enabled: Objavi seznam odkritih strežnikov v API-ju diff --git a/config/locales/simple_form.sq.yml b/config/locales/simple_form.sq.yml index c3c3920962d635..4236d7dce2673b 100644 --- a/config/locales/simple_form.sq.yml +++ b/config/locales/simple_form.sq.yml @@ -211,6 +211,7 @@ sq: setting_default_privacy: PrivatĂ«si postimi setting_default_sensitive: Mediave vĂ«ru pĂ«rherĂ« shenjĂ« si rezervat setting_delete_modal: Shfaq dialog ripohimi pĂ«rpara fshirjes sĂ« njĂ« mesazhi + setting_disable_hover_cards: Çaktivizo paraparje profili, kur i kalohet kursori pĂ«rsipĂ«r setting_disable_swiping: Çaktivizo lĂ«vizje me fĂ«rkim setting_display_media: Shfaqje mediash setting_display_media_default: Parazgjedhje @@ -242,11 +243,13 @@ sq: warn: Fshihe me njĂ« sinjalizim form_admin_settings: activity_api_enabled: Publikoni te API statistika pĂ«rmbledhĂ«se rreth veprimtarisĂ« sĂ« pĂ«rdoruesve + app_icon: IkonĂ« aplikacioni backups_retention_period: PeriudhĂ« mbajtjeje arkivash pĂ«rdoruesish bootstrap_timeline_accounts: Rekomandoju pĂ«rherĂ« kĂ«to llogari pĂ«rdoruesve tĂ« rinj closed_registrations_message: Mesazh vetjak pĂ«r pamundĂ«si regjistrimesh tĂ« reja content_cache_retention_period: PeriudhĂ« mbajtjeje lĂ«nde tĂ« largĂ«t custom_css: CSS Vetjake + favicon: FavikonĂ« mascot: Simbol vetjak (e dikurshme) media_cache_retention_period: PeriudhĂ« mbajtjeje lĂ«nde media peers_api_enabled: Publiko te API listĂ« shĂ«rbyesish tĂ« zbuluar diff --git a/config/locales/simple_form.sr-Latn.yml b/config/locales/simple_form.sr-Latn.yml index 710f81e84fd1bd..40b710b078e690 100644 --- a/config/locales/simple_form.sr-Latn.yml +++ b/config/locales/simple_form.sr-Latn.yml @@ -211,6 +211,7 @@ sr-Latn: setting_default_privacy: Privatnost objava setting_default_sensitive: Uvek oznaÄi multimediju kao osetljivu setting_delete_modal: Prikaži dijalog za potvrdu pre brisanja objave + setting_disable_hover_cards: Onemoguc̀i pregled profila prelaskom kursora setting_disable_swiping: Onemogući pokrete prevlaÄenja setting_display_media: Prikaz medija setting_display_media_default: Podrazumevano @@ -242,11 +243,13 @@ sr-Latn: warn: Sakrij uz upozorenje form_admin_settings: activity_api_enabled: Objavi prikupljenu statistiku o korisniÄkoj aktivnosti u API + app_icon: Ikonica aplikacije backups_retention_period: Period Äuvanja korisniÄke arhive bootstrap_timeline_accounts: Uvek preporuÄi ove naloge novim korisnicima closed_registrations_message: PrilagoÄ‘ena poruka kada prijave nisu moguće content_cache_retention_period: Period zadržavanja udaljenog sadržaja custom_css: PrilagoÄ‘eni CSS + favicon: Favikon mascot: PrilagoÄ‘ena maskota (nasleÄ‘e) media_cache_retention_period: Period Äuvanja keÅ¡a medija peers_api_enabled: Objavite listu otkrivenih servera u API diff --git a/config/locales/simple_form.sr.yml b/config/locales/simple_form.sr.yml index c5fbc9185a517e..c0a9ac2d8963c6 100644 --- a/config/locales/simple_form.sr.yml +++ b/config/locales/simple_form.sr.yml @@ -211,6 +211,7 @@ sr: setting_default_privacy: ĐŸÑ€Đ¸Đ²Đ°Ñ‚Đ½Đ¾ÑÑ‚ Đ¾Đ±Ñ˜Đ°Đ²Đ° setting_default_sensitive: Đ£Đ²ĐµĐº Đ¾Đ·Đ½Đ°Ñ‡Đ¸ Đ¼ÑƒĐ»Ñ‚Đ¸Đ¼ĐµĐ´Đ¸Ñ˜Ñƒ ĐºĐ°Đ¾ Đ¾ÑĐµÑ‚Ñ™Đ¸Đ²Ñƒ setting_delete_modal: ĐŸÑ€Đ¸ĐºĐ°Đ¶Đ¸ Đ´Đ¸Ñ˜Đ°Đ»Đ¾Đ³ Đ·Đ° Đ¿Đ¾Ñ‚Đ²Ñ€Đ´Ñƒ Đ¿Ñ€Đµ Đ±Ñ€Đ¸ÑĐ°ÑĐ° Đ¾Đ±Ñ˜Đ°Đ²Đµ + setting_disable_hover_cards: ĐĐ½ĐµĐ¼Đ¾Đ³ÑƒÑ›Đ¸ Đ¿Ñ€ĐµĐ³Đ»ĐµĐ´ Đ¿Ñ€Đ¾Ñ„Đ¸Đ»Đ° Đ¿Ñ€ĐµĐ»Đ°ÑĐºĐ¾Đ¼ ĐºÑƒÑ€ÑĐ¾Ñ€Đ° setting_disable_swiping: ĐĐ½ĐµĐ¼Đ¾Đ³ÑƒÑ›Đ¸ Đ¿Đ¾ĐºÑ€ĐµÑ‚Đµ Đ¿Ñ€ĐµĐ²Đ»Đ°Ñ‡ĐµÑĐ° setting_display_media: ĐŸÑ€Đ¸ĐºĐ°Đ· Đ¼ĐµĐ´Đ¸Ñ˜Đ° setting_display_media_default: ĐŸĐ¾Đ´Ñ€Đ°Đ·ÑƒĐ¼ĐµĐ²Đ°Đ½Đ¾ @@ -242,11 +243,13 @@ sr: warn: Đ¡Đ°ĐºÑ€Đ¸Ñ˜ ÑƒĐ· ÑƒĐ¿Đ¾Đ·Đ¾Ñ€ĐµÑе form_admin_settings: activity_api_enabled: ĐĐ±Ñ˜Đ°Đ²Đ¸ Đ¿Ñ€Đ¸ĐºÑƒĐ¿Ñ™ĐµĐ½Ñƒ ÑÑ‚Đ°Ñ‚Đ¸ÑÑ‚Đ¸ĐºÑƒ Đ¾ ĐºĐ¾Ñ€Đ¸ÑĐ½Đ¸Ñ‡ĐºĐ¾Ñ˜ Đ°ĐºÑ‚Đ¸Đ²Đ½Đ¾ÑÑ‚Đ¸ у API + app_icon: Đ˜ĐºĐ¾Đ½Đ¸Ñ†Đ° Đ°Đ¿Đ»Đ¸ĐºĐ°Ñ†Đ¸Ñ˜Đµ backups_retention_period: ĐŸĐµÑ€Đ¸Đ¾Đ´ Ñ‡ÑƒĐ²Đ°ÑĐ° ĐºĐ¾Ñ€Đ¸ÑĐ½Đ¸Ñ‡ĐºĐµ Đ°Ñ€Ñ…Đ¸Đ²Đµ bootstrap_timeline_accounts: Đ£Đ²ĐµĐº Đ¿Ñ€ĐµĐ¿Đ¾Ñ€ÑƒÑ‡Đ¸ Đ¾Đ²Đµ Đ½Đ°Đ»Đ¾Đ³Đµ Đ½Đ¾Đ²Đ¸Đ¼ ĐºĐ¾Ñ€Đ¸ÑĐ½Đ¸Ñ†Đ¸Đ¼Đ° closed_registrations_message: ĐŸÑ€Đ¸Đ»Đ°Đ³Đ¾Ñ’ĐµĐ½Đ° Đ¿Đ¾Ñ€ÑƒĐºĐ° ĐºĐ°Đ´Đ° Đ¿Ñ€Đ¸Ñ˜Đ°Đ²Đµ Đ½Đ¸Ñу Đ¼Đ¾Đ³ÑƒÑ›Đµ content_cache_retention_period: ĐŸĐµÑ€Đ¸Đ¾Đ´ Đ·Đ°Đ´Ñ€Đ¶Đ°Đ²Đ°ÑĐ° ÑƒĐ´Đ°Ñ™ĐµĐ½Đ¾Đ³ ÑĐ°Đ´Ñ€Đ¶Đ°Ñ˜Đ° custom_css: ĐŸÑ€Đ¸Đ»Đ°Đ³Đ¾Ñ’ĐµĐ½Đ¸ CSS + favicon: Đ¤Đ°Đ²Đ¸ĐºĐ¾Đ½ mascot: ĐŸÑ€Đ¸Đ»Đ°Đ³Đ¾Ñ’ĐµĐ½Đ° Đ¼Đ°ÑĐºĐ¾Ñ‚Đ° (Đ½Đ°ÑĐ»ĐµÑ’Đµ) media_cache_retention_period: ĐŸĐµÑ€Đ¸Đ¾Đ´ Ñ‡ÑƒĐ²Đ°ÑĐ° ĐºĐµÑˆĐ° Đ¼ĐµĐ´Đ¸Ñ˜Đ° peers_api_enabled: ĐĐ±Ñ˜Đ°Đ²Đ¸Ñ‚Đµ лиÑту Đ¾Ñ‚ĐºÑ€Đ¸Đ²ĐµĐ½Đ¸Ñ… ÑĐµÑ€Đ²ĐµÑ€Đ° у API diff --git a/config/locales/simple_form.sv.yml b/config/locales/simple_form.sv.yml index 11d142a2bd6d73..2281e4b4abe109 100644 --- a/config/locales/simple_form.sv.yml +++ b/config/locales/simple_form.sv.yml @@ -242,11 +242,13 @@ sv: warn: Dölj med en varning form_admin_settings: activity_api_enabled: Publicera aggregerad statistik om användaraktivitet i API:et + app_icon: Appikon backups_retention_period: Lagringsperiod för användararkivet bootstrap_timeline_accounts: Rekommendera alltid dessa konton till nya användare closed_registrations_message: Anpassat meddelande när nyregistreringar inte är tillgängliga content_cache_retention_period: Förvaringsperiod för fjärrinnehĂ¥ll custom_css: Anpassad CSS + favicon: Favicon mascot: Anpassad maskot (tekniskt arv) media_cache_retention_period: Tid för bibehĂ¥llande av mediecache peers_api_enabled: Publicera lista över upptäckta servrar i API:et diff --git a/config/locales/simple_form.th.yml b/config/locales/simple_form.th.yml index 0d9a88bc380ff7..cdc82367f9346c 100644 --- a/config/locales/simple_form.th.yml +++ b/config/locales/simple_form.th.yml @@ -211,6 +211,7 @@ th: setting_default_privacy: ความเป็นส่วนตัวของà¸à¸²à¸£à¹‚à¸à¸ªà¸•à¹Œ setting_default_sensitive: ทำเครื่องหมายสื่อว่าละเอียดอ่อนเสมอ setting_delete_modal: à¹à¸ªà¸”งà¸à¸¥à¹ˆà¸­à¸‡à¹‚ต้ตอà¸à¸à¸²à¸£à¸¢à¸·à¸™à¸¢à¸±à¸™à¸à¹ˆà¸­à¸™à¸¥à¸à¹‚à¸à¸ªà¸•à¹Œ + setting_disable_hover_cards: ปิดใà¸à¹‰à¸‡à¸²à¸™à¸•à¸±à¸§à¸­à¸¢à¹ˆà¸²à¸‡à¹‚ปรไฟล์เมื่อวางเมาส์เหนือ setting_disable_swiping: ปิดใà¸à¹‰à¸‡à¸²à¸™à¸à¸²à¸£à¹€à¸„ลื่อนไหวในà¸à¸²à¸£à¸›à¸±à¸” setting_display_media: à¸à¸²à¸£à¹à¸ªà¸”งสื่อ setting_display_media_default: ค่าเริ่มต้น diff --git a/config/locales/simple_form.tr.yml b/config/locales/simple_form.tr.yml index 697417a5415956..f098bfd3ca6d32 100644 --- a/config/locales/simple_form.tr.yml +++ b/config/locales/simple_form.tr.yml @@ -211,6 +211,7 @@ tr: setting_default_privacy: Gönderi gizliliÄŸi setting_default_sensitive: Medyayı her zaman hassas olarak iÅŸaretle setting_delete_modal: Bir gönderiyi silmeden önce onay iletiÅŸim kutusu göster + setting_disable_hover_cards: ĂœstĂ¼ne geldiÄŸinde profil önizlemesini devre dışı bırak setting_disable_swiping: Kaydırma hareketlerini devre dışı bırak setting_display_media: Medya görĂ¼ntĂ¼leme setting_display_media_default: Varsayılan @@ -242,11 +243,13 @@ tr: warn: Uyarıyla gizle form_admin_settings: activity_api_enabled: API'deki kullanıcı etkinliÄŸi hakkında toplu istatistikler yayınlayın + app_icon: Uygulama simgesi backups_retention_period: Kullanıcı arÅŸivi saklama sĂ¼resi bootstrap_timeline_accounts: Bu hesapları yeni kullanıcılara her zaman öner closed_registrations_message: Kayıt olma mevcut deÄŸilken gösterilen özel ileti content_cache_retention_period: Uzak içerik saklama sĂ¼resi custom_css: Ă–zel CSS + favicon: Yer imi simgesi mascot: Ă–zel maskot (eski) media_cache_retention_period: Medya önbelleÄŸi saklama sĂ¼resi peers_api_enabled: API'de keÅŸfedilen sunucuların listesini yayınla diff --git a/config/locales/simple_form.uk.yml b/config/locales/simple_form.uk.yml index 11337f2f61f689..2f494534ea63b9 100644 --- a/config/locales/simple_form.uk.yml +++ b/config/locales/simple_form.uk.yml @@ -211,6 +211,7 @@ uk: setting_default_privacy: Đ’Đ¸Đ´Đ¸Đ¼Ñ–ÑÑ‚ÑŒ Đ´Đ¾Đ¿Đ¸ÑÑ–Đ² setting_default_sensitive: ĐŸĐ¾Đ·Đ½Đ°Ñ‡Đ°Ñ‚Đ¸ Đ¼ĐµĐ´Ñ–Đ° Đ´ĐµĐ»Ñ–ĐºĐ°Ñ‚Đ½Đ¸Đ¼Đ¸ setting_delete_modal: ĐŸĐ¾ĐºĐ°Đ·ÑƒĐ²Đ°Ñ‚Đ¸ Đ´Ñ–Đ°Đ»Đ¾Đ³ Đ¿Ñ–Đ´Ñ‚Đ²ĐµÑ€Đ´Đ¶ĐµĐ½Đ½Ñ Đ¿Ñ–Đ´ Ñ‡Đ°Ñ Đ²Đ¸Đ´Đ°Đ»ĐµĐ½Đ½Ñ Đ´Đ¾Đ¿Đ¸Ñу + setting_disable_hover_cards: Đ’Đ¸Đ¼ĐºĐ½ÑƒÑ‚Đ¸ Đ¿Đ¾Đ¿ĐµÑ€ĐµĐ´Đ½Ñ–Đ¹ Đ¿ĐµÑ€ĐµĐ³Đ»ÑĐ´ Đ¿Ñ€Đ¾Ñ„Ñ–Đ»Ñ Đ¿Ñ€Đ¸ Đ½Đ°Đ²ĐµĐ´ĐµĐ½Đ½Ñ– setting_disable_swiping: Đ’Đ¸Đ¼ĐºĐ½ÑƒÑ‚Đ¸ рух Đ¿Đ¾ÑÑƒĐ²Đ°Đ½Đ½Ñ setting_display_media: ĐŸĐ¾ĐºĐ°Đ· Đ¼ĐµĐ´Ñ–Đ° setting_display_media_default: Đ—Đ° Đ¿Ñ€Đ¾Đ¼Đ¾Đ²Ñ‡Đ°Đ½Đ½ÑĐ¼ @@ -242,11 +243,13 @@ uk: warn: Đ¡Ñ…Đ¾Đ²Đ°Ñ‚Đ¸ Đ·Đ° Đ¿Đ¾Đ¿ĐµÑ€ĐµĐ´Đ¶ĐµĐ½Đ½ÑĐ¼ form_admin_settings: activity_api_enabled: ĐŸÑƒĐ±Đ»Ñ–ĐºĐ°Ñ†Ñ–Ñ Đ°Đ³Ñ€ĐµĐ³Đ¾Đ²Đ°Đ½Đ¾Ñ— ÑÑ‚Đ°Ñ‚Đ¸ÑÑ‚Đ¸ĐºĐ¸ Đ¿Ñ€Đ¾ Đ°ĐºÑ‚Đ¸Đ²Đ½Ñ–ÑÑ‚ÑŒ ĐºĐ¾Ñ€Đ¸ÑÑ‚ÑƒĐ²Đ°Ñ‡Ñ–Đ² + app_icon: Đ—Đ½Đ°Ñ‡Đ¾Đº Đ·Đ°ÑÑ‚Đ¾ÑÑƒĐ½ĐºÑƒ backups_retention_period: ĐŸĐµÑ€Ñ–Đ¾Đ´ ÑƒÑ‚Ñ€Đ¸Đ¼Đ°Đ½Đ½Ñ Đ°Ñ€Ñ…Ñ–Đ²Ñƒ ĐºĐ¾Ñ€Đ¸ÑÑ‚ÑƒĐ²Đ°Ñ‡Đ° bootstrap_timeline_accounts: Đ—Đ°Đ²Đ¶Đ´Đ¸ Ñ€ĐµĐºĐ¾Đ¼ĐµĐ½Đ´ÑƒĐ²Đ°Ñ‚Đ¸ Đ½Đ¾Đ²Đ¸Đ¼ ĐºĐ¾Ñ€Đ¸ÑÑ‚ÑƒĐ²Đ°Ñ‡Đ°Đ¼ ці Đ¾Đ±Đ»Ñ–ĐºĐ¾Đ²Ñ– Đ·Đ°Đ¿Đ¸Ñи closed_registrations_message: ĐŸĐ¾ĐºĐ°Đ·ÑƒĐ²Đ°Đ½Đµ Đ¿Đ¾Đ²Ñ–Đ´Đ¾Đ¼Đ»ĐµĐ½Đ½Ñ, ÑĐºÑ‰Đ¾ Ñ€ĐµÑ”ÑÑ‚Ñ€Đ°Ñ†Ñ–Ñ Đ½ĐµĐ´Đ¾ÑÑ‚ÑƒĐ¿Đ½Đ° content_cache_retention_period: ĐŸĐµÑ€Ñ–Đ¾Đ´ Đ·Đ±ĐµÑ€ĐµĐ¶ĐµĐ½Đ½Ñ Đ²Ñ–Đ´Đ´Đ°Đ»ĐµĐ½Đ¾Đ³Đ¾ Đ²Đ¼Ñ–Ñту custom_css: ĐĐ¾Ñ€Đ¸ÑÑ‚ÑƒĐ²Đ°Ñ†ÑŒĐºĐ¸Đ¹ CSS + favicon: Đ—Đ½Đ°Ñ‡Đ¾Đº ÑĐ°Đ¹Ñ‚Ñƒ mascot: ĐĐ¾Ñ€Đ¸ÑÑ‚ÑƒĐ²Đ°Ñ†ÑŒĐºĐ¸Đ¹ ÑĐ¸Đ¼Đ²Đ¾Đ» (Đ·Đ°ÑÑ‚Đ°Ñ€Ñ–Đ»Đ¸Đ¹) media_cache_retention_period: ĐŸĐµÑ€Ñ–Đ¾Đ´ Đ·Đ±ĐµÑ€ĐµĐ¶ĐµĐ½Đ½Ñ ĐºĐµÑˆÑƒ Đ¼ĐµĐ´Ñ–Đ° peers_api_enabled: ĐĐ¿ÑƒĐ±Đ»Ñ–ĐºÑƒĐ²Đ°Ñ‚Đ¸ ÑĐ¿Đ¸ÑĐ¾Đº Đ·Đ½Đ°Đ¹Đ´ĐµĐ½Đ¸Ñ… ÑĐµÑ€Đ²ĐµÑ€Ñ–Đ² у API diff --git a/config/locales/simple_form.vi.yml b/config/locales/simple_form.vi.yml index e5063e611225de..c45da4713718ca 100644 --- a/config/locales/simple_form.vi.yml +++ b/config/locales/simple_form.vi.yml @@ -211,6 +211,7 @@ vi: setting_default_privacy: Kiểu đăng setting_default_sensitive: ÄĂ¡nh dấu media nhạy cảm setting_delete_modal: Há»i trÆ°á»›c khi xĂ³a tĂºt + setting_disable_hover_cards: Tắt thẻ xem trÆ°á»›c hồ sÆ¡ setting_disable_swiping: KhĂ´ng dĂ¹ng chuyển Ä‘á»™ng vuốt setting_display_media: Media nhạy cảm setting_display_media_default: Mặc định @@ -242,11 +243,13 @@ vi: warn: Ẩn kèm theo cảnh bĂ¡o form_admin_settings: activity_api_enabled: CĂ´ng khai số liệu thống kĂª tổng hợp vá» hoạt Ä‘á»™ng của ngÆ°á»i dĂ¹ng trong API + app_icon: Biểu tượng ứng dụng backups_retention_period: Thá»i hạn lÆ°u trữ ná»™i dung ngÆ°á»i dĂ¹ng sao lÆ°u bootstrap_timeline_accounts: LuĂ´n Ä‘á» xuất những ngÆ°á»i nĂ y đến ngÆ°á»i má»›i closed_registrations_message: ThĂ´ng bĂ¡o tĂ¹y chỉnh khi tắt đăng kĂ½ content_cache_retention_period: Khoảng thá»i gian lÆ°u giữ ná»™i dung mĂ¡y chủ khĂ¡c custom_css: TĂ¹y chỉnh CSS + favicon: Favicon mascot: TĂ¹y chỉnh linh vật (kế thừa) media_cache_retention_period: Thá»i hạn lÆ°u trữ cache media peers_api_enabled: CĂ´ng khai danh sĂ¡ch cĂ¡c mĂ¡y chủ được phĂ¡t hiện trong API diff --git a/config/locales/simple_form.zh-CN.yml b/config/locales/simple_form.zh-CN.yml index 6058cc00cff3ac..ab440e04f43c7f 100644 --- a/config/locales/simple_form.zh-CN.yml +++ b/config/locales/simple_form.zh-CN.yml @@ -211,6 +211,7 @@ zh-CN: setting_default_privacy: 嘟文默认å¯è§èŒƒå›´ setting_default_sensitive: 始终标记媒体为æ•æ„Ÿå†…容 setting_delete_modal: 在删除嘟文å‰è¯¢é—®æˆ‘ + setting_disable_hover_cards: ç¦ç”¨æ‚¬åœèµ„料预览 setting_disable_swiping: ç¦ç”¨æ»‘å¨å¨ä½œ setting_display_media: 媒体显示 setting_display_media_default: 默认 @@ -242,11 +243,13 @@ zh-CN: warn: éè—时显示警å‘ä¿¡æ¯ form_admin_settings: activity_api_enabled: 在 API 中å‘布有关用户活å¨ç„æ±‡æ€»ç»Ÿè®¡æ•°æ® + app_icon: 应用图标 backups_retention_period: 用户存档ä¿ç•™æœŸ bootstrap_timeline_accounts: æ¨èæ–°ç”¨æˆ·å…³æ³¨ä»¥ä¸‹è´¦å· closed_registrations_message: 在关闭注册时显示ç„自å®ä¹‰æ¶ˆæ¯ content_cache_retention_period: 外站内容ä¿ç•™æœŸ custom_css: 自å®ä¹‰ CSS + favicon: Favicon mascot: 自å®ä¹‰å‰ç¥¥ç‰©ï¼ˆæ—§ï¼‰ media_cache_retention_period: 媒体缓存ä¿ç•™æœŸ peers_api_enabled: 在API中公开ç„已知å®ä¾‹ç„æœå¡å™¨ç„列表 diff --git a/config/locales/simple_form.zh-TW.yml b/config/locales/simple_form.zh-TW.yml index b7a67c6a6fb8a9..15ccaf8a17782d 100644 --- a/config/locales/simple_form.zh-TW.yml +++ b/config/locales/simple_form.zh-TW.yml @@ -24,7 +24,7 @@ zh-TW: type_html: 設å®è¦ä½¿ç”¨ %{acct} åç„事 types: disable: ç¦æ­¢è©²ä½¿ç”¨è€…使用他們ç„帳號,但是ä¸åˆªé™¤æˆ–é±è—他們ç„å…§å®¹ă€‚ - none: 使用這個寄é€è­¦å‘給該使用者,而ä¸é€²è¡Œå…¶ä»–å‹•ä½œă€‚ + none: 使用這個寄é€è­¦å‘至該使用者,而ä¸é€²è¡Œå…¶ä»–å‹•ä½œă€‚ sensitive: 強制標記此使用者所有å¤åª’體附å æª”案為æ•æ„Ÿå…§å®¹ă€‚ silence: ç¦æ­¢è©²ä½¿ç”¨è€…發公開嘟文,å¾ç„¡è·Ÿé¨ä»–們ç„帳號中é±è—嘟文與é€çŸ¥ă€‚關閉所有å°æ­¤å¸³è™Ÿä¹‹æª¢èˆ‰å ±å‘。 suspend: ç¦æ­¢æ‰€æœ‰å°è©²å¸³è™Ÿä»»ä½•äº’å‹•ï¼Œä¸¦ä¸”åˆªé™¤å…¶å…§å®¹ă€‚ä¸‰å天內å¯ä»¥æ’¤é·æ­¤å‹•ä½œă€‚關閉所有å°æ­¤å¸³è™Ÿä¹‹æª¢èˆ‰å ±å‘。 @@ -34,7 +34,7 @@ zh-TW: ends_at: å¯é¸ç„ă€‚å…¬å‘會於該時間é»è‡ªå‹•å–消發布 scheduled_at: 空白則立å³ç™¼å¸ƒå…¬å‘ starts_at: å¯é¸ç„ă€‚ä½¿å…¬å‘於特å®æ™‚間範åœå…§é¡¯ç¤º - text: 您å¯ä»¥ä½¿ç”¨å˜Ÿæ–‡èªæ³•ï¼Œä½†è«‹å°å¿ƒåˆ¥è®“å…¬å‘太鴨霸而佔æ“使用者ç„整個版é¢ă€‚ + text: 您å¯ä»¥ä½¿ç”¨å˜Ÿæ–‡èªæ³•ï¼Œä½†è«‹å°å¿ƒåˆ¥ä½¿å…¬å‘太鴨霸而佔æ“使用者ç„整個版é¢ă€‚ appeal: text: 您åªèƒ½å°è­¦ç¤ºæ出一次申訴 defaults: @@ -47,7 +47,7 @@ zh-TW: digest: 僅於您長時間未登入且於未登入期間收到ç§è¨æ™‚å‚³é€ email: 您將收到一å°ç¢ºèªé›»å­éƒµä»¶ header: æ”¯æ´ WEBPă€PNGă€GIF 或 JPG 圖片格å¼ï¼Œæª”案最大為 %{size}ă€‚å°‡ç­‰æ¯”ä¾‹ç¸®æ¸›è‡³ %{dimensions} åƒç´  - inbox_url: å¾æ‚¨æƒ³è¦ä½¿ç”¨ç„中繼首é è¤‡è£½ç¶²å€ + inbox_url: 自您想è¦ä½¿ç”¨ç„中繼首é è¤‡è£½ç¶²å€ irreversible: å·²é濾ç„嘟文將會ä¸å¯é€†åœ°æ¶ˆå¤±ï¼Œå³ä¾¿ä¹‹å¾Œç§»é™¤é濾器也一樣 locale: 使用者介é¢ă€é›»å­éƒµä»¶èˆ‡æ¨æ’­é€çŸ¥ç„èªè¨€ password: 使用至少 8 個字元 @@ -92,7 +92,7 @@ zh-TW: site_contact_email: 其他人如何è¯ç¹«æ‚¨é—œæ–¼æ³•å¾‹æˆ–支æ´ä¹‹è«®è©¢ă€‚ site_contact_username: 其他人如何於 Mastodon ä¸è¯ç¹«æ‚¨ă€‚ site_extended_description: 任何其他å¯èƒ½å°è¨ªå®¢æˆ–使用者有用ç„é¡å¤–資è¨ă€‚å¯ç”± Markdown èªæ³•æ’°å¯«ă€‚ - site_short_description: 一段有å©æ–¼è¾¨åˆ¥æ‚¨ä¼ºæœå™¨ç„簡短說æ˜ă€‚例如ï¼èª°é‹è¡Œè©²ä¼ºæœå™¨ă€è©²ä¼ºæœå™¨æ˜¯æ供給哪些人群? + site_short_description: 一段有å©æ–¼è¾¨åˆ¥æ‚¨ä¼ºæœå™¨ç„簡短說æ˜ă€‚例如ï¼èª°é‹è¡Œè©²ä¼ºæœå™¨ă€è©²ä¼ºæœå™¨æ˜¯æ供至哪些人群? site_terms: 使用您自己ç„é±ç§æ¬æ”¿ç­–,或者ä¿ç•™ç©ºç™½ä»¥ä½¿ç”¨é è¨­å€¼ă€‚å¯ç”± Markdown èªæ³•æ’°å¯«ă€‚ site_title: 除了網域外,其他人該如何指稱您ç„伺æœå™¨ă€‚ status_page_url: 當æœå‹™ä¸­æ–·æ™‚,å¯ä»¥æ供使用者了解伺æœå™¨è³‡è¨é é¢ä¹‹ URL @@ -101,11 +101,11 @@ zh-TW: timeline_preview: 未登入之訪客能夠ç€è¦½æ­¤ä¼ºæœå™¨ä¸æœ€æ–°ç„å…¬é–‹å˜Ÿæ–‡ă€‚ trendable_by_default: è·³éæ‰‹å‹•å¯©æ ¸ç†±é–€å…§å®¹ă€‚ä»èƒ½æ–¼ç™»ä¸ç†±é–€è¶¨å‹¢å¾Œç§»é™¤å€‹åˆ¥å…§å®¹ă€‚ trends: 熱門趨勢將顯示於您伺æœå™¨ä¸æ­£åœ¨å¸å¼•å¤§é‡æ³¨æ„å›ç„嘟文ă€ä¸»é¡Œæ¨™ç±¤ă€æˆ–者新è。 - trends_as_landing_page: 顯示熱門趨勢內容給未登入使用者å訪客而ä¸æ˜¯é—œæ–¼æ­¤ä¼ºæœå™¨ä¹‹æè¿°ă€‚éœ€è¦å•Ÿç”¨ç†±é–€è¶¨å‹¢ă€‚ + trends_as_landing_page: 顯示熱門趨勢內容至未登入使用者å訪客而ä¸æ˜¯é—œæ–¼æ­¤ä¼ºæœå™¨ä¹‹æè¿°ă€‚éœ€è¦å•Ÿç”¨ç†±é–€è¶¨å‹¢ă€‚ form_challenge: current_password: 您正è¦é€²å…¥å®‰å…¨å€åŸŸ imports: - data: å¾å…¶ä»– Mastodon 伺æœå™¨åŒ¯å‡ºç„ CSV 檔案 + data: 自其他 Mastodon 伺æœå™¨åŒ¯å‡ºç„ CSV 檔案 invite_request: text: 這會å”å©æˆ‘們審核您ç„申請 ip_block: @@ -133,7 +133,7 @@ zh-TW: role: 角色æ§åˆ¶ä½¿ç”¨è€…有哪些æ¬é™ user_role: color: 於整個使用者介é¢ä¸­ç”¨æ–¼è§’色ç„é¡è‰²ï¼Œå六進ä½æ ¼å¼ç„ RGB - highlighted: 這會使角色公開å¯è¦‹ + highlighted: 這將使角色公開å¯è¦‹ name: 角色ç„公開å稱,如æœè§’色設å®ç‚ºé¡¯ç¤ºç‚ºå¾½ç«  permissions_as_keys: 有此角色ç„使用者將有æ¬å­˜å–... position: æŸäº›æƒ…æ³ä¸‹ï¼Œè¡çªç„解決方å¼ç”±æ›´é«˜éç„角色決å®ă€‚æŸäº›å‹•ä½œåªèƒ½ç”±å„ªå…ˆç¨‹åº¦è¼ƒä½ç„角色執行 @@ -211,6 +211,7 @@ zh-TW: setting_default_privacy: 嘟文é±ç§è¨­å® setting_default_sensitive: 總是將媒體標記為æ•æ„Ÿå…§å®¹ setting_delete_modal: 刪除嘟文å‰å…ˆè©¢å•æˆ‘ + setting_disable_hover_cards: åœç”¨æ–¼æ»‘鼠懸åœæ™‚é è¦½å€‹äººæª”案 setting_disable_swiping: åœç”¨æ»‘動手勢 setting_display_media: 媒體顯示 setting_display_media_default: é è¨­ @@ -242,11 +243,13 @@ zh-TW: warn: é±è—於警å‘之後 form_admin_settings: activity_api_enabled: æ–¼ API 中公開使用者活èºåº¦ç„çµ±è¨ˆæ•¸æ“ + app_icon: 應用程å¼åœ–示 backups_retention_period: 使用者å°å­˜è³‡æ–™ä¿ç•™æœŸé–“ - bootstrap_timeline_accounts: æ°¸é æ¨è–¦é€™äº›å¸³è™Ÿçµ¦æ–°ä½¿ç”¨è€… + bootstrap_timeline_accounts: æ°¸é æ¨è–¦é€™äº›å¸³è™Ÿè‡³æ–°ä½¿ç”¨è€… closed_registrations_message: 當註å†é—œé–‰æ™‚ç„客製化è¨æ¯ content_cache_retention_period: é ç«¯å…§å®¹ä¿ç•™æœŸé™ custom_css: 自訂 CSS + favicon: 網站圖示 (Favicon) mascot: 自訂å‰ç¥¥ç‰© (legacy) media_cache_retention_period: å¤åª’體快å–資料ä¿ç•™æœŸé–“ peers_api_enabled: æ–¼ API 中公開已知伺æœå™¨ç„列表 diff --git a/config/locales/sl.yml b/config/locales/sl.yml index 6087b1a1749642..f63aadd6c8f794 100644 --- a/config/locales/sl.yml +++ b/config/locales/sl.yml @@ -232,6 +232,7 @@ sl: update_custom_emoji: Posodobi emotikon po meri update_domain_block: Posodobi blokado domene update_ip_block: Posodobi pravilo IP + update_report: Posodobi poroÄilo update_status: Posodobi objavo update_user_role: Posodobi vlogo actions: @@ -662,6 +663,7 @@ sl: report: 'Prijavi #%{id}' reported_account: Prijavljeni raÄun reported_by: Prijavil/a + reported_with_application: Prijavljeno s programom resolved: RazreÅ¡eni resolved_msg: Prijava je uspeÅ¡no razreÅ¡ena! skip_to_actions: PreskoÄi na dejanja diff --git a/config/locales/sq.yml b/config/locales/sq.yml index 5439f08a04a8b2..c4bed80cc7cf47 100644 --- a/config/locales/sq.yml +++ b/config/locales/sq.yml @@ -226,6 +226,7 @@ sq: update_custom_emoji: PĂ«rditĂ«so Emoxhi Vetjake update_domain_block: PĂ«rditĂ«so Bllok PĂ«rkatĂ«sish update_ip_block: PĂ«rditĂ«soni rregull IP + update_report: PĂ«rditĂ«soni Raportimin update_status: PĂ«rditĂ«so Gjendjen update_user_role: PĂ«rditĂ«soni Rol actions: diff --git a/config/locales/sv.yml b/config/locales/sv.yml index 91b1720b553f2c..de2664f8b5f109 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -226,6 +226,7 @@ sv: update_custom_emoji: Uppdatera egna emojis update_domain_block: Uppdatera blockerad domän update_ip_block: Uppdatera IP-regel + update_report: Uppdatera rapport update_status: Uppdatera inlägg update_user_role: Uppdatera roll actions: diff --git a/config/locales/tr.yml b/config/locales/tr.yml index c690d22580cc20..9855b569241153 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -226,6 +226,7 @@ tr: update_custom_emoji: Ă–zel Ä°fadeyi GĂ¼ncelle update_domain_block: Engellenen Alan Adını GĂ¼ncelle update_ip_block: IP kuralını gĂ¼ncelle + update_report: Raporu GĂ¼ncelle update_status: Durumu GĂ¼ncelle update_user_role: RolĂ¼ GĂ¼ncelle actions: @@ -638,6 +639,7 @@ tr: report: 'Åikayet #%{id}' reported_account: Åikayet edilen hesap reported_by: Åikayet eden + reported_with_application: Uygulamayla bildirildi resolved: Giderildi resolved_msg: Åikayet baÅŸarıyla çözĂ¼mlendi! skip_to_actions: Ä°ÅŸlemlere atla diff --git a/config/locales/uk.yml b/config/locales/uk.yml index 9994cd9d0dadc8..69f5ca665c6362 100644 --- a/config/locales/uk.yml +++ b/config/locales/uk.yml @@ -232,6 +232,7 @@ uk: update_custom_emoji: ĐĐ½Đ¾Đ²Đ¸Ñ‚Đ¸ ĐºĐ¾Ñ€Đ¸ÑÑ‚ÑƒĐ²Đ°Ñ†ÑŒĐºÑ– ĐµĐ¼Đ¾Đ´Đ·Ñ– update_domain_block: ĐĐ½Đ¾Đ²Đ¸Ñ‚Đ¸ Đ±Đ»Đ¾ĐºÑƒĐ²Đ°Đ½Đ½Ñ Đ´Đ¾Đ¼ĐµĐ½Ñƒ update_ip_block: ĐĐ½Đ¾Đ²Đ¸Ñ‚Đ¸ Đ¿Ñ€Đ°Đ²Đ¸Đ»Đ¾ IP + update_report: ĐĐ½Đ¾Đ²Đ¸Ñ‚Đ¸ Đ·Đ²Ñ–Ñ‚ update_status: ĐĐ½Đ¾Đ²Đ¸Ñ‚Đ¸ Đ´Đ¾Đ¿Đ¸Ñ update_user_role: ĐĐ½Đ¾Đ²Đ¸Ñ‚Đ¸ Ñ€Đ¾Đ»ÑŒ actions: diff --git a/config/locales/vi.yml b/config/locales/vi.yml index 467356d65adfab..48e026d377ff87 100644 --- a/config/locales/vi.yml +++ b/config/locales/vi.yml @@ -223,6 +223,7 @@ vi: update_custom_emoji: Cập nhật emoji update_domain_block: Cập nhật mĂ¡y chủ chặn update_ip_block: Cập nhật chặn IP + update_report: Cập nhật bĂ¡o cĂ¡o update_status: Cập nhật tĂºt update_user_role: Cập nhật vai trĂ² actions: @@ -626,6 +627,7 @@ vi: report: 'BĂ¡o cĂ¡o #%{id}' reported_account: TĂ i khoản bị bĂ¡o cĂ¡o reported_by: BĂ¡o cĂ¡o bởi + reported_with_application: BĂ¡o cĂ¡o bằng ứng dụng resolved: ÄĂ£ xong resolved_msg: ÄĂ£ xá»­ lĂ½ bĂ¡o cĂ¡o xong! skip_to_actions: Kiểm duyệt diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index 794b8344c10783..d2d64152fa7bcc 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -223,6 +223,7 @@ zh-CN: update_custom_emoji: 更新自å®ä¹‰è¡¨æƒ…ç¬¦å· update_domain_block: 更新域åå±è”½ update_ip_block: 编辑 IP å°ç¦è§„则 + update_report: æ›´æ–°ä¸¾æ¥ update_status: 更新嘟文 update_user_role: 更新角色 actions: @@ -626,6 +627,7 @@ zh-CN: report: 'ä¸¾æ¥ #%{id}' reported_account: 举æ¥ç”¨æˆ· reported_by: 举æ¥äºº + reported_with_application: 举æ¥äººä½¿ç”¨ç„应用 resolved: å·²å¤„ç† resolved_msg: 举æ¥å¤„ç†æˆåŸï¼ skip_to_actions: 跳转到æ“作 diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index 1317d5f70740a5..375c79048a4d71 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -223,11 +223,12 @@ zh-TW: update_custom_emoji: 更新自訂 emoji 表情符號 update_domain_block: 更新網域å°é– update_ip_block: æ›´æ–° IP è¦å‰‡ + update_report: æ›´æ–°æª¢èˆ‰å ±å‘ update_status: 更新狀態 update_user_role: 更新角色 actions: approve_appeal_html: "%{name} 已批准來自 %{target} ç„審核決å®ç”³è¨´" - approve_user_html: "%{name} å·²æ‰¹å‡†å¾ %{target} 而來ç„註å†" + approve_user_html: "%{name} 已批准自 %{target} 而來ç„註å†" assigned_to_self_report_html: "%{name} å°‡å ±å‘ %{target} 指派給自己" change_email_user_html: "%{name} å·²è®æ›´ä½¿ç”¨è€… %{target} ç„é›»å­éƒµä»¶åœ°å€" change_role_user_html: "%{name} å·²è®æ›´ %{target} ç„角色" @@ -264,10 +265,10 @@ zh-TW: memorialize_account_html: "%{name} å°‡ %{target} 設å®ç‚ºè¿½æ‚¼å¸³è™Ÿ" promote_user_html: "%{name} å°ä½¿ç”¨è€… %{target} 已進行晉ç´æ“作" reject_appeal_html: "%{name} å·²å›çµ•ä¾†è‡ª %{target} ç„審核決å®ç”³è¨´" - reject_user_html: "%{name} å·²å›çµ•å¾ %{target} 而來ç„註å†" + reject_user_html: "%{name} å·²å›çµ•è‡ª %{target} 而來ç„註å†" remove_avatar_user_html: "%{name} 已移除 %{target} ç„大頭貼" reopen_report_html: "%{name} é‡æ–°é–‹å•Ÿ %{target} ç„檢舉" - resend_user_html: "%{name} å·²é‡æ–°ç™¼é€é©—證信給 %{target}" + resend_user_html: "%{name} å·²é‡æ–°ç™¼é€é©—證信至 %{target}" reset_password_user_html: "%{name} å·²é‡æ–°è¨­å®ä½¿ç”¨è€… %{target} ç„密碼" resolve_report_html: "%{name} å·²è™•ç† %{target} ç„檢舉" sensitive_account_html: "%{name} å°‡ %{target} ç„媒體檔案標記為æ•æ„Ÿå…§å®¹" @@ -383,7 +384,7 @@ zh-TW: confirm: åœæ¬ permanent_action: æ’¤é·åœæ¬å°‡ä¸æœƒå›å¾©ä»»ä½•è³‡æ–™æˆ–è·Ÿé¨é—œä¿‚ preamble_html: 您將è¦åœæ¬ %{domain} åå…¶å­ç¶²åŸŸă€‚ - remove_all_data: æ­¤æ“作將å¾æ‚¨ä¼ºæœå™¨ç§»é™¤æ‰€æœ‰ä¾†è‡ªæ­¤ç¶²åŸŸå¸³è™Ÿä¹‹å…§å®¹ă€åª’é«”ă€å€‹äººæª”æ¡ˆè³‡æ–™ă€‚ + remove_all_data: æ­¤æ“作將自您伺æœå™¨ç§»é™¤æ‰€æœ‰ä¾†è‡ªæ­¤ç¶²åŸŸå¸³è™Ÿä¹‹å…§å®¹ă€åª’é«”ă€å€‹äººæª”æ¡ˆè³‡æ–™ă€‚ stop_communication: 您伺æœå™¨å°‡åœæ­¢èˆ‡é€™äº›ä¼ºæœå™¨äº¤æµă€‚ title: 確èªå° %{domain} 網域之å°é– undo_relationships: æ­¤æ“作將撤é·ä»»ä½•æ‚¨ä¼ºæœå™¨èˆ‡æ­¤ä¼ºæœå™¨å¸³è™Ÿé–“之跟é¨é—œä¿‚。 @@ -555,11 +556,11 @@ zh-TW: relays: add_new: æ–°å¢ä¸­ç¹¼ç«™ delete: 刪除 - description_html: "è¯é‚¦ä¸­ç¹¼ç«™ 是種中繼伺æœå™¨ï¼Œæœƒæ–¼è¨‚閱並æ¨é€è‡³æ­¤ä¸­ç¹¼ç«™ç„伺æœå™¨ä¹‹é–“交æ›å¤§é‡ç„å…¬é–‹å˜Ÿæ–‡ă€‚ä¸­ç¹¼ç«™ä¹Ÿèƒ½å”å©å°å‹æˆ–中å‹ä¼ºæœå™¨å¾è¯é‚¦å®‡å®™ä¸­æ¢ç´¢å…§å®¹ï¼Œè€Œç„¡é ˆæœ¬åœ°ä½¿ç”¨è€…手動跟é¨é ç«¯ä¼ºæœå™¨ç„å…¶ä»–ä½¿ç”¨è€…ă€‚" + description_html: "è¯é‚¦ä¸­ç¹¼ç«™ 是種中繼伺æœå™¨ï¼Œæœƒæ–¼è¨‚閱並æ¨é€è‡³æ­¤ä¸­ç¹¼ç«™ç„伺æœå™¨ä¹‹é–“交æ›å¤§é‡ç„å…¬é–‹å˜Ÿæ–‡ă€‚ä¸­ç¹¼ç«™ä¹Ÿèƒ½å”å©å°å‹æˆ–中å‹ä¼ºæœå™¨è‡ªè¯é‚¦å®‡å®™ä¸­æ¢ç´¢å…§å®¹ï¼Œè€Œç„¡é ˆæœ¬åœ°ä½¿ç”¨è€…手動跟é¨é ç«¯ä¼ºæœå™¨ç„å…¶ä»–ä½¿ç”¨è€…ă€‚" disable: åœç”¨ disabled: åœç”¨ enable: 啟用 - enable_hint: 啟用後,您ç„伺æœå™¨å°‡è¨‚閱該中繼ç„所有公開文章,並將會此伺æœå™¨ç„公開文章發é€çµ¦å®ƒă€‚ + enable_hint: 啟用後,您ç„伺æœå™¨å°‡è¨‚閱該中繼ç„所有公開文章,並將此伺æœå™¨ç„公開文章å‘它發é€ă€‚ enabled: 已啟用 inbox_url: 中繼 URL pending: 等待中繼站審核 @@ -626,6 +627,7 @@ zh-TW: report: '檢舉 #%{id}' reported_account: 被檢舉使用者 reported_by: 檢舉人 + reported_with_application: é€é應用程å¼æª¢èˆ‰ resolved: 已解決 resolved_msg: 檢舉報å‘已處ç†å®Œæˆï¼ skip_to_actions: è·³é行動 @@ -648,7 +650,7 @@ zh-TW: delete_data_html: æ–¼å³æ—¥èµ· 30 天後刪除 @%{acct}之個人檔案與內容,除é他們於期é™å‰è¢«è§£é™¤åœæ¬ preview_preamble_html: "@%{acct} 將收到關於以下內容之警å‘ï¼" record_strike_html: 紀錄關於 @%{acct}之警示有å©æ–¼æ‚¨å‡ç´å°æ­¤å¸³è™Ÿæœªä¾†é•è¦è™•ç† - send_email_html: 寄一å°è­¦å‘ e-mail 給 @%{acct} + send_email_html: 寄一å°è­¦å‘ e-mail 至 @%{acct} warning_placeholder: é¸å¡«ä¹‹å…¶ä»–站務動作ç†ç”±ă€‚ target_origin: æª¢èˆ‰å¸³è™Ÿä¹‹ä¾†æº title: 檢舉 @@ -671,7 +673,7 @@ zh-TW: description_html: é€é使用者角色,您å¯ä»¥è‡ªè¨‚您ç„使用者å¯ä»¥å­˜å– Mastodon ç„哪些åŸèƒ½èˆ‡å€åŸŸă€‚ edit: ç·¨è¼¯ă€Œ%{name}ă€è§’色 everyone: é è¨­æ¬é™ - everyone_full_description_html: 這是會影響所有使用者ç„基本角色,å³ä½¿æ˜¯é‚£äº›æ²’有被分é…角色ç„ä½¿ç”¨è€…ä¹Ÿä¸€æ¨£ă€‚å…¶ä»–æ‰€æœ‰ç„角色都å¾å®ƒç¹¼æ‰¿æ¬é™ă€‚ + everyone_full_description_html: 這是會影響所有使用者ç„基本角色,å³ä½¿æ˜¯é‚£äº›æ²’有被分é…角色ç„ä½¿ç”¨è€…ä¹Ÿä¸€æ¨£ă€‚å…¶ä»–æ‰€æœ‰ç„角色都自它繼承æ¬é™ă€‚ permissions_count: other: "%{count} 個æ¬é™" privileges: @@ -757,8 +759,8 @@ zh-TW: title: æ¢ç´¢ trends: 熱門趨勢 domain_blocks: - all: 給任何人 - disabled: 給沒有人 + all: 至任何人 + disabled: 至沒有人 users: 套用至所有登入ç„本站使用者 registrations: moderation_recommandation: å°æ‰€æœ‰äººé–‹æ”¾è¨»å†ä¹‹å‰ï¼Œè«‹ç¢ºä¿æ‚¨æœ‰äººæ‰‹å……足且å應éˆæ•ç„管ç†å“¡åœ˜éï¼ @@ -797,7 +799,7 @@ zh-TW: back_to_account: è¿”å›å¸³è™Ÿè³‡è¨é é¢ back_to_report: å›åˆ°æª¢èˆ‰å ±å‘é é¢ batch: - remove_from_report: å¾æª¢èˆ‰å ±å‘中移除 + remove_from_report: 自檢舉報å‘中移除 report: æª¢èˆ‰å ±å‘ deleted: 已刪除 favourites: 最愛 @@ -1055,7 +1057,7 @@ zh-TW: dont_have_your_security_key: 找ä¸åˆ°æ‚¨ç„安全金鑰? forgot_password: 忘記密碼? invalid_reset_password_token: 密碼é‡è¨­ token 無效或已éæœŸă€‚è«‹é‡æ–°è¨­å®å¯†ç¢¼ă€‚ - link_to_otp: è«‹å¾æ‚¨æ‰‹æ©Ÿè¼¸å…¥å…©é段驗證 (2FA) 或備用驗證碼 + link_to_otp: 請自您手機輸入兩é段驗證 (2FA) 或備用驗證碼 link_to_webauth: 使用您ç„安全金鑰 log_in_with: 登入,使用 login: 登入 @@ -1138,7 +1140,7 @@ zh-TW: x_seconds: "%{count}秒" deletes: challenge_not_passed: 您所輸入ç„資料ä¸æ­£ç¢º - confirm_password: 輸入您ç¾åœ¨ç„密碼以驗證身份 + confirm_password: 輸入您目å‰ç„密碼以驗證身份 confirm_username: 請輸入您ç„使用者åç¨±ä»¥ä½œç¢ºèª proceed: 刪除帳號 success_msg: 您ç„帳號已經æˆåŸåˆªé™¤ @@ -1170,7 +1172,7 @@ zh-TW: recipient: 此致 reject_appeal: é§å›ç”³è¨´ status: '嘟文編號 #%{id}' - status_removed: 嘟文已å¾ç³»çµ±ä¸­ç§»é™¤ + status_removed: 嘟文已自系統中移除 title: "%{action} 來自 %{date}" title_actions: delete_statuses: 嘟文移除 @@ -1238,10 +1240,10 @@ zh-TW: add_keyword: æ–°å¢é—œéµå­— keywords: é—œéµå­— statuses: å„別嘟文 - statuses_hint_html: æ­¤é濾器會套用至所é¸ä¹‹å„別嘟文,無論其是å¦ç¬¦åˆä¸‹åˆ—é—œéµå­—ă€‚å¯©é–±æˆ–å¾é濾æ¢ä»¶ç§»é™¤å˜Ÿæ–‡ă€‚ + statuses_hint_html: æ­¤é濾器會套用至所é¸ä¹‹å„別嘟文,無論其是å¦ç¬¦åˆä¸‹åˆ—é—œéµå­—ă€‚å¯©é–±æˆ–è‡ªé濾æ¢ä»¶ç§»é™¤å˜Ÿæ–‡ă€‚ title: 編輯é濾æ¢ä»¶ errors: - deprecated_api_multiple_keywords: 這些åƒæ•¸ç„¡æ³•å¾æ­¤æ‡‰ç”¨ç¨‹å¼ä¸­æ›´æ”¹ï¼Œå› ç‚ºå®ƒå€‘é©ç”¨æ–¼ä¸€æˆ–å¤å€‹é濾器關éµå­—ă€‚è«‹ä½¿ç”¨è¼ƒæ–°ç„應用程å¼æˆ–是網é ä»‹é¢ă€‚ + deprecated_api_multiple_keywords: 這些åƒæ•¸ç„¡æ³•è‡ªæ­¤æ‡‰ç”¨ç¨‹å¼ä¸­æ›´æ”¹ï¼Œå› ç‚ºå®ƒå€‘é©ç”¨æ–¼ä¸€æˆ–å¤å€‹é濾器關éµå­—ă€‚è«‹ä½¿ç”¨è¼ƒæ–°ç„應用程å¼æˆ–是網é ä»‹é¢ă€‚ invalid_context: 沒有æ供內文或內文無效 index: contexts: "%{contexts} 中ç„é濾器" @@ -1262,7 +1264,7 @@ zh-TW: statuses: back_to_filter: å›åˆ°é濾器 batch: - remove: å¾é濾器中移除 + remove: 自é濾器中移除 index: hint: æ­¤é濾器會套用至所é¸ä¹‹å„別嘟文,ä¸ç®¡å®ƒå€‘有無符åˆå…¶ä»–æ¢ä»¶ă€‚您å¯ä»¥å¾ç¶²é ä»‹é¢ä¸­å°‡æ›´å¤å˜Ÿæ–‡å å…¥è‡³æ­¤éæ¿¾å™¨ă€‚ title: å·²é濾之嘟文 @@ -1419,7 +1421,7 @@ zh-TW: on_cooldown: 您最近已轉移é您ç„å¸³è™Ÿă€‚æ­¤åŸèƒ½å°‡æ–¼ %{count} 天後å¯å†åº¦ä½¿ç”¨ă€‚ past_migrations: 以往ç„轉移紀錄 proceed_with_move: 移動跟é¨è€… - redirected_msg: 您ç„帳號ç¾åœ¨æŒ‡å‘ %{acct} + redirected_msg: 您ç„帳號目å‰é‡å°å‘至 %{acct}。 redirecting_to: 您ç„帳號目å‰æ­£è¢«é‡æ–°å°å‘到 %{acct} set_redirect: 設å®é‡æ–°å°å‘ warning: @@ -1552,7 +1554,7 @@ zh-TW: mutual: è·Ÿé¨å½¼æ­¤ primary: ä¸»è¦ relationship: 關係 - remove_selected_domains: å¾æ‰€é¸å–網域中移除所有跟é¨è€… + remove_selected_domains: 自所é¸å–網域中移除所有跟é¨è€… remove_selected_followers: 移除é¸å–ç„è·Ÿé¨è€… remove_selected_follows: å–消跟é¨é¸å–ç„使用者 status: 帳號狀態 @@ -1599,7 +1601,7 @@ zh-TW: current_session: ç›®å‰ç„ session date: 日期 description: "%{platform} ä¸ç„ %{browser}" - explanation: 這些是ç¾åœ¨æ­£ç™»å…¥æ–¼æ‚¨ Mastodon 帳號ç„ç€è¦½å™¨ă€‚ + explanation: 這些是目å‰æ­£ç™»å…¥æ–¼æ‚¨ Mastodon 帳號ç„ç€è¦½å™¨ă€‚ ip: IP ä½å€ platforms: adobe_air: Adobe Air diff --git a/config/routes.rb b/config/routes.rb index 51e09ca6229a67..4114db5f43478a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -30,6 +30,7 @@ def redirect_with_vary(path) /lists/(*any) /links/(*any) /notifications/(*any) + /notifications_v2/(*any) /favourites /bookmarks /pinned @@ -64,12 +65,16 @@ def redirect_with_vary(path) tokens: 'oauth/tokens' end - get '.well-known/oauth-authorization-server', to: 'well_known/oauth_metadata#show', as: :oauth_metadata, defaults: { format: 'json' } - get '.well-known/host-meta', to: 'well_known/host_meta#show', as: :host_meta, defaults: { format: 'xml' } - get '.well-known/nodeinfo', to: 'well_known/node_info#index', as: :nodeinfo, defaults: { format: 'json' } - get '.well-known/webfinger', to: 'well_known/webfinger#show', as: :webfinger - get '.well-known/change-password', to: redirect('/auth/edit') - get '.well-known/proxy', to: redirect { |_, request| "/authorize_interaction?#{request.params.to_query}" } + scope path: '.well-known' do + scope module: :well_known do + get 'oauth-authorization-server', to: 'oauth_metadata#show', as: :oauth_metadata, defaults: { format: 'json' } + get 'host-meta', to: 'host_meta#show', as: :host_meta, defaults: { format: 'xml' } + get 'nodeinfo', to: 'node_info#index', as: :nodeinfo, defaults: { format: 'json' } + get 'webfinger', to: 'webfinger#show', as: :webfinger + end + get 'change-password', to: redirect('/auth/edit'), as: nil + get 'proxy', to: redirect { |_, request| "/authorize_interaction?#{request.params.to_query}" }, as: nil + end get '/nodeinfo/2.0', to: 'well_known/node_info#show', as: :nodeinfo_schema @@ -95,19 +100,15 @@ def redirect_with_vary(path) namespace :auth do resource :setup, only: [:show, :update], controller: :setup - resource :challenge, only: [:create], controller: :challenges + resource :challenge, only: [:create] get 'sessions/security_key_options', to: 'sessions#webauthn_options' post 'captcha_confirmation', to: 'confirmations#confirm_captcha', as: :captcha_confirmation end end - devise_for :users, path: 'auth', format: false, controllers: { - omniauth_callbacks: 'auth/omniauth_callbacks', - sessions: 'auth/sessions', - registrations: 'auth/registrations', - passwords: 'auth/passwords', - confirmations: 'auth/confirmations', - } + scope module: :auth do + devise_for :users, path: 'auth', format: false + end with_options constraints: ->(req) { req.format.nil? || req.format.html? } do get '/users/:username', to: redirect_with_vary('/@%{username}') diff --git a/config/routes/api.rb b/config/routes/api.rb index 03a79b2286eb3e..7ae621461f06ca 100644 --- a/config/routes/api.rb +++ b/config/routes/api.rb @@ -205,9 +205,11 @@ post :unmute end - resource :pin, only: :create, controller: 'accounts/pins' - post :unpin, to: 'accounts/pins#destroy' - resource :note, only: :create, controller: 'accounts/notes' + scope module: :accounts do + resource :pin, only: :create + post :unpin, to: 'pins#destroy' + resource :note, only: :create + end end resources :tags, only: [:show] do @@ -220,7 +222,7 @@ resources :followed_tags, only: [:index] resources :lists, only: [:index, :create, :show, :update, :destroy] do - resource :accounts, only: [:show, :create, :destroy], controller: 'lists/accounts' + resource :accounts, only: [:show, :create, :destroy], module: :lists end namespace :featured_tags do @@ -230,7 +232,7 @@ resources :featured_tags, only: [:index, :create, :destroy] resources :polls, only: [:create, :show] do - resources :votes, only: :create, controller: 'polls/votes' + resources :votes, only: :create, module: :polls end namespace :push do @@ -316,8 +318,10 @@ resources :suggestions, only: [:index] resource :instance, only: [:show] resources :filters, only: [:index, :create, :show, :update, :destroy] do - resources :keywords, only: [:index, :create], controller: 'filters/keywords' - resources :statuses, only: [:index, :create], controller: 'filters/statuses' + scope module: :filters do + resources :keywords, only: [:index, :create] + resources :statuses, only: [:index, :create] + end end namespace :filters do diff --git a/config/routes/settings.rb b/config/routes/settings.rb index 9aac8ef690cb05..6f166850ee8665 100644 --- a/config/routes/settings.rb +++ b/config/routes/settings.rb @@ -26,9 +26,9 @@ resources :follows, only: :index, controller: :following_accounts resources :blocks, only: :index, controller: :blocked_accounts resources :mutes, only: :index, controller: :muted_accounts - resources :lists, only: :index, controller: :lists + resources :lists, only: :index resources :domain_blocks, only: :index, controller: :blocked_domains - resources :bookmarks, only: :index, controller: :bookmarks + resources :bookmarks, only: :index end resources :two_factor_authentication_methods, only: [:index] do @@ -37,13 +37,13 @@ end end - resource :otp_authentication, only: [:show, :create], controller: 'two_factor_authentication/otp_authentication' + scope module: :two_factor_authentication do + resource :otp_authentication, only: [:show, :create], controller: :otp_authentication - resources :webauthn_credentials, only: [:index, :new, :create, :destroy], - path: 'security_keys', - controller: 'two_factor_authentication/webauthn_credentials' do - collection do - get :options + resources :webauthn_credentials, only: [:index, :new, :create, :destroy], path: 'security_keys' do + collection do + get :options + end end end diff --git a/db/migrate/20240713171841_add_application_to_reports.rb b/db/migrate/20240713171841_add_application_to_reports.rb new file mode 100644 index 00000000000000..42ba14e9b260a0 --- /dev/null +++ b/db/migrate/20240713171841_add_application_to_reports.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class AddApplicationToReports < ActiveRecord::Migration[7.1] + def change + add_column :reports, :application_id, :bigint, null: true + add_foreign_key :reports, :oauth_applications, column: :application_id, on_delete: :nullify, validate: false + end +end diff --git a/db/migrate/20240713171909_validate_add_application_to_reports.rb b/db/migrate/20240713171909_validate_add_application_to_reports.rb new file mode 100644 index 00000000000000..34ae690a3908e3 --- /dev/null +++ b/db/migrate/20240713171909_validate_add_application_to_reports.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class ValidateAddApplicationToReports < ActiveRecord::Migration[7.1] + def change + validate_foreign_key :reports, :oauth_applications + end +end diff --git a/db/post_migrate/20240712064044_remove_dismissed_from_notification_requests.rb b/db/post_migrate/20240712064044_remove_dismissed_from_notification_requests.rb new file mode 100644 index 00000000000000..0d858380730ec4 --- /dev/null +++ b/db/post_migrate/20240712064044_remove_dismissed_from_notification_requests.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class RemoveDismissedFromNotificationRequests < ActiveRecord::Migration[7.1] + def up + safety_assured do + execute 'DELETE FROM notification_requests WHERE dismissed' + remove_column :notification_requests, :dismissed + end + end + + def down + add_column :notification_requests, :dismissed, :boolean, default: false, null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index d21a1c46216c0a..9797481d6cdec9 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_06_07_094856) do +ActiveRecord::Schema[7.1].define(version: 2024_07_13_171909) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -706,11 +706,9 @@ t.bigint "from_account_id", null: false t.bigint "last_status_id" t.bigint "notifications_count", default: 0, null: false - t.boolean "dismissed", default: false, null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["account_id", "from_account_id"], name: "index_notification_requests_on_account_id_and_from_account_id", unique: true - t.index ["account_id", "id"], name: "index_notification_requests_on_account_id_and_id", order: { id: :desc }, where: "(dismissed = false)" t.index ["from_account_id"], name: "index_notification_requests_on_from_account_id" t.index ["last_status_id"], name: "index_notification_requests_on_last_status_id" end @@ -931,6 +929,7 @@ t.integer "category", default: 0, null: false t.datetime "action_taken_at", precision: nil t.bigint "rule_ids", array: true + t.bigint "application_id" t.index ["account_id"], name: "index_reports_on_account_id" t.index ["action_taken_by_account_id"], name: "index_reports_on_action_taken_by_account_id", where: "(action_taken_by_account_id IS NOT NULL)" t.index ["assigned_account_id"], name: "index_reports_on_assigned_account_id", where: "(assigned_account_id IS NOT NULL)" @@ -1367,6 +1366,7 @@ add_foreign_key "reports", "accounts", column: "assigned_account_id", on_delete: :nullify add_foreign_key "reports", "accounts", column: "target_account_id", name: "fk_eb37af34f0", on_delete: :cascade add_foreign_key "reports", "accounts", name: "fk_4b81f7522c", on_delete: :cascade + add_foreign_key "reports", "oauth_applications", column: "application_id", on_delete: :nullify add_foreign_key "scheduled_statuses", "accounts", on_delete: :cascade add_foreign_key "session_activations", "oauth_access_tokens", column: "access_token_id", name: "fk_957e5bda89", on_delete: :cascade add_foreign_key "session_activations", "users", name: "fk_e5fda67334", on_delete: :cascade diff --git a/package.json b/package.json index a320c281ba0993..acfb215f560126 100644 --- a/package.json +++ b/package.json @@ -126,6 +126,7 @@ "tesseract.js": "^2.1.5", "tiny-queue": "^0.2.1", "twitter-text": "3.1.0", + "use-debounce": "^10.0.0", "webpack": "^4.47.0", "webpack-assets-manifest": "^4.0.6", "webpack-bundle-analyzer": "^4.8.0", diff --git a/spec/controllers/activitypub/collections_controller_spec.rb b/spec/controllers/activitypub/collections_controller_spec.rb index 11ef03c8425c1c..a5718fbd7d3c06 100644 --- a/spec/controllers/activitypub/collections_controller_spec.rb +++ b/spec/controllers/activitypub/collections_controller_spec.rb @@ -25,14 +25,12 @@ context 'without signature' do let(:remote_account) { nil } - it 'returns http success and correct media type' do + it_behaves_like 'cacheable response' + + it 'returns http success and correct media type and correct items' do expect(response).to have_http_status(200) expect(response.media_type).to eq 'application/activity+json' - end - it_behaves_like 'cacheable response' - - it 'returns orderedItems with correct items' do expect(body_as_json[:orderedItems]) .to be_an(Array) .and have_attributes(size: 3) @@ -66,14 +64,12 @@ let(:remote_account) { Fabricate(:account, domain: 'example.com') } context 'when getting a featured resource' do - it 'returns http success and correct media type' do + it_behaves_like 'cacheable response' + + it 'returns http success and correct media type and expected items' do expect(response).to have_http_status(200) expect(response.media_type).to eq 'application/activity+json' - end - - it_behaves_like 'cacheable response' - it 'returns orderedItems with expected items' do expect(body_as_json[:orderedItems]) .to be_an(Array) .and have_attributes(size: 3) @@ -92,16 +88,14 @@ account.block!(remote_account) end - it 'returns http success and correct media type and cache headers' do + it 'returns http success and correct media type and cache headers and empty items' do expect(response).to have_http_status(200) expect(response.media_type).to eq 'application/activity+json' expect(response.headers['Cache-Control']).to include 'private' - end - it 'returns empty orderedItems' do expect(body_as_json[:orderedItems]) .to be_an(Array) - .and have_attributes(size: 0) + .and be_empty end end @@ -110,16 +104,14 @@ account.block_domain!(remote_account.domain) end - it 'returns http success and correct media type and cache headers' do + it 'returns http success and correct media type and cache headers and empty items' do expect(response).to have_http_status(200) expect(response.media_type).to eq 'application/activity+json' expect(response.headers['Cache-Control']).to include 'private' - end - it 'returns empty orderedItems' do expect(body_as_json[:orderedItems]) .to be_an(Array) - .and have_attributes(size: 0) + .and be_empty end end end diff --git a/spec/controllers/activitypub/followers_synchronizations_controller_spec.rb b/spec/controllers/activitypub/followers_synchronizations_controller_spec.rb index b50c7b9cdcb1d7..c030078d43a643 100644 --- a/spec/controllers/activitypub/followers_synchronizations_controller_spec.rb +++ b/spec/controllers/activitypub/followers_synchronizations_controller_spec.rb @@ -37,25 +37,18 @@ let(:body) { body_as_json } let(:remote_account) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/instance') } - it 'returns http success' do + it 'returns http success and cache control and activity json types and correct items' do expect(response).to have_http_status(200) - end - - it 'returns application/activity+json' do + expect(response.headers['Cache-Control']).to eq 'max-age=0, private' expect(response.media_type).to eq 'application/activity+json' - end - it 'returns orderedItems with followers from example.com' do - expect(body[:orderedItems]).to be_an Array - expect(body[:orderedItems]).to contain_exactly( - follower_example_com_instance_actor.uri, - follower_example_com_user_a.uri, - follower_example_com_user_b.uri - ) - end - - it 'returns private Cache-Control header' do - expect(response.headers['Cache-Control']).to eq 'max-age=0, private' + expect(body[:orderedItems]) + .to be_an(Array) + .and contain_exactly( + follower_example_com_instance_actor.uri, + follower_example_com_user_a.uri, + follower_example_com_user_b.uri + ) end context 'when account is permanently suspended' do diff --git a/spec/controllers/activitypub/outboxes_controller_spec.rb b/spec/controllers/activitypub/outboxes_controller_spec.rb index ead231f29fbe43..3c8e8e399f6296 100644 --- a/spec/controllers/activitypub/outboxes_controller_spec.rb +++ b/spec/controllers/activitypub/outboxes_controller_spec.rb @@ -25,22 +25,13 @@ context 'with page not requested' do let(:page) { nil } - it 'returns http success' do - expect(response).to have_http_status(200) - end - - it 'returns application/activity+json' do - expect(response.media_type).to eq 'application/activity+json' - end - - it 'returns totalItems' do - expect(body[:totalItems]).to eq 4 - end - it_behaves_like 'cacheable response' - it 'does not have a Vary header' do + it 'returns http success and correct media type and headers and items count' do + expect(response).to have_http_status(200) + expect(response.media_type).to eq 'application/activity+json' expect(response.headers['Vary']).to be_nil + expect(body[:totalItems]).to eq 4 end context 'when account is permanently suspended' do @@ -68,26 +59,18 @@ context 'with page requested' do let(:page) { 'true' } - it 'returns http success' do - expect(response).to have_http_status(200) - end + it_behaves_like 'cacheable response' - it 'returns application/activity+json' do + it 'returns http success and correct media type and vary header and items' do + expect(response).to have_http_status(200) expect(response.media_type).to eq 'application/activity+json' - end + expect(response.headers['Vary']).to include 'Signature' - it 'returns orderedItems with public or unlisted statuses' do expect(body[:orderedItems]).to be_an Array expect(body[:orderedItems].size).to eq 2 expect(body[:orderedItems].all? { |item| targets_public_collection?(item) }).to be true end - it_behaves_like 'cacheable response' - - it 'returns Vary header with Signature' do - expect(response.headers['Vary']).to include 'Signature' - end - context 'when account is permanently suspended' do before do account.suspend! @@ -120,23 +103,14 @@ get :show, params: { account_username: account.username, page: page } end - it 'returns http success' do + it 'returns http success and correct media type and headers and items' do expect(response).to have_http_status(200) - end - - it 'returns application/activity+json' do expect(response.media_type).to eq 'application/activity+json' - end - - it 'returns orderedItems with public or unlisted statuses' do - json = body_as_json - expect(json[:orderedItems]).to be_an Array - expect(json[:orderedItems].size).to eq 2 - expect(json[:orderedItems].all? { |item| targets_public_collection?(item) }).to be true - end - - it 'returns private Cache-Control header' do expect(response.headers['Cache-Control']).to eq 'max-age=60, private' + + expect(body_as_json[:orderedItems]).to be_an Array + expect(body_as_json[:orderedItems].size).to eq 2 + expect(body_as_json[:orderedItems].all? { |item| targets_public_collection?(item) }).to be true end end @@ -146,23 +120,14 @@ get :show, params: { account_username: account.username, page: page } end - it 'returns http success' do + it 'returns http success and correct media type and headers and items' do expect(response).to have_http_status(200) - end - - it 'returns application/activity+json' do expect(response.media_type).to eq 'application/activity+json' - end - - it 'returns orderedItems with private statuses' do - json = body_as_json - expect(json[:orderedItems]).to be_an Array - expect(json[:orderedItems].size).to eq 3 - expect(json[:orderedItems].all? { |item| targets_public_collection?(item) || targets_followers_collection?(item, account) }).to be true - end - - it 'returns private Cache-Control header' do expect(response.headers['Cache-Control']).to eq 'max-age=60, private' + + expect(body_as_json[:orderedItems]).to be_an Array + expect(body_as_json[:orderedItems].size).to eq 3 + expect(body_as_json[:orderedItems].all? { |item| targets_public_collection?(item) || targets_followers_collection?(item, account) }).to be true end end @@ -172,22 +137,14 @@ get :show, params: { account_username: account.username, page: page } end - it 'returns http success' do + it 'returns http success and correct media type and headers and items' do expect(response).to have_http_status(200) - end - - it 'returns application/activity+json' do expect(response.media_type).to eq 'application/activity+json' - end - - it 'returns empty orderedItems' do - json = body_as_json - expect(json[:orderedItems]).to be_an Array - expect(json[:orderedItems].size).to eq 0 - end - - it 'returns private Cache-Control header' do expect(response.headers['Cache-Control']).to eq 'max-age=60, private' + + expect(body_as_json[:orderedItems]) + .to be_an(Array) + .and be_empty end end @@ -197,22 +154,14 @@ get :show, params: { account_username: account.username, page: page } end - it 'returns http success' do + it 'returns http success and correct media type and headers and items' do expect(response).to have_http_status(200) - end - - it 'returns application/activity+json' do expect(response.media_type).to eq 'application/activity+json' - end - - it 'returns empty orderedItems' do - json = body_as_json - expect(json[:orderedItems]).to be_an Array - expect(json[:orderedItems].size).to eq 0 - end - - it 'returns private Cache-Control header' do expect(response.headers['Cache-Control']).to eq 'max-age=60, private' + + expect(body_as_json[:orderedItems]) + .to be_an(Array) + .and be_empty end end end diff --git a/spec/controllers/activitypub/replies_controller_spec.rb b/spec/controllers/activitypub/replies_controller_spec.rb index db7f60d3f873dc..c556e0727047c4 100644 --- a/spec/controllers/activitypub/replies_controller_spec.rb +++ b/spec/controllers/activitypub/replies_controller_spec.rb @@ -66,19 +66,15 @@ context 'when status is public' do let(:parent_visibility) { :public } - let(:json) { body_as_json } - let(:page_json) { json[:first] } + let(:page_json) { body_as_json[:first] } - it 'returns http success' do - expect(response).to have_http_status(200) - end + it_behaves_like 'cacheable response' - it 'returns application/activity+json' do + it 'returns http success and correct media type' do + expect(response).to have_http_status(200) expect(response.media_type).to eq 'application/activity+json' end - it_behaves_like 'cacheable response' - context 'without only_other_accounts' do it "returns items with thread author's replies" do expect(page_json).to be_a Hash diff --git a/spec/controllers/admin/disputes/appeals_controller_spec.rb b/spec/controllers/admin/disputes/appeals_controller_spec.rb index bf7f9bd70485c0..678ceee1158eb1 100644 --- a/spec/controllers/admin/disputes/appeals_controller_spec.rb +++ b/spec/controllers/admin/disputes/appeals_controller_spec.rb @@ -34,7 +34,7 @@ let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) } - it 'redirects back to the strike page and notifies target account about approved appeal', :sidekiq_inline do + it 'redirects back to the strike page and notifies target account about approved appeal', :inline_jobs do emails = capture_emails { subject } expect(response) @@ -58,7 +58,7 @@ let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) } - it 'redirects back to the strike page and notifies target account about rejected appeal', :sidekiq_inline do + it 'redirects back to the strike page and notifies target account about rejected appeal', :inline_jobs do emails = capture_emails { subject } expect(response) diff --git a/spec/controllers/admin/domain_blocks_controller_spec.rb b/spec/controllers/admin/domain_blocks_controller_spec.rb index 87b08323da917c..eb2c6265d12eec 100644 --- a/spec/controllers/admin/domain_blocks_controller_spec.rb +++ b/spec/controllers/admin/domain_blocks_controller_spec.rb @@ -176,7 +176,7 @@ end end - describe 'PUT #update', :sidekiq_inline do + describe 'PUT #update', :inline_jobs do subject do post :update, params: { :id => domain_block.id, :domain_block => { domain: 'example.com', severity: new_severity }, 'confirm' => '' } end diff --git a/spec/controllers/admin/reports_controller_spec.rb b/spec/controllers/admin/reports_controller_spec.rb index 02760154fbe5ff..5849163b5fe06e 100644 --- a/spec/controllers/admin/reports_controller_spec.rb +++ b/spec/controllers/admin/reports_controller_spec.rb @@ -64,7 +64,7 @@ describe 'POST #reopen' do it 'reopens the report' do - report = Fabricate(:report) + report = Fabricate(:report, action_taken_at: 3.days.ago) put :reopen, params: { id: report } expect(response).to redirect_to(admin_report_path(report)) @@ -89,7 +89,7 @@ describe 'POST #unassign' do it 'reopens the report' do - report = Fabricate(:report) + report = Fabricate(:report, assigned_account_id: Account.last.id) put :unassign, params: { id: report } expect(response).to redirect_to(admin_report_path(report)) diff --git a/spec/controllers/admin/resets_controller_spec.rb b/spec/controllers/admin/resets_controller_spec.rb index 10ed2cf969730c..0cbc3b60ab6f88 100644 --- a/spec/controllers/admin/resets_controller_spec.rb +++ b/spec/controllers/admin/resets_controller_spec.rb @@ -13,7 +13,7 @@ sign_in Fabricate(:user, role: UserRole.find_by(name: 'Admin')), scope: :user end - describe 'POST #create', :sidekiq_inline do + describe 'POST #create', :inline_jobs do it 'redirects to admin accounts page' do emails = capture_emails { subject } diff --git a/spec/controllers/auth/sessions_controller_spec.rb b/spec/controllers/auth/sessions_controller_spec.rb index e78554ec7dc3e8..9a94e5e1a1a464 100644 --- a/spec/controllers/auth/sessions_controller_spec.rb +++ b/spec/controllers/auth/sessions_controller_spec.rb @@ -123,7 +123,7 @@ user.update(current_sign_in_at: 1.month.ago) end - it 'logs the user in and sends suspicious email and redirects home', :sidekiq_inline do + it 'logs the user in and sends suspicious email and redirects home', :inline_jobs do emails = capture_emails { subject } expect(response) @@ -263,7 +263,7 @@ travel_to '2023-12-20T10:00:00Z' end - it 'does not log the user in, sets a flash message, and sends a suspicious sign in email', :sidekiq_inline do + it 'does not log the user in, sets a flash message, and sends a suspicious sign in email', :inline_jobs do emails = capture_emails do Auth::SessionsController::MAX_2FA_ATTEMPTS_PER_HOUR.times do post :create, params: { user: { otp_attempt: '1234' } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s } diff --git a/spec/controllers/concerns/user_tracking_concern_spec.rb b/spec/controllers/concerns/user_tracking_concern_spec.rb index b1de3cf4e2e2a0..f23d482f5f9303 100644 --- a/spec/controllers/concerns/user_tracking_concern_spec.rb +++ b/spec/controllers/concerns/user_tracking_concern_spec.rb @@ -75,7 +75,7 @@ def show expect(redis.ttl("account:#{user.account_id}:regeneration")).to be >= 0 end - it 'regenerates feed when sign in is older than two weeks', :sidekiq_inline do + it 'regenerates feed when sign in is older than two weeks', :inline_jobs do get :show expect_updated_sign_in_at(user) diff --git a/spec/controllers/disputes/appeals_controller_spec.rb b/spec/controllers/disputes/appeals_controller_spec.rb index 99d5a8b17f0252..3e874bbdcc0cab 100644 --- a/spec/controllers/disputes/appeals_controller_spec.rb +++ b/spec/controllers/disputes/appeals_controller_spec.rb @@ -17,7 +17,7 @@ let(:strike) { Fabricate(:account_warning, target_account: current_user.account) } let(:params) { { strike_id: strike.id, appeal: { text: 'Foo' } } } - it 'notifies staff about new appeal and redirects back to strike page', :sidekiq_inline do + it 'notifies staff about new appeal and redirects back to strike page', :inline_jobs do emails = capture_emails { subject } expect(emails.size) @@ -36,7 +36,7 @@ let(:strike) { Fabricate(:account_warning, target_account: current_user.account) } let(:params) { { strike_id: strike.id, appeal: { text: '' } } } - it 'does not send email and renders strike show page', :sidekiq_inline do + it 'does not send email and renders strike show page', :inline_jobs do emails = capture_emails { subject } expect(emails).to be_empty diff --git a/spec/controllers/invites_controller_spec.rb b/spec/controllers/invites_controller_spec.rb index 3190c82884228f..5221941267fa00 100644 --- a/spec/controllers/invites_controller_spec.rb +++ b/spec/controllers/invites_controller_spec.rb @@ -69,19 +69,16 @@ end end - describe 'DELETE #create' do - let(:invite) { Fabricate(:invite, user: user, expires_at: nil) } - - before do - delete :destroy, params: { id: invite.id } - end + describe 'DELETE #destroy' do + subject { delete :destroy, params: { id: invite.id } } - it 'redirects' do - expect(response).to redirect_to invites_path - end + let(:invite) { Fabricate(:invite, user: user, expires_at: nil) } - it 'expires invite' do - expect(invite.reload).to be_expired + it 'expires invite and redirects' do + expect { subject } + .to(change { invite.reload.expired? }.to(true)) + expect(response) + .to redirect_to invites_path end end end diff --git a/spec/controllers/settings/deletes_controller_spec.rb b/spec/controllers/settings/deletes_controller_spec.rb index ccca4564e733a1..3342599bc1172e 100644 --- a/spec/controllers/settings/deletes_controller_spec.rb +++ b/spec/controllers/settings/deletes_controller_spec.rb @@ -50,7 +50,7 @@ delete :destroy, params: { form_delete_confirmation: { password: 'petsmoldoggos' } } end - it 'removes user record and redirects', :aggregate_failures, :sidekiq_inline do + it 'removes user record and redirects', :aggregate_failures, :inline_jobs do expect(response).to redirect_to '/auth/sign_in' expect(User.find_by(id: user.id)).to be_nil expect(user.account.reload).to be_suspended diff --git a/spec/fabricators/notification_request_fabricator.rb b/spec/fabricators/notification_request_fabricator.rb index 05a13b8ef8010d..a20d3b3ef2b83d 100644 --- a/spec/fabricators/notification_request_fabricator.rb +++ b/spec/fabricators/notification_request_fabricator.rb @@ -4,5 +4,4 @@ account from_account { Fabricate.build(:account) } last_status { Fabricate.build(:status) } - dismissed false end diff --git a/spec/fixtures/requests/alternative_utf8_spelling_in_header.txt b/spec/fixtures/requests/alternative_utf8_spelling_in_header.txt new file mode 100644 index 00000000000000..7aaea370e86230 --- /dev/null +++ b/spec/fixtures/requests/alternative_utf8_spelling_in_header.txt @@ -0,0 +1,18 @@ +HTTP/1.1 200 OK +server: nginx +date: Thu, 13 Jun 2024 14:33:13 GMT +content-type: text/html; charset=utf8 +content-length: 192 +accept-ranges: bytes + + + + + + Webserver Configs R Us + + +

Welcome

+

Sneaky non-UTF character: á

+ + diff --git a/spec/fixtures/requests/latin1_posing_as_utf8_broken.txt b/spec/fixtures/requests/latin1_posing_as_utf8_broken.txt new file mode 100644 index 00000000000000..ed8a4716a3eba6 --- /dev/null +++ b/spec/fixtures/requests/latin1_posing_as_utf8_broken.txt @@ -0,0 +1,17 @@ +HTTP/1.1 200 OK +server: nginx +date: Thu, 13 Jun 2024 14:33:13 GMT +content-type: text/html; charset=utf-8 +content-length: 158 +accept-ranges: bytes + + + + + + Tofu á l'orange + + +

Tofu á l'orange

+ + diff --git a/spec/fixtures/requests/latin1_posing_as_utf8_recoverable.txt b/spec/fixtures/requests/latin1_posing_as_utf8_recoverable.txt new file mode 100644 index 00000000000000..a24985832ca551 --- /dev/null +++ b/spec/fixtures/requests/latin1_posing_as_utf8_recoverable.txt @@ -0,0 +1,17 @@ +HTTP/1.1 200 OK +server: nginx +date: Thu, 13 Jun 2024 14:33:13 GMT +content-type: text/html; charset=utf-8 +content-length: 158 +accept-ranges: bytes + + + + + + Tofu with orange sauce + + +

Tofu á l'orange

+ + diff --git a/spec/fixtures/requests/long_canonical_url.txt b/spec/fixtures/requests/long_canonical_url.txt new file mode 100644 index 00000000000000..97d6c93961fb47 --- /dev/null +++ b/spec/fixtures/requests/long_canonical_url.txt @@ -0,0 +1,18 @@ +HTTP/1.1 200 OK +server: nginx +date: Thu, 13 Jun 2024 14:33:13 GMT +content-type: text/html; charset=utf-8 +content-length: 3225 +accept-ranges: bytes + + + + + + + Very long canonical URL + + +

We have very long URLs

+ + diff --git a/spec/fixtures/requests/page_without_title.txt b/spec/fixtures/requests/page_without_title.txt new file mode 100644 index 00000000000000..0054aa3b7e0db0 --- /dev/null +++ b/spec/fixtures/requests/page_without_title.txt @@ -0,0 +1,17 @@ +HTTP/1.1 200 OK +server: nginx +date: Thu, 13 Jun 2024 14:33:13 GMT +content-type: text/html; charset=utf-8 +content-length: 171 +accept-ranges: bytes + + + + + + + +

I am not a valid page

+

Thankfully, browsers do not care

+ + diff --git a/spec/lib/activitypub/activity/delete_spec.rb b/spec/lib/activitypub/activity/delete_spec.rb index 48421a116294b5..71977a96a2be81 100644 --- a/spec/lib/activitypub/activity/delete_spec.rb +++ b/spec/lib/activitypub/activity/delete_spec.rb @@ -47,7 +47,7 @@ expect(Status.find_by(id: status.id)).to be_nil end - it 'sends delete activity to followers of rebloggers', :sidekiq_inline do + it 'sends delete activity to followers of rebloggers', :inline_jobs do expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once end diff --git a/spec/lib/activitypub/activity/flag_spec.rb b/spec/lib/activitypub/activity/flag_spec.rb index 426cd97df9acf3..be1bd42a14a810 100644 --- a/spec/lib/activitypub/activity/flag_spec.rb +++ b/spec/lib/activitypub/activity/flag_spec.rb @@ -36,6 +36,7 @@ expect(report).to_not be_nil expect(report.comment).to eq 'Boo!!' expect(report.status_ids).to eq [status.id] + expect(report.application).to be_nil end end diff --git a/spec/lib/activitypub/activity/move_spec.rb b/spec/lib/activitypub/activity/move_spec.rb index 4dda014a068565..d69ef215161210 100644 --- a/spec/lib/activitypub/activity/move_spec.rb +++ b/spec/lib/activitypub/activity/move_spec.rb @@ -38,7 +38,7 @@ subject.perform end - context 'when all conditions are met', :sidekiq_inline do + context 'when all conditions are met', :inline_jobs do it 'sets moved account on old account' do expect(old_account.reload.moved_to_account_id).to eq new_account.id end diff --git a/spec/lib/link_details_extractor_spec.rb b/spec/lib/link_details_extractor_spec.rb index 26d9d4e2659821..2a4df70a8bf226 100644 --- a/spec/lib/link_details_extractor_spec.rb +++ b/spec/lib/link_details_extractor_spec.rb @@ -192,6 +192,35 @@ include_examples 'structured data' end + + context 'with author names as array' do + let(:ld_json) do + { + '@context' => 'https://schema.org', + '@type' => 'NewsArticle', + 'headline' => 'A lot of authors', + 'description' => 'But we decided to cram them into one', + 'author' => { + '@type' => 'Person', + 'name' => ['Author 1', 'Author 2'], + }, + }.to_json + end + let(:html) { <<~HTML } + + + + + + + HTML + + it 'joins author names' do + expect(subject.author_name).to eq 'Author 1, Author 2' + end + end end context 'when Open Graph protocol data is present' do diff --git a/spec/lib/vacuum/media_attachments_vacuum_spec.rb b/spec/lib/vacuum/media_attachments_vacuum_spec.rb index 3c17ecb0003f83..1039c36cea6ff2 100644 --- a/spec/lib/vacuum/media_attachments_vacuum_spec.rb +++ b/spec/lib/vacuum/media_attachments_vacuum_spec.rb @@ -17,32 +17,21 @@ let!(:old_unattached_media) { Fabricate(:media_attachment, account_id: nil, created_at: 10.days.ago) } let!(:new_unattached_media) { Fabricate(:media_attachment, account_id: nil, created_at: 1.hour.ago) } - before do - subject.perform - end - - it 'deletes cache of remote media attachments past the retention period' do - expect(old_remote_media.reload.file).to be_blank - end - - it 'does not touch local media attachments past the retention period' do - expect(old_local_media.reload.file).to_not be_blank - end - - it 'does not delete cache of remote media attachments within the retention period' do - expect(new_remote_media.reload.file).to_not be_blank - end - - it 'does not touch local media attachments within the retention period' do - expect(new_local_media.reload.file).to_not be_blank - end - - it 'deletes unattached media attachments past TTL' do - expect { old_unattached_media.reload }.to raise_error(ActiveRecord::RecordNotFound) - end - - it 'does not delete unattached media attachments within TTL' do - expect(new_unattached_media.reload).to be_persisted + before { subject.perform } + + it 'handles attachments based on metadata details' do + expect(old_remote_media.reload.file) # Remote and past retention period + .to be_blank + expect(old_local_media.reload.file) # Local and past retention + .to_not be_blank + expect(new_remote_media.reload.file) # Remote and within retention + .to_not be_blank + expect(new_local_media.reload.file) # Local and within retention + .to_not be_blank + expect { old_unattached_media.reload } # Unattached and past TTL + .to raise_error(ActiveRecord::RecordNotFound) + expect(new_unattached_media.reload) # Unattached and within TTL + .to be_persisted end end end diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index 225929ae39f9a6..dfb1f5bc61528c 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -1015,21 +1015,26 @@ def account_note_over_limit context 'when is local' do it 'generates keys' do - account = described_class.create!(domain: nil, username: Faker::Internet.user_name(separators: ['_'])) - expect(account.keypair).to be_private - expect(account.keypair).to be_public + account = described_class.create!(domain: nil, username: 'user_without_keys') + + expect(account) + .to be_private_key + .and be_public_key + expect(account.keypair) + .to be_private + .and be_public end end context 'when is remote' do it 'does not generate keys' do key = OpenSSL::PKey::RSA.new(1024).public_key - account = described_class.create!(domain: 'remote', uri: 'https://remote/actor', username: Faker::Internet.user_name(separators: ['_']), public_key: key.to_pem) + account = described_class.create!(domain: 'remote', uri: 'https://remote/actor', username: 'remote_user_with_public', public_key: key.to_pem) expect(account.keypair.params).to eq key.params end it 'normalizes domain' do - account = described_class.create!(domain: 'ă«ă‚ƒă‚“', uri: 'https://xn--r9j5b5b/actor', username: Faker::Internet.user_name(separators: ['_'])) + account = described_class.create!(domain: 'ă«ă‚ƒă‚“', uri: 'https://xn--r9j5b5b/actor', username: 'remote_user_with_idn_domain') expect(account.domain).to eq 'xn--r9j5b5b' end end diff --git a/spec/models/admin/account_action_spec.rb b/spec/models/admin/account_action_spec.rb index e55db2f814a19e..49bc2b4a91c46c 100644 --- a/spec/models/admin/account_action_spec.rb +++ b/spec/models/admin/account_action_spec.rb @@ -69,7 +69,7 @@ end end - it 'sends email to target account user', :sidekiq_inline do + it 'sends email to target account user', :inline_jobs do emails = capture_emails { subject } expect(emails).to contain_exactly( diff --git a/spec/models/custom_emoji_spec.rb b/spec/models/custom_emoji_spec.rb index 038d1d0c6cda8f..cb8cb5c11bd67e 100644 --- a/spec/models/custom_emoji_spec.rb +++ b/spec/models/custom_emoji_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe CustomEmoji, :paperclip_processing do +RSpec.describe CustomEmoji, :attachment_processing do describe '#search' do subject { described_class.search(search_term) } diff --git a/spec/models/media_attachment_spec.rb b/spec/models/media_attachment_spec.rb index a8f1ce7745ee6e..3142b291fb2b00 100644 --- a/spec/models/media_attachment_spec.rb +++ b/spec/models/media_attachment_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe MediaAttachment, :paperclip_processing do +RSpec.describe MediaAttachment, :attachment_processing do describe 'local?' do subject { media_attachment.local? } @@ -90,7 +90,7 @@ media.destroy end - it 'saves media attachment with correct file metadata' do + it 'saves media attachment with correct file and size metadata' do expect(media) .to be_persisted .and be_processing_complete @@ -103,14 +103,12 @@ # Rack::Mime (used by PublicFileServerMiddleware) recognizes file extension expect(Rack::Mime.mime_type(extension, nil)).to eq content_type - end - it 'saves media attachment with correct size metadata' do - # strips original file name + # Strip original file name expect(media.file_file_name) .to_not start_with '600x400' - # sets meta for original and thumbnail + # Set meta for original and thumbnail expect(media.file.meta.deep_symbolize_keys) .to include( original: include( @@ -174,10 +172,18 @@ let(:media) { Fabricate(:media_attachment, file: attachment_fixture('avatar.gif')) } it 'sets correct file metadata' do - expect(media.type).to eq 'gifv' - expect(media.file_content_type).to eq 'video/mp4' - expect(media.file.meta['original']['width']).to eq 128 - expect(media.file.meta['original']['height']).to eq 128 + expect(media) + .to have_attributes( + type: eq('gifv'), + file_content_type: eq('video/mp4') + ) + expect(media_metadata) + .to include( + original: include( + width: eq(128), + height: eq(128) + ) + ) end end @@ -192,11 +198,19 @@ let(:media) { Fabricate(:media_attachment, file: attachment_fixture(fixture[:filename])) } it 'sets correct file metadata' do - expect(media.type).to eq 'image' - expect(media.file_content_type).to eq 'image/gif' - expect(media.file.meta['original']['width']).to eq fixture[:width] - expect(media.file.meta['original']['height']).to eq fixture[:height] - expect(media.file.meta['original']['aspect']).to eq fixture[:aspect] + expect(media) + .to have_attributes( + type: eq('image'), + file_content_type: eq('image/gif') + ) + expect(media_metadata) + .to include( + original: include( + width: eq(fixture[:width]), + height: eq(fixture[:height]), + aspect: eq(fixture[:aspect]) + ) + ) end end end @@ -204,39 +218,42 @@ describe 'ogg with cover art' do let(:media) { Fabricate(:media_attachment, file: attachment_fixture('boop.ogg')) } + let(:expected_media_duration) { 0.235102 } - it 'sets correct file metadata' do - expect(media.type).to eq 'audio' - expect(media.file.meta['original']['duration']).to be_within(0.05).of(0.235102) - expect(media.thumbnail.present?).to be true + # The libvips and ImageMagick implementations produce different results + let(:expected_background_color) { Rails.configuration.x.use_vips ? '#268cd9' : '#3088d4' } - expect(media.file.meta['colors']['background']).to eq(expected_background_color) - expect(media.file_file_name).to_not eq 'boop.ogg' - end + it 'sets correct file metadata' do + expect(media) + .to have_attributes( + type: eq('audio'), + thumbnail: be_present, + file_file_name: not_eq('boop.ogg') + ) - def expected_background_color - # The libvips and ImageMagick implementations produce different results - Rails.configuration.x.use_vips ? '#268cd9' : '#3088d4' + expect(media_metadata) + .to include( + original: include(duration: be_within(0.05).of(expected_media_duration)), + colors: include(background: eq(expected_background_color)) + ) end end describe 'mp3 with large cover art' do let(:media) { Fabricate(:media_attachment, file: attachment_fixture('boop.mp3')) } + let(:expected_media_duration) { 0.235102 } - it 'detects it as an audio file' do - expect(media.type).to eq 'audio' - end - - it 'sets meta for the duration' do - expect(media.file.meta['original']['duration']).to be_within(0.05).of(0.235102) - end - - it 'extracts thumbnail' do - expect(media.thumbnail.present?).to be true - end - - it 'gives the file a random name' do - expect(media.file_file_name).to_not eq 'boop.mp3' + it 'detects file type and sets correct metadata' do + expect(media) + .to have_attributes( + type: eq('audio'), + thumbnail: be_present, + file_file_name: not_eq('boop.mp3') + ) + expect(media_metadata) + .to include( + original: include(duration: be_within(0.05).of(expected_media_duration)) + ) end end @@ -274,4 +291,10 @@ def expected_background_color expect(media.valid?).to be true end end + + private + + def media_metadata + media.file.meta.deep_symbolize_keys + end end diff --git a/spec/models/notification_request_spec.rb b/spec/models/notification_request_spec.rb index 07bbc3e0a8e7e9..4adddc194f015c 100644 --- a/spec/models/notification_request_spec.rb +++ b/spec/models/notification_request_spec.rb @@ -4,9 +4,7 @@ RSpec.describe NotificationRequest do describe '#reconsider_existence!' do - subject { Fabricate(:notification_request, dismissed: dismissed) } - - let(:dismissed) { false } + subject { Fabricate(:notification_request) } context 'when there are remaining notifications' do before do @@ -28,14 +26,6 @@ subject.reconsider_existence! end - context 'when dismissed' do - let(:dismissed) { true } - - it 'leaves request intact' do - expect(subject.destroyed?).to be false - end - end - it 'removes the request' do expect(subject.destroyed?).to be true end diff --git a/spec/models/status_spec.rb b/spec/models/status_spec.rb index 0d87588d4c497f..c0b0c2420fdd7c 100644 --- a/spec/models/status_spec.rb +++ b/spec/models/status_spec.rb @@ -284,6 +284,41 @@ end end + describe '#ordered_media_attachments' do + let(:status) { Fabricate(:status) } + + let(:first_attachment) { Fabricate(:media_attachment) } + let(:second_attachment) { Fabricate(:media_attachment) } + let(:last_attachment) { Fabricate(:media_attachment) } + let(:extra_attachment) { Fabricate(:media_attachment) } + + before do + stub_const('Status::MEDIA_ATTACHMENTS_LIMIT', 3) + + # Add attachments out of order + status.media_attachments << second_attachment + status.media_attachments << last_attachment + status.media_attachments << extra_attachment + status.media_attachments << first_attachment + end + + context 'when ordered_media_attachment_ids is not set' do + it 'returns up to MEDIA_ATTACHMENTS_LIMIT attachments' do + expect(status.ordered_media_attachments.size).to eq Status::MEDIA_ATTACHMENTS_LIMIT + end + end + + context 'when ordered_media_attachment_ids is set' do + before do + status.update!(ordered_media_attachment_ids: [first_attachment.id, second_attachment.id, last_attachment.id, extra_attachment.id]) + end + + it 'returns up to MEDIA_ATTACHMENTS_LIMIT attachments in the expected order' do + expect(status.ordered_media_attachments).to eq [first_attachment, second_attachment, last_attachment] + end + end + end + describe '.mutes_map' do subject { described_class.mutes_map([status.conversation.id], account) } diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index fa0a0503a6561d..4755500fc4e356 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -101,7 +101,7 @@ end end - describe 'scopes', :sidekiq_inline do + describe 'scopes', :inline_jobs do describe 'recent' do it 'returns an array of recent users ordered by id' do first_user = Fabricate(:user) @@ -507,7 +507,7 @@ def within_duration_window_days context 'when user is new' do let(:confirmed_at) { nil } - it 'confirms user and delivers welcome email', :sidekiq_inline do + it 'confirms user and delivers welcome email', :inline_jobs do emails = capture_emails { subject } expect(user.confirmed_at).to be_present diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 38aa711089e325..d4b9bddf93f12a 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -120,7 +120,7 @@ def sign_in(resource, _deprecated = nil, scope: nil) end config.around do |example| - if example.metadata[:sidekiq_inline] == true + if example.metadata[:inline_jobs] == true Sidekiq::Testing.inline! else Sidekiq::Testing.fake! @@ -137,7 +137,7 @@ def sign_in(resource, _deprecated = nil, scope: nil) end config.before do |example| - unless example.metadata[:paperclip_processing] + unless example.metadata[:attachment_processing] allow_any_instance_of(Paperclip::Attachment).to receive(:post_process).and_return(true) # rubocop:disable RSpec/AnyInstance end end @@ -161,6 +161,7 @@ def sign_in(resource, _deprecated = nil, scope: nil) end RSpec::Matchers.define_negated_matcher :not_change, :change +RSpec::Matchers.define_negated_matcher :not_eq, :eq RSpec::Matchers.define_negated_matcher :not_include, :include def request_fixture(name) diff --git a/spec/requests/api/v1/accounts/statuses_spec.rb b/spec/requests/api/v1/accounts/statuses_spec.rb index 371867b21572c4..97cdbe0156f7b0 100644 --- a/spec/requests/api/v1/accounts/statuses_spec.rb +++ b/spec/requests/api/v1/accounts/statuses_spec.rb @@ -10,12 +10,15 @@ describe 'GET /api/v1/accounts/:account_id/statuses' do it 'returns expected headers', :aggregate_failures do - Fabricate(:status, account: user.account) + status = Fabricate(:status, account: user.account) get "/api/v1/accounts/#{user.account.id}/statuses", params: { limit: 1 }, headers: headers - expect(response).to have_http_status(200) - expect(links_from_header.size) - .to eq(2) + expect(response) + .to have_http_status(200) + .and include_pagination_headers( + prev: api_v1_account_statuses_url(limit: 1, min_id: status.id), + next: api_v1_account_statuses_url(limit: 1, max_id: status.id) + ) end context 'with only media' do @@ -55,16 +58,9 @@ it 'returns http success and includes a header link' do get "/api/v1/accounts/#{user.account.id}/statuses", params: { pinned: true }, headers: headers - expect(response).to have_http_status(200) - expect(links_from_header.size) - .to eq(1) - expect(links_from_header) - .to contain_exactly( - have_attributes( - href: /pinned=true/, - attr_pairs: contain_exactly(['rel', 'prev']) - ) - ) + expect(response) + .to have_http_status(200) + .and include_pagination_headers(prev: api_v1_account_statuses_url(pinned: true, min_id: Status.first.id)) end end @@ -77,19 +73,11 @@ it 'returns http success and header pagination links to prev and next' do get "/api/v1/accounts/#{user.account.id}/statuses", params: { pinned: true }, headers: headers - expect(response).to have_http_status(200) - expect(links_from_header.size) - .to eq(2) - expect(links_from_header) - .to contain_exactly( - have_attributes( - href: /pinned=true/, - attr_pairs: contain_exactly(['rel', 'next']) - ), - have_attributes( - href: /pinned=true/, - attr_pairs: contain_exactly(['rel', 'prev']) - ) + expect(response) + .to have_http_status(200) + .and include_pagination_headers( + prev: api_v1_account_statuses_url(pinned: true, min_id: Status.first.id), + next: api_v1_account_statuses_url(pinned: true, max_id: Status.first.id) ) end end @@ -138,12 +126,4 @@ end end end - - private - - def links_from_header - response - .headers['Link'] - .links - end end diff --git a/spec/requests/api/v1/admin/account_actions_spec.rb b/spec/requests/api/v1/admin/account_actions_spec.rb index 778658508ec100..5bcf809401da4c 100644 --- a/spec/requests/api/v1/admin/account_actions_spec.rb +++ b/spec/requests/api/v1/admin/account_actions_spec.rb @@ -10,7 +10,7 @@ let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } shared_examples 'a successful notification delivery' do - it 'notifies the user about the action taken', :sidekiq_inline do + it 'notifies the user about the action taken', :inline_jobs do emails = capture_emails { subject } expect(emails.size) diff --git a/spec/requests/api/v1/conversations_spec.rb b/spec/requests/api/v1/conversations_spec.rb index caa0f5c52c0975..f136e1f4e84dfd 100644 --- a/spec/requests/api/v1/conversations_spec.rb +++ b/spec/requests/api/v1/conversations_spec.rb @@ -10,7 +10,7 @@ let(:other) { Fabricate(:user) } - describe 'GET /api/v1/conversations', :sidekiq_inline do + describe 'GET /api/v1/conversations', :inline_jobs do before do user.account.follow!(other.account) PostStatusService.new.call(other.account, text: 'Hey @alice', visibility: 'direct') @@ -20,8 +20,12 @@ it 'returns pagination headers', :aggregate_failures do get '/api/v1/conversations', params: { limit: 1 }, headers: headers - expect(response).to have_http_status(200) - expect(response.headers['Link'].links.size).to eq(2) + expect(response) + .to have_http_status(200) + .and include_pagination_headers( + prev: api_v1_conversations_url(limit: 1, min_id: Status.first.id), + next: api_v1_conversations_url(limit: 1, max_id: Status.first.id) + ) end it 'returns conversations', :aggregate_failures do diff --git a/spec/requests/api/v1/featured_tags_spec.rb b/spec/requests/api/v1/featured_tags_spec.rb index f499dd1d09a4d5..4b9698870411aa 100644 --- a/spec/requests/api/v1/featured_tags_spec.rb +++ b/spec/requests/api/v1/featured_tags_spec.rb @@ -147,7 +147,7 @@ expect(body).to be_empty end - it 'deletes the featured tag', :sidekiq_inline do + it 'deletes the featured tag', :inline_jobs do delete "/api/v1/featured_tags/#{id}", headers: headers featured_tag = FeaturedTag.find_by(id: id) diff --git a/spec/requests/api/v1/media_spec.rb b/spec/requests/api/v1/media_spec.rb index 26c76b9c5b98f6..c89c49afdf43aa 100644 --- a/spec/requests/api/v1/media_spec.rb +++ b/spec/requests/api/v1/media_spec.rb @@ -121,19 +121,19 @@ end end - context 'with image/jpeg', :paperclip_processing do + context 'with image/jpeg', :attachment_processing do let(:params) { { file: fixture_file_upload('attachment.jpg', 'image/jpeg'), description: 'jpeg image' } } it_behaves_like 'a successful media upload', 'image' end - context 'with image/gif', :paperclip_processing do + context 'with image/gif', :attachment_processing do let(:params) { { file: fixture_file_upload('attachment.gif', 'image/gif') } } it_behaves_like 'a successful media upload', 'image' end - context 'with video/webm', :paperclip_processing do + context 'with video/webm', :attachment_processing do let(:params) { { file: fixture_file_upload('attachment.webm', 'video/webm') } } it_behaves_like 'a successful media upload', 'gifv' diff --git a/spec/requests/api/v1/notifications/policies_spec.rb b/spec/requests/api/v1/notifications/policies_spec.rb index d02d2ed0d7b27d..cbd4499772d443 100644 --- a/spec/requests/api/v1/notifications/policies_spec.rb +++ b/spec/requests/api/v1/notifications/policies_spec.rb @@ -8,7 +8,7 @@ let(:scopes) { 'read:notifications write:notifications' } let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - describe 'GET /api/v1/notifications/policy', :sidekiq_inline do + describe 'GET /api/v1/notifications/policy', :inline_jobs do subject do get '/api/v1/notifications/policy', headers: headers, params: params end diff --git a/spec/requests/api/v1/notifications/requests_spec.rb b/spec/requests/api/v1/notifications/requests_spec.rb index 772402a6b5a089..d3a9753246a2ec 100644 --- a/spec/requests/api/v1/notifications/requests_spec.rb +++ b/spec/requests/api/v1/notifications/requests_spec.rb @@ -8,7 +8,7 @@ let(:scopes) { 'read:notifications write:notifications' } let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - describe 'GET /api/v1/notifications/requests', :sidekiq_inline do + describe 'GET /api/v1/notifications/requests', :inline_jobs do subject do get '/api/v1/notifications/requests', headers: headers, params: params end @@ -17,7 +17,6 @@ before do Fabricate(:notification_request, account: user.account) - Fabricate(:notification_request, account: user.account, dismissed: true) end it_behaves_like 'forbidden for wrong scope', 'write write:notifications' @@ -29,16 +28,6 @@ expect(response).to have_http_status(200) end end - - context 'with dismissed' do - let(:params) { { dismissed: '1' } } - - it 'returns http success', :aggregate_failures do - subject - - expect(response).to have_http_status(200) - end - end end describe 'POST /api/v1/notifications/requests/:id/accept' do @@ -78,15 +67,14 @@ post "/api/v1/notifications/requests/#{notification_request.id}/dismiss", headers: headers end - let(:notification_request) { Fabricate(:notification_request, account: user.account) } + let!(:notification_request) { Fabricate(:notification_request, account: user.account) } it_behaves_like 'forbidden for wrong scope', 'read read:notifications' - it 'returns http success and dismisses the notification request', :aggregate_failures do - subject + it 'returns http success and destroys the notification request', :aggregate_failures do + expect { subject }.to change(NotificationRequest, :count).by(-1) expect(response).to have_http_status(200) - expect(notification_request.reload.dismissed?).to be true end context 'when notification request belongs to someone else' do diff --git a/spec/requests/api/v1/notifications_spec.rb b/spec/requests/api/v1/notifications_spec.rb index 55d3cdac948896..c9034c17dcbd97 100644 --- a/spec/requests/api/v1/notifications_spec.rb +++ b/spec/requests/api/v1/notifications_spec.rb @@ -8,7 +8,7 @@ let(:scopes) { 'read:notifications write:notifications' } let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - describe 'GET /api/v1/notifications', :sidekiq_inline do + describe 'GET /api/v1/notifications', :inline_jobs do subject do get '/api/v1/notifications', headers: headers, params: params end @@ -20,8 +20,8 @@ before do first_status = PostStatusService.new.call(user.account, text: 'Test') ReblogService.new.call(bob.account, first_status) - mentioning_status = PostStatusService.new.call(bob.account, text: 'Hello @alice') - mentioning_status.mentions.first + PostStatusService.new.call(bob.account, text: 'Hello @alice') + PostStatusService.new.call(tom.account, text: 'Hello @alice', visibility: :direct) # Filtered by default FavouriteService.new.call(bob.account, first_status) FavouriteService.new.call(tom.account, first_status) FollowService.new.call(bob.account, user.account) @@ -34,10 +34,22 @@ subject expect(response).to have_http_status(200) - expect(body_json_types).to include 'reblog' - expect(body_json_types).to include 'mention' - expect(body_json_types).to include 'favourite' - expect(body_json_types).to include 'follow' + expect(body_as_json.size).to eq 5 + expect(body_json_types).to include('reblog', 'mention', 'favourite', 'follow') + expect(body_as_json.any? { |x| x[:filtered] }).to be false + end + end + + context 'with include_filtered' do + let(:params) { { include_filtered: true } } + + it 'returns expected notification types, including filtered notifications' do + subject + + expect(response).to have_http_status(200) + expect(body_as_json.size).to eq 6 + expect(body_json_types).to include('reblog', 'mention', 'favourite', 'follow') + expect(body_as_json.any? { |x| x[:filtered] }).to be true end end @@ -96,7 +108,7 @@ def body_json_account_ids it 'returns the requested number of notifications paginated', :aggregate_failures do subject - notifications = user.account.notifications + notifications = user.account.notifications.browserable expect(body_as_json.size) .to eq(params[:limit]) diff --git a/spec/requests/api/v1/polls/votes_spec.rb b/spec/requests/api/v1/polls/votes_spec.rb index e2b22708be8720..669f64b6e4577e 100644 --- a/spec/requests/api/v1/polls/votes_spec.rb +++ b/spec/requests/api/v1/polls/votes_spec.rb @@ -10,9 +10,10 @@ describe 'POST /api/v1/polls/:poll_id/votes' do let(:poll) { Fabricate(:poll) } + let(:params) { { choices: %w(1) } } before do - post "/api/v1/polls/#{poll.id}/votes", params: { choices: %w(1) }, headers: headers + post "/api/v1/polls/#{poll.id}/votes", params: params, headers: headers end it 'creates a vote', :aggregate_failures do @@ -24,6 +25,14 @@ expect(poll.reload.cached_tallies).to eq [0, 1] end + context 'when the required choices param is not provided' do + let(:params) { {} } + + it 'returns http bad request' do + expect(response).to have_http_status(400) + end + end + private def vote diff --git a/spec/requests/api/v1/reports_spec.rb b/spec/requests/api/v1/reports_spec.rb index 9e8954a4c65dd8..a72d9bbcd85bbb 100644 --- a/spec/requests/api/v1/reports_spec.rb +++ b/spec/requests/api/v1/reports_spec.rb @@ -33,7 +33,7 @@ it_behaves_like 'forbidden for wrong scope', 'read read:reports' - it 'creates a report', :aggregate_failures, :sidekiq_inline do + it 'creates a report', :aggregate_failures, :inline_jobs do emails = capture_emails { subject } expect(response).to have_http_status(200) @@ -47,6 +47,7 @@ expect(target_account.targeted_reports).to_not be_empty expect(target_account.targeted_reports.first.comment).to eq 'reasons' + expect(target_account.targeted_reports.first.application).to eq token.application expect(emails.size) .to eq(1) diff --git a/spec/requests/api/v1/statuses/favourited_by_accounts_spec.rb b/spec/requests/api/v1/statuses/favourited_by_accounts_spec.rb index 44296f4c37e5d5..2fd79f424b12b6 100644 --- a/spec/requests/api/v1/statuses/favourited_by_accounts_spec.rb +++ b/spec/requests/api/v1/statuses/favourited_by_accounts_spec.rb @@ -29,8 +29,10 @@ expect(response) .to have_http_status(200) - expect(response.headers['Link'].links.size) - .to eq(2) + .and include_pagination_headers( + prev: api_v1_status_favourited_by_index_url(limit: 2, since_id: Favourite.last.id), + next: api_v1_status_favourited_by_index_url(limit: 2, max_id: Favourite.first.id) + ) expect(body_as_json.size) .to eq(2) diff --git a/spec/requests/api/v1/statuses/favourites_spec.rb b/spec/requests/api/v1/statuses/favourites_spec.rb index 033aed7e285ddc..22d0e4831fc64d 100644 --- a/spec/requests/api/v1/statuses/favourites_spec.rb +++ b/spec/requests/api/v1/statuses/favourites_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'Favourites', :sidekiq_inline do +RSpec.describe 'Favourites', :inline_jobs do let(:user) { Fabricate(:user) } let(:scopes) { 'write:favourites' } let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } diff --git a/spec/requests/api/v1/statuses/reblogged_by_accounts_spec.rb b/spec/requests/api/v1/statuses/reblogged_by_accounts_spec.rb index 6f99ce94646670..5fc54042f91a8f 100644 --- a/spec/requests/api/v1/statuses/reblogged_by_accounts_spec.rb +++ b/spec/requests/api/v1/statuses/reblogged_by_accounts_spec.rb @@ -28,8 +28,10 @@ expect(response) .to have_http_status(200) - expect(response.headers['Link'].links.size) - .to eq(2) + .and include_pagination_headers( + prev: api_v1_status_reblogged_by_index_url(limit: 2, since_id: bob.statuses.first.id), + next: api_v1_status_reblogged_by_index_url(limit: 2, max_id: alice.statuses.first.id) + ) expect(body_as_json.size) .to eq(2) diff --git a/spec/requests/api/v1/statuses/reblogs_spec.rb b/spec/requests/api/v1/statuses/reblogs_spec.rb index cf0a1f861d9bde..503d804ed01c0b 100644 --- a/spec/requests/api/v1/statuses/reblogs_spec.rb +++ b/spec/requests/api/v1/statuses/reblogs_spec.rb @@ -41,7 +41,7 @@ end end - describe 'POST /api/v1/statuses/:status_id/unreblog', :sidekiq_inline do + describe 'POST /api/v1/statuses/:status_id/unreblog', :inline_jobs do context 'with public status' do let(:status) { Fabricate(:status, account: user.account) } diff --git a/spec/requests/api/v1/timelines/home_spec.rb b/spec/requests/api/v1/timelines/home_spec.rb index 2bebe8cf452847..96bd153affe5a4 100644 --- a/spec/requests/api/v1/timelines/home_spec.rb +++ b/spec/requests/api/v1/timelines/home_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -describe 'Home', :sidekiq_inline do +describe 'Home', :inline_jobs do let(:user) { Fabricate(:user) } let(:scopes) { 'read:statuses' } let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } diff --git a/spec/requests/api/v2/admin/accounts_spec.rb b/spec/requests/api/v2/admin/accounts_spec.rb index f5db93233c2012..8f52c6a6134ed6 100644 --- a/spec/requests/api/v2/admin/accounts_spec.rb +++ b/spec/requests/api/v2/admin/accounts_spec.rb @@ -83,7 +83,8 @@ def body_json_ids let(:params) { { limit: 1 } } it 'sets the correct pagination headers' do - expect(response.headers['Link'].find_link(%w(rel next)).href).to eq api_v2_admin_accounts_url(limit: 1, max_id: admin_account.id) + expect(response) + .to include_pagination_headers(next: api_v2_admin_accounts_url(limit: 1, max_id: admin_account.id)) end end end diff --git a/spec/requests/api/v2/media_spec.rb b/spec/requests/api/v2/media_spec.rb index 990fa5d0baeeab..97540413f152d4 100644 --- a/spec/requests/api/v2/media_spec.rb +++ b/spec/requests/api/v2/media_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe 'Media API', :paperclip_processing do +RSpec.describe 'Media API', :attachment_processing do let(:user) { Fabricate(:user) } let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } let(:scopes) { 'write' } diff --git a/spec/requests/api/v2_alpha/notifications_spec.rb b/spec/requests/api/v2_alpha/notifications_spec.rb index ac44605ac5d212..104651ebe39f44 100644 --- a/spec/requests/api/v2_alpha/notifications_spec.rb +++ b/spec/requests/api/v2_alpha/notifications_spec.rb @@ -8,7 +8,7 @@ let(:scopes) { 'read:notifications write:notifications' } let(:headers) { { 'Authorization' => "Bearer #{token.token}" } } - describe 'GET /api/v2_alpha/notifications', :sidekiq_inline do + describe 'GET /api/v2_alpha/notifications', :inline_jobs do subject do get '/api/v2_alpha/notifications', headers: headers, params: params end diff --git a/spec/search/models/concerns/account/statuses_search_spec.rb b/spec/search/models/concerns/account/statuses_search_spec.rb index a1b0bf405c5133..b1bf4968ca9abd 100644 --- a/spec/search/models/concerns/account/statuses_search_spec.rb +++ b/spec/search/models/concerns/account/statuses_search_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -describe Account::StatusesSearch, :sidekiq_inline do +describe Account::StatusesSearch, :inline_jobs do describe 'a non-indexable account becoming indexable' do let(:account) { Account.find_by(username: 'search_test_account_1') } diff --git a/spec/services/activitypub/fetch_remote_status_service_spec.rb b/spec/services/activitypub/fetch_remote_status_service_spec.rb index a86f141fe0b747..635fcb7976c954 100644 --- a/spec/services/activitypub/fetch_remote_status_service_spec.rb +++ b/spec/services/activitypub/fetch_remote_status_service_spec.rb @@ -225,9 +225,9 @@ end end - context 'with statuses referencing other statuses', :sidekiq_inline do + context 'with statuses referencing other statuses', :inline_jobs do before do - stub_const 'ActivityPub::FetchRemoteStatusService::DISCOVERIES_PER_REQUEST', 5 + stub_const 'ActivityPub::FetchRemoteStatusService::DISCOVERIES_PER_REQUEST', 3 end context 'when using inReplyTo' do @@ -243,7 +243,7 @@ end before do - 8.times do |i| + 5.times do |i| status_json = { '@context': 'https://www.w3.org/ns/activitystreams', id: "https://foo.bar/@foo/#{i}", @@ -257,12 +257,10 @@ end end - it 'creates at least some statuses' do - expect { subject.call(object[:id], prefetched_body: Oj.dump(object)) }.to change { sender.statuses.count }.by_at_least(2) - end - - it 'creates no more account than the limit allows' do - expect { subject.call(object[:id], prefetched_body: Oj.dump(object)) }.to change { sender.statuses.count }.by_at_most(5) + it 'creates statuses but not more than limit allows' do + expect { subject.call(object[:id], prefetched_body: Oj.dump(object)) } + .to change { sender.statuses.count }.by_at_least(2) + .and change { sender.statuses.count }.by_at_most(3) end end @@ -287,7 +285,7 @@ end before do - 8.times do |i| + 5.times do |i| status_json = { '@context': 'https://www.w3.org/ns/activitystreams', id: "https://foo.bar/@foo/#{i}", @@ -309,12 +307,10 @@ end end - it 'creates at least some statuses' do - expect { subject.call(object[:id], prefetched_body: Oj.dump(object)) }.to change { sender.statuses.count }.by_at_least(2) - end - - it 'creates no more account than the limit allows' do - expect { subject.call(object[:id], prefetched_body: Oj.dump(object)) }.to change { sender.statuses.count }.by_at_most(5) + it 'creates statuses but not more than limit allows' do + expect { subject.call(object[:id], prefetched_body: Oj.dump(object)) } + .to change { sender.statuses.count }.by_at_least(2) + .and change { sender.statuses.count }.by_at_most(3) end end end diff --git a/spec/services/activitypub/process_account_service_spec.rb b/spec/services/activitypub/process_account_service_spec.rb index 8b80dafe45a924..4fbb527b39041e 100644 --- a/spec/services/activitypub/process_account_service_spec.rb +++ b/spec/services/activitypub/process_account_service_spec.rb @@ -224,7 +224,7 @@ end end - it 'creates accounts without exceeding rate limit', :sidekiq_inline do + it 'creates accounts without exceeding rate limit', :inline_jobs do expect { subject.call('user1', 'foo.test', payload) } .to create_some_remote_accounts .and create_fewer_than_rate_limit_accounts diff --git a/spec/services/activitypub/process_status_update_service_spec.rb b/spec/services/activitypub/process_status_update_service_spec.rb index e451d15dc0359c..a97e8408026b7c 100644 --- a/spec/services/activitypub/process_status_update_service_spec.rb +++ b/spec/services/activitypub/process_status_update_service_spec.rb @@ -40,14 +40,13 @@ def poll_option_json(name, votes) end describe '#call' do - it 'updates text' do + it 'updates text and content warning' do subject.call(status, json, json) - expect(status.reload.text).to eq 'Hello universe' - end - - it 'updates content warning' do - subject.call(status, json, json) - expect(status.reload.spoiler_text).to eq 'Show more' + expect(status.reload) + .to have_attributes( + text: eq('Hello universe'), + spoiler_text: eq('Show more') + ) end context 'when the changes are only in sanitized-out HTML' do @@ -67,12 +66,9 @@ def poll_option_json(name, votes) subject.call(status, json, json) end - it 'does not create any edits' do + it 'does not create any edits and does not mark status edited' do expect(status.reload.edits).to be_empty - end - - it 'does not mark status as edited' do - expect(status.edited?).to be false + expect(status).to_not be_edited end end @@ -90,15 +86,9 @@ def poll_option_json(name, votes) subject.call(status, json, json) end - it 'does not create any edits' do + it 'does not create any edits, mark status edited, or update text' do expect(status.reload.edits).to be_empty - end - - it 'does not mark status as edited' do - expect(status.reload.edited?).to be false - end - - it 'does not update the text' do + expect(status.reload).to_not be_edited expect(status.reload.text).to eq 'Hello world' end end @@ -137,19 +127,10 @@ def poll_option_json(name, votes) subject.call(status, json, json) end - it 'does not create any edits' do + it 'does not create any edits, mark status edited, update text but does update tallies' do expect(status.reload.edits).to be_empty - end - - it 'does not mark status as edited' do - expect(status.reload.edited?).to be false - end - - it 'does not update the text' do + expect(status.reload).to_not be_edited expect(status.reload.text).to eq 'Hello world' - end - - it 'updates tallies' do expect(status.poll.reload.cached_tallies).to eq [4, 3] end end @@ -189,19 +170,10 @@ def poll_option_json(name, votes) subject.call(status, json, json) end - it 'does not create any edits' do + it 'does not create any edits, mark status edited, update text, or update tallies' do expect(status.reload.edits).to be_empty - end - - it 'does not mark status as edited' do - expect(status.reload.edited?).to be false - end - - it 'does not update the text' do + expect(status.reload).to_not be_edited expect(status.reload.text).to eq 'Hello world' - end - - it 'does not update tallies' do expect(status.poll.reload.cached_tallies).to eq [0, 0] end end @@ -213,13 +185,10 @@ def poll_option_json(name, votes) status.snapshot!(rate_limit: false) end - it 'does not create any edits' do - expect { subject.call(status, json, json) }.to_not(change { status.reload.edits.pluck(&:id) }) - end - - it 'does not update the text, spoiler_text or edited_at' do + it 'does not create any edits or update relevant attributes' do expect { subject.call(status, json, json) } - .to_not(change { status.reload.attributes.slice('text', 'spoiler_text', 'edited_at').values }) + .to not_change { status.reload.edits.pluck(&:id) } + .and(not_change { status.reload.attributes.slice('text', 'spoiler_text', 'edited_at').values }) end end @@ -237,12 +206,9 @@ def poll_option_json(name, votes) subject.call(status, json, json) end - it 'does not create any edits' do + it 'does not create any edits or mark status edited' do expect(status.reload.edits).to be_empty - end - - it 'does not mark status as edited' do - expect(status.edited?).to be false + expect(status).to_not be_edited end end @@ -261,12 +227,9 @@ def poll_option_json(name, votes) subject.call(status, json, json) end - it 'does not create any edits' do + it 'does not create any edits or mark status edited' do expect(status.reload.edits).to be_empty - end - - it 'does not mark status as edited' do - expect(status.edited?).to be false + expect(status).to_not be_edited end end @@ -412,11 +375,8 @@ def poll_option_json(name, votes) subject.call(status, json, json) end - it 'removes poll' do + it 'removes poll and records media change in edit' do expect(status.reload.poll).to be_nil - end - - it 'records media change in edit' do expect(status.edits.reload.last.poll_options).to be_nil end end @@ -442,26 +402,21 @@ def poll_option_json(name, votes) subject.call(status, json, json) end - it 'creates a poll' do + it 'creates a poll and records media change in edit' do poll = status.reload.poll expect(poll).to_not be_nil expect(poll.options).to eq %w(Foo Bar Baz) - end - - it 'records media change in edit' do expect(status.edits.reload.last.poll_options).to eq %w(Foo Bar Baz) end end - it 'creates edit history' do - subject.call(status, json, json) - expect(status.edits.reload.map(&:text)).to eq ['Hello world', 'Hello universe'] - end - - it 'sets edited timestamp' do + it 'creates edit history and sets edit timestamp' do subject.call(status, json, json) - expect(status.reload.edited_at.to_s).to eq '2021-09-08 22:39:25 UTC' + expect(status.edits.reload.map(&:text)) + .to eq ['Hello world', 'Hello universe'] + expect(status.reload.edited_at.to_s) + .to eq '2021-09-08 22:39:25 UTC' end end end diff --git a/spec/services/activitypub/synchronize_followers_service_spec.rb b/spec/services/activitypub/synchronize_followers_service_spec.rb index 648f9a33212c3e..974368b7d77e79 100644 --- a/spec/services/activitypub/synchronize_followers_service_spec.rb +++ b/spec/services/activitypub/synchronize_followers_service_spec.rb @@ -13,11 +13,9 @@ let(:collection_uri) { 'http://example.com/partial-followers' } let(:items) do - [ - ActivityPub::TagManager.instance.uri_for(alice), - ActivityPub::TagManager.instance.uri_for(eve), - ActivityPub::TagManager.instance.uri_for(mallory), - ] + [alice, eve, mallory].map do |account| + ActivityPub::TagManager.instance.uri_for(account) + end end let(:payload) do @@ -40,20 +38,15 @@ subject.call(actor, collection_uri) end - it 'keeps expected followers' do - expect(alice.following?(actor)).to be true - end - - it 'removes local followers not in the remote list' do - expect(bob.following?(actor)).to be false - end - - it 'converts follow requests to follow relationships when they have been accepted' do - expect(mallory.following?(actor)).to be true - end - - it 'sends an Undo Follow to the actor' do - expect(ActivityPub::DeliveryWorker).to have_received(:perform_async).with(anything, eve.id, actor.inbox_url) + it 'maintains following records and sends Undo Follow to actor' do + expect(alice) + .to be_following(actor) # Keep expected followers + expect(bob) + .to_not be_following(actor) # Remove local followers not in remote list + expect(mallory) + .to be_following(actor) # Convert follow request to follow when accepted + expect(ActivityPub::DeliveryWorker) + .to have_received(:perform_async).with(anything, eve.id, actor.inbox_url) # Send Undo Follow to actor end end diff --git a/spec/services/appeal_service_spec.rb b/spec/services/appeal_service_spec.rb index 3fad74db9d8951..6a47bb2cea61d2 100644 --- a/spec/services/appeal_service_spec.rb +++ b/spec/services/appeal_service_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe AppealService, :sidekiq_inline do +RSpec.describe AppealService, :inline_jobs do describe '#call' do let!(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) } diff --git a/spec/services/authorize_follow_service_spec.rb b/spec/services/authorize_follow_service_spec.rb index be2a8641854054..533b791fb7f6e7 100644 --- a/spec/services/authorize_follow_service_spec.rb +++ b/spec/services/authorize_follow_service_spec.rb @@ -41,7 +41,7 @@ expect(bob.following?(sender)).to be true end - it 'sends an accept activity', :sidekiq_inline do + it 'sends an accept activity', :inline_jobs do expect(a_request(:post, bob.inbox_url)).to have_been_made.once end end diff --git a/spec/services/batched_remove_status_service_spec.rb b/spec/services/batched_remove_status_service_spec.rb index e501b9ba84a94c..628bb198ef06f3 100644 --- a/spec/services/batched_remove_status_service_spec.rb +++ b/spec/services/batched_remove_status_service_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe BatchedRemoveStatusService, :sidekiq_inline do +RSpec.describe BatchedRemoveStatusService, :inline_jobs do subject { described_class.new } let!(:alice) { Fabricate(:account) } diff --git a/spec/services/block_domain_service_spec.rb b/spec/services/block_domain_service_spec.rb index d4f0c042d453c9..839137db4498e8 100644 --- a/spec/services/block_domain_service_spec.rb +++ b/spec/services/block_domain_service_spec.rb @@ -49,7 +49,7 @@ end describe 'for a silence with reject media' do - it 'does not mark the domain as blocked, but silences accounts with an appropriate silencing date, clears media', :aggregate_failures, :sidekiq_inline do + it 'does not mark the domain as blocked, but silences accounts with an appropriate silencing date, clears media', :aggregate_failures, :inline_jobs do subject.call(DomainBlock.create!(domain: 'evil.org', severity: :silence, reject_media: true)) expect(DomainBlock.blocked?('evil.org')).to be false diff --git a/spec/services/block_service_spec.rb b/spec/services/block_service_spec.rb index d096aa1ea35566..46dd69198699a4 100644 --- a/spec/services/block_service_spec.rb +++ b/spec/services/block_service_spec.rb @@ -33,7 +33,7 @@ expect(sender.blocking?(bob)).to be true end - it 'sends a block activity', :sidekiq_inline do + it 'sends a block activity', :inline_jobs do expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once end end diff --git a/spec/services/delete_account_service_spec.rb b/spec/services/delete_account_service_spec.rb index de93862435afbe..741ac340cfa0be 100644 --- a/spec/services/delete_account_service_spec.rb +++ b/spec/services/delete_account_service_spec.rb @@ -62,7 +62,7 @@ def expect_deletion_of_associated_target_notifications end end - describe '#call on local account', :sidekiq_inline do + describe '#call on local account', :inline_jobs do before do stub_request(:post, remote_alice.inbox_url).to_return(status: 201) stub_request(:post, remote_bob.inbox_url).to_return(status: 201) @@ -83,7 +83,7 @@ def expect_deletion_of_associated_target_notifications end end - describe '#call on remote account', :sidekiq_inline do + describe '#call on remote account', :inline_jobs do before do stub_request(:post, account.inbox_url).to_return(status: 201) end diff --git a/spec/services/fan_out_on_write_service_spec.rb b/spec/services/fan_out_on_write_service_spec.rb index b51d802a5b9ae2..c6dd020cdff4b6 100644 --- a/spec/services/fan_out_on_write_service_spec.rb +++ b/spec/services/fan_out_on_write_service_spec.rb @@ -34,21 +34,14 @@ def home_feed_of(account) context 'when status is public' do let(:visibility) { 'public' } - it 'is added to the home feed of its author' do - expect(home_feed_of(alice)).to include status.id - end - - it 'is added to the home feed of a follower', :sidekiq_inline do - expect(home_feed_of(bob)).to include status.id - expect(home_feed_of(tom)).to include status.id - end + it 'adds status to home feed of author and followers and broadcasts', :inline_jobs do + expect(status.id) + .to be_in(home_feed_of(alice)) + .and be_in(home_feed_of(bob)) + .and be_in(home_feed_of(tom)) - it 'is broadcast to the hashtag stream' do expect(redis).to have_received(:publish).with('timeline:hashtag:hoge', anything) expect(redis).to have_received(:publish).with('timeline:hashtag:hoge:local', anything) - end - - it 'is broadcast to the public stream' do expect(redis).to have_received(:publish).with('timeline:public', anything) expect(redis).to have_received(:publish).with('timeline:public:local', anything) expect(redis).to have_received(:publish).with('timeline:public:media', anything) @@ -58,60 +51,41 @@ def home_feed_of(account) context 'when status is limited' do let(:visibility) { 'limited' } - it 'is added to the home feed of its author' do - expect(home_feed_of(alice)).to include status.id - end - - it 'is added to the home feed of the mentioned follower', :sidekiq_inline do - expect(home_feed_of(bob)).to include status.id - end - - it 'is not added to the home feed of the other follower' do - expect(home_feed_of(tom)).to_not include status.id - end + it 'adds status to home feed of author and mentioned followers and does not broadcast', :inline_jobs do + expect(status.id) + .to be_in(home_feed_of(alice)) + .and be_in(home_feed_of(bob)) + expect(status.id) + .to_not be_in(home_feed_of(tom)) - it 'is not broadcast publicly' do - expect(redis).to_not have_received(:publish).with('timeline:hashtag:hoge', anything) - expect(redis).to_not have_received(:publish).with('timeline:public', anything) + expect_no_broadcasting end end context 'when status is private' do let(:visibility) { 'private' } - it 'is added to the home feed of its author' do - expect(home_feed_of(alice)).to include status.id - end - - it 'is added to the home feed of a follower', :sidekiq_inline do - expect(home_feed_of(bob)).to include status.id - expect(home_feed_of(tom)).to include status.id - end + it 'adds status to home feed of author and followers and does not broadcast', :inline_jobs do + expect(status.id) + .to be_in(home_feed_of(alice)) + .and be_in(home_feed_of(bob)) + .and be_in(home_feed_of(tom)) - it 'is not broadcast publicly' do - expect(redis).to_not have_received(:publish).with('timeline:hashtag:hoge', anything) - expect(redis).to_not have_received(:publish).with('timeline:public', anything) + expect_no_broadcasting end end context 'when status is direct' do let(:visibility) { 'direct' } - it 'is added to the home feed of its author' do - expect(home_feed_of(alice)).to include status.id - end - - it 'is added to the home feed of the mentioned follower', :sidekiq_inline do - expect(home_feed_of(bob)).to include status.id - end - - it 'is not added to the home feed of the other follower' do - expect(home_feed_of(tom)).to_not include status.id - end + it 'is added to the home feed of its author and mentioned followers and does not broadcast', :inline_jobs do + expect(status.id) + .to be_in(home_feed_of(alice)) + .and be_in(home_feed_of(bob)) + expect(status.id) + .to_not be_in(home_feed_of(tom)) - it 'is not broadcast publicly' do - expect(redis).to_not have_received(:publish).with('timeline:hashtag:hoge', anything) - expect(redis).to_not have_received(:publish).with('timeline:public', anything) + expect_no_broadcasting end context 'when handling status updates' do @@ -131,4 +105,13 @@ def home_feed_of(account) end end end + + def expect_no_broadcasting + expect(redis) + .to_not have_received(:publish) + .with('timeline:hashtag:hoge', anything) + expect(redis) + .to_not have_received(:publish) + .with('timeline:public', anything) + end end diff --git a/spec/services/favourite_service_spec.rb b/spec/services/favourite_service_spec.rb index d0f1ff17c1ebd9..c39362def2f7f3 100644 --- a/spec/services/favourite_service_spec.rb +++ b/spec/services/favourite_service_spec.rb @@ -33,7 +33,7 @@ expect(status.favourites.first).to_not be_nil end - it 'sends a like activity', :sidekiq_inline do + it 'sends a like activity', :inline_jobs do expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once end end diff --git a/spec/services/fetch_link_card_service_spec.rb b/spec/services/fetch_link_card_service_spec.rb index d83a5275149962..2f64f405583955 100644 --- a/spec/services/fetch_link_card_service_spec.rb +++ b/spec/services/fetch_link_card_service_spec.rb @@ -27,7 +27,12 @@ stub_request(:get, 'http://example.com/koi8-r').to_return(request_fixture('koi8-r.txt')) stub_request(:get, 'http://example.com/windows-1251').to_return(request_fixture('windows-1251.txt')) stub_request(:get, 'http://example.com/low_confidence_latin1').to_return(request_fixture('low_confidence_latin1.txt')) + stub_request(:get, 'http://example.com/latin1_posing_as_utf8_broken').to_return(request_fixture('latin1_posing_as_utf8_broken.txt')) + stub_request(:get, 'http://example.com/latin1_posing_as_utf8_recoverable').to_return(request_fixture('latin1_posing_as_utf8_recoverable.txt')) stub_request(:get, 'http://example.com/aergerliche-umlaute').to_return(request_fixture('redirect_with_utf8_url.txt')) + stub_request(:get, 'http://example.com/page_without_title').to_return(request_fixture('page_without_title.txt')) + stub_request(:get, 'http://example.com/long_canonical_url').to_return(request_fixture('long_canonical_url.txt')) + stub_request(:get, 'http://example.com/alternative_utf8_spelling_in_header').to_return(request_fixture('alternative_utf8_spelling_in_header.txt')) Rails.cache.write('oembed_endpoint:example.com', oembed_cache) if oembed_cache @@ -110,6 +115,14 @@ end end + context 'with a page that has no title' do + let(:status) { Fabricate(:status, text: 'http://example.com/page_without_title') } + + it 'does not create a preview card' do + expect(status.preview_card).to be_nil + end + end + context 'with a 404 URL' do let(:status) { Fabricate(:status, text: 'http://example.com/not-found') } @@ -159,10 +172,30 @@ end context 'with a URL of a page in ISO-8859-1 encoding, that charlock_holmes cannot detect' do - let(:status) { Fabricate(:status, text: 'Check out http://example.com/low_confidence_latin1') } + context 'when encoding in http header is correct' do + let(:status) { Fabricate(:status, text: 'Check out http://example.com/low_confidence_latin1') } - it 'decodes the HTML' do - expect(status.preview_card.title).to eq("Tofu Ă¡ l'orange") + it 'decodes the HTML' do + expect(status.preview_card.title).to eq("Tofu Ă¡ l'orange") + end + end + + context 'when encoding in http header is incorrect' do + context 'when encoding problems appear in unrelated tags' do + let(:status) { Fabricate(:status, text: 'Check out http://example.com/latin1_posing_as_utf8_recoverable') } + + it 'decodes the HTML' do + expect(status.preview_card.title).to eq('Tofu with orange sauce') + end + end + + context 'when encoding problems appear in title tag' do + let(:status) { Fabricate(:status, text: 'Check out http://example.com/latin1_posing_as_utf8_broken') } + + it 'does not create a preview card' do + expect(status.preview_card).to be_nil + end + end end end @@ -202,19 +235,6 @@ end end - context 'with an URL too long for PostgreSQL unique indexes' do - let(:url) { "http://example.com/#{'a' * 2674}" } - let(:status) { Fabricate(:status, text: url) } - - it 'does not fetch the URL' do - expect(a_request(:get, url)).to_not have_been_made - end - - it 'does not create a preview card' do - expect(status.preview_card).to be_nil - end - end - context 'with a URL of a page with oEmbed support' do let(:html) { 'Hello world' } let(:status) { Fabricate(:status, text: 'http://example.com/html') } @@ -265,6 +285,22 @@ end end end + + context 'with a URL of a page that includes a canonical URL too long for PostgreSQL unique indexes' do + let(:status) { Fabricate(:status, text: 'test http://example.com/long_canonical_url') } + + it 'does not create a preview card' do + expect(status.preview_card).to be_nil + end + end + + context 'with a URL where the `Content-Type` header uses `utf8` instead of `utf-8`' do + let(:status) { Fabricate(:status, text: 'test http://example.com/alternative_utf8_spelling_in_header') } + + it 'does not create a preview card' do + expect(status.preview_card.title).to eq 'Webserver Configs R Us' + end + end end context 'with a remote status' do diff --git a/spec/services/follow_service_spec.rb b/spec/services/follow_service_spec.rb index bea2412a3d36fe..0c4cd600460922 100644 --- a/spec/services/follow_service_spec.rb +++ b/spec/services/follow_service_spec.rb @@ -150,7 +150,7 @@ expect(FollowRequest.find_by(account: sender, target_account: bob)).to_not be_nil end - it 'sends a follow activity to the inbox', :sidekiq_inline do + it 'sends a follow activity to the inbox', :inline_jobs do expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once end end diff --git a/spec/services/import_service_spec.rb b/spec/services/import_service_spec.rb index 90877d99975200..0a99c5e748db55 100644 --- a/spec/services/import_service_spec.rb +++ b/spec/services/import_service_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe ImportService, :sidekiq_inline do +RSpec.describe ImportService, :inline_jobs do include RoutingHelper let!(:account) { Fabricate(:account, locked: false) } diff --git a/spec/services/mute_service_spec.rb b/spec/services/mute_service_spec.rb index 681afc0b16ec39..3bde92b87aebdc 100644 --- a/spec/services/mute_service_spec.rb +++ b/spec/services/mute_service_spec.rb @@ -17,7 +17,7 @@ redis.del(home_timeline_key) end - it "clears account's statuses", :sidekiq_inline do + it "clears account's statuses", :inline_jobs do FeedManager.instance.push_to_home(account, status) FeedManager.instance.push_to_home(account, other_account_status) diff --git a/spec/services/notify_service_spec.rb b/spec/services/notify_service_spec.rb index 8c810f1c32b521..c7e00129b2cf22 100644 --- a/spec/services/notify_service_spec.rb +++ b/spec/services/notify_service_spec.rb @@ -105,7 +105,7 @@ context 'when email notification is enabled' do let(:enabled) { true } - it 'sends email', :sidekiq_inline do + it 'sends email', :inline_jobs do emails = capture_emails { subject } expect(emails.size) @@ -129,6 +129,39 @@ end end + context 'with filtered notifications' do + let(:unknown) { Fabricate(:account, username: 'unknown') } + let(:status) { Fabricate(:status, account: unknown) } + let(:activity) { Fabricate(:mention, account: recipient, status: status) } + let(:type) { :mention } + + before do + Fabricate(:notification_policy, account: recipient, filter_not_following: true) + end + + it 'creates a filtered notification' do + expect { subject }.to change(Notification, :count) + expect(Notification.last).to be_filtered + end + + context 'when no notification request exists' do + it 'creates a notification request' do + expect { subject }.to change(NotificationRequest, :count) + end + end + + context 'when a notification request exists' do + let!(:notification_request) do + Fabricate(:notification_request, account: recipient, from_account: unknown, last_status: Fabricate(:status, account: unknown)) + end + + it 'updates the existing notification request' do + expect { subject }.to_not change(NotificationRequest, :count) + expect(notification_request.reload.last_status).to eq status + end + end + end + describe NotifyService::DismissCondition do subject { described_class.new(notification) } diff --git a/spec/services/reject_follow_service_spec.rb b/spec/services/reject_follow_service_spec.rb index 98aaf70478539b..d2c7a00206210b 100644 --- a/spec/services/reject_follow_service_spec.rb +++ b/spec/services/reject_follow_service_spec.rb @@ -41,7 +41,7 @@ expect(bob.following?(sender)).to be false end - it 'sends a reject activity', :sidekiq_inline do + it 'sends a reject activity', :inline_jobs do expect(a_request(:post, bob.inbox_url)).to have_been_made.once end end diff --git a/spec/services/remove_from_followers_service_spec.rb b/spec/services/remove_from_followers_service_spec.rb index d6420f76742dfe..515600096cfc04 100644 --- a/spec/services/remove_from_followers_service_spec.rb +++ b/spec/services/remove_from_followers_service_spec.rb @@ -33,7 +33,7 @@ expect(bob.followed_by?(sender)).to be false end - it 'sends a reject activity', :sidekiq_inline do + it 'sends a reject activity', :inline_jobs do expect(a_request(:post, sender.inbox_url)).to have_been_made.once end end diff --git a/spec/services/remove_status_service_spec.rb b/spec/services/remove_status_service_spec.rb index 917b66c6df467b..08f519b5360d99 100644 --- a/spec/services/remove_status_service_spec.rb +++ b/spec/services/remove_status_service_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe RemoveStatusService, :sidekiq_inline do +RSpec.describe RemoveStatusService, :inline_jobs do subject { described_class.new } let!(:alice) { Fabricate(:account) } diff --git a/spec/services/report_service_spec.rb b/spec/services/report_service_spec.rb index 141dc8c3be5623..6518c5c27ad3a0 100644 --- a/spec/services/report_service_spec.rb +++ b/spec/services/report_service_spec.rb @@ -23,7 +23,12 @@ stub_request(:post, 'http://example.com/inbox').to_return(status: 200) end - context 'when forward is true', :sidekiq_inline do + it 'does not have an application' do + report = subject.call(source_account, remote_account) + expect(report.application).to be_nil + end + + context 'when forward is true', :inline_jobs do let(:forward) { true } it 'sends ActivityPub payload when forward is true' do @@ -96,6 +101,15 @@ end end + context 'when passed an application' do + let(:application) { Fabricate(:application) } + + it 'has an application' do + report = subject.call(source_account, target_account, application: application) + expect(report.application).to eq application + end + end + context 'when the reported status is a DM' do subject do -> { described_class.new.call(source_account, target_account, status_ids: [status.id]) } diff --git a/spec/services/resolve_account_service_spec.rb b/spec/services/resolve_account_service_spec.rb index 316266c8f8e539..e0084a15791a1a 100644 --- a/spec/services/resolve_account_service_spec.rb +++ b/spec/services/resolve_account_service_spec.rb @@ -195,7 +195,7 @@ expect(account.uri).to eq 'https://ap.example.com/users/foo' end - it 'merges accounts', :sidekiq_inline do + it 'merges accounts', :inline_jobs do account = subject.call('foo@ap.example.com') expect(status.reload.account_id).to eq account.id diff --git a/spec/services/suspend_account_service_spec.rb b/spec/services/suspend_account_service_spec.rb index 7c72a4776b4b1d..4a2f494e0cb1b8 100644 --- a/spec/services/suspend_account_service_spec.rb +++ b/spec/services/suspend_account_service_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -RSpec.describe SuspendAccountService, :sidekiq_inline do +RSpec.describe SuspendAccountService, :inline_jobs do shared_examples 'common behavior' do subject { described_class.new.call(account) } diff --git a/spec/services/unallow_domain_service_spec.rb b/spec/services/unallow_domain_service_spec.rb index caec3d596ff144..4bf6c540432027 100644 --- a/spec/services/unallow_domain_service_spec.rb +++ b/spec/services/unallow_domain_service_spec.rb @@ -13,7 +13,7 @@ let!(:already_banned_account) { Fabricate(:account, username: 'badguy', domain: bad_domain, suspended: true, silenced: true) } let!(:domain_allow) { Fabricate(:domain_allow, domain: bad_domain) } - context 'with limited federation mode', :sidekiq_inline do + context 'with limited federation mode', :inline_jobs do before do allow(Rails.configuration.x).to receive(:limited_federation_mode).and_return(true) end diff --git a/spec/services/unblock_service_spec.rb b/spec/services/unblock_service_spec.rb index 4c9fcb9aeecdd0..6132e74415ecd6 100644 --- a/spec/services/unblock_service_spec.rb +++ b/spec/services/unblock_service_spec.rb @@ -33,7 +33,7 @@ expect(sender.blocking?(bob)).to be false end - it 'sends an unblock activity', :sidekiq_inline do + it 'sends an unblock activity', :inline_jobs do expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.once end end diff --git a/spec/services/unfollow_service_spec.rb b/spec/services/unfollow_service_spec.rb index bba17a8d2709a2..0c206c4b983215 100644 --- a/spec/services/unfollow_service_spec.rb +++ b/spec/services/unfollow_service_spec.rb @@ -20,7 +20,7 @@ end end - describe 'remote ActivityPub', :sidekiq_inline do + describe 'remote ActivityPub', :inline_jobs do let(:bob) { Fabricate(:account, username: 'bob', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } before do @@ -38,7 +38,7 @@ end end - describe 'remote ActivityPub (reverse)', :sidekiq_inline do + describe 'remote ActivityPub (reverse)', :inline_jobs do let(:bob) { Fabricate(:account, username: 'bob', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') } before do diff --git a/spec/services/unsuspend_account_service_spec.rb b/spec/services/unsuspend_account_service_spec.rb index 79a4441d3ec9ef..8d4882c37f88aa 100644 --- a/spec/services/unsuspend_account_service_spec.rb +++ b/spec/services/unsuspend_account_service_spec.rb @@ -45,7 +45,7 @@ def match_update_actor_request(req, account) remote_follower.follow!(account) end - it 'merges back into feeds of local followers and sends update', :sidekiq_inline do + it 'merges back into feeds of local followers and sends update', :inline_jobs do subject expect_feeds_merged diff --git a/spec/services/update_account_service_spec.rb b/spec/services/update_account_service_spec.rb index 5204f1f34d469d..d066db481e5568 100644 --- a/spec/services/update_account_service_spec.rb +++ b/spec/services/update_account_service_spec.rb @@ -5,7 +5,7 @@ RSpec.describe UpdateAccountService do subject { described_class.new } - describe 'switching form locked to unlocked accounts', :sidekiq_inline do + describe 'switching form locked to unlocked accounts', :inline_jobs do let(:account) { Fabricate(:account, locked: true) } let(:alice) { Fabricate(:account) } let(:bob) { Fabricate(:account) } diff --git a/spec/support/examples/models/concerns/account_avatar.rb b/spec/support/examples/models/concerns/account_avatar.rb index 2c9b5514aad7d6..ab6020d834a8f7 100644 --- a/spec/support/examples/models/concerns/account_avatar.rb +++ b/spec/support/examples/models/concerns/account_avatar.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true shared_examples 'AccountAvatar' do |fabricator| - describe 'static avatars', :paperclip_processing do + describe 'static avatars', :attachment_processing do describe 'when GIF' do it 'creates a png static style' do account = Fabricate(fabricator, avatar: attachment_fixture('avatar.gif')) @@ -17,7 +17,7 @@ end end - describe 'base64-encoded files', :paperclip_processing do + describe 'base64-encoded files', :attachment_processing do let(:base64_attachment) { "data:image/jpeg;base64,#{Base64.encode64(attachment_fixture('attachment.jpg').read)}" } let(:account) { Fabricate(fabricator, avatar: base64_attachment) } diff --git a/spec/support/examples/models/concerns/account_header.rb b/spec/support/examples/models/concerns/account_header.rb index ce09eb006b8ae4..43bbdaacf425d9 100644 --- a/spec/support/examples/models/concerns/account_header.rb +++ b/spec/support/examples/models/concerns/account_header.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true shared_examples 'AccountHeader' do |fabricator| - describe 'base64-encoded files', :paperclip_processing do + describe 'base64-encoded files', :attachment_processing do let(:base64_attachment) { "data:image/jpeg;base64,#{Base64.encode64(attachment_fixture('attachment.jpg').read)}" } let(:account) { Fabricate(fabricator, header: base64_attachment) } diff --git a/spec/system/admin/accounts_spec.rb b/spec/system/admin/accounts_spec.rb index 54d755b914de12..20813f6be42505 100644 --- a/spec/system/admin/accounts_spec.rb +++ b/spec/system/admin/accounts_spec.rb @@ -48,7 +48,7 @@ end end - context 'with action of `reject`', :sidekiq_inline do + context 'with action of `reject`', :inline_jobs do it 'rejects and removes the account' do batch_checkbox_for(unapproved_user_account).check diff --git a/spec/system/new_statuses_spec.rb b/spec/system/new_statuses_spec.rb index 725ea8fe5209d4..2f2fcf22485ee4 100644 --- a/spec/system/new_statuses_spec.rb +++ b/spec/system/new_statuses_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -describe 'NewStatuses', :js, :sidekiq_inline, :streaming do +describe 'NewStatuses', :inline_jobs, :js, :streaming do include ProfileStories subject { page } diff --git a/spec/system/ocr_spec.rb b/spec/system/ocr_spec.rb index 4f4941adca581c..17d18af1586ed7 100644 --- a/spec/system/ocr_spec.rb +++ b/spec/system/ocr_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -describe 'OCR', :js, :paperclip_processing, :sidekiq_inline, :streaming do +describe 'OCR', :attachment_processing, :inline_jobs, :js, :streaming do include ProfileStories let(:email) { 'test@example.com' } diff --git a/spec/system/report_interface_spec.rb b/spec/system/report_interface_spec.rb index f82604aae89643..e6cc3b1b68870f 100644 --- a/spec/system/report_interface_spec.rb +++ b/spec/system/report_interface_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -describe 'report interface', :js, :paperclip_processing, :streaming do +describe 'report interface', :attachment_processing, :js, :streaming do include ProfileStories let(:email) { 'admin@example.com' } diff --git a/spec/workers/backup_worker_spec.rb b/spec/workers/backup_worker_spec.rb index 74928c7ca6ba63..db1b50140b6790 100644 --- a/spec/workers/backup_worker_spec.rb +++ b/spec/workers/backup_worker_spec.rb @@ -14,7 +14,7 @@ let(:backup) { Fabricate(:backup) } let!(:other_backup) { Fabricate(:backup, user: backup.user) } - it 'sends the backup to the service and removes other backups', :sidekiq_inline do + it 'sends the backup to the service and removes other backups', :inline_jobs do emails = capture_emails { worker.perform(backup.id) } expect(service).to have_received(:call).with(backup) diff --git a/spec/workers/move_worker_spec.rb b/spec/workers/move_worker_spec.rb index 0513dc42e5282d..b25992e44bd615 100644 --- a/spec/workers/move_worker_spec.rb +++ b/spec/workers/move_worker_spec.rb @@ -104,7 +104,7 @@ def mute_account_comment end shared_examples 'lists handling' do - it 'puts the new account on the list and makes valid lists', :sidekiq_inline do + it 'puts the new account on the list and makes valid lists', :inline_jobs do subject.perform(source_account.id, target_account.id) expect(list.accounts.include?(target_account)).to be true diff --git a/spec/workers/post_process_media_worker_spec.rb b/spec/workers/post_process_media_worker_spec.rb index 828da5244f55f9..1a274623d73fba 100644 --- a/spec/workers/post_process_media_worker_spec.rb +++ b/spec/workers/post_process_media_worker_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' -describe PostProcessMediaWorker, :paperclip_processing do +describe PostProcessMediaWorker, :attachment_processing do let(:worker) { described_class.new } describe '#perform' do diff --git a/streaming/index.js b/streaming/index.js index 028bd84a1b0599..74121774ccc2af 100644 --- a/streaming/index.js +++ b/streaming/index.js @@ -524,43 +524,27 @@ const startServer = async () => { * @param {any} req * @returns {Promise} */ - const accountFromToken = (token, req) => new Promise((resolve, reject) => { - pgPool.connect((err, client, done) => { - if (err) { - reject(err); - return; - } - - // @ts-ignore - client.query('SELECT oauth_access_tokens.id, oauth_access_tokens.resource_owner_id, users.account_id, users.chosen_languages, oauth_access_tokens.scopes, devices.device_id FROM oauth_access_tokens INNER JOIN users ON oauth_access_tokens.resource_owner_id = users.id LEFT OUTER JOIN devices ON oauth_access_tokens.id = devices.access_token_id WHERE oauth_access_tokens.token = $1 AND oauth_access_tokens.revoked_at IS NULL LIMIT 1', [token], (err, result) => { - done(); - - if (err) { - reject(err); - return; - } + const accountFromToken = async (token, req) => { + const result = await pgPool.query('SELECT oauth_access_tokens.id, oauth_access_tokens.resource_owner_id, users.account_id, users.chosen_languages, oauth_access_tokens.scopes, devices.device_id FROM oauth_access_tokens INNER JOIN users ON oauth_access_tokens.resource_owner_id = users.id LEFT OUTER JOIN devices ON oauth_access_tokens.id = devices.access_token_id WHERE oauth_access_tokens.token = $1 AND oauth_access_tokens.revoked_at IS NULL LIMIT 1', [token]); - if (result.rows.length === 0) { - reject(new AuthenticationError('Invalid access token')); - return; - } - - req.accessTokenId = result.rows[0].id; - req.scopes = result.rows[0].scopes.split(' '); - req.accountId = result.rows[0].account_id; - req.chosenLanguages = result.rows[0].chosen_languages; - req.deviceId = result.rows[0].device_id; + if (result.rows.length === 0) { + throw new AuthenticationError('Invalid access token'); + } - resolve({ - accessTokenId: result.rows[0].id, - scopes: result.rows[0].scopes.split(' '), - accountId: result.rows[0].account_id, - chosenLanguages: result.rows[0].chosen_languages, - deviceId: result.rows[0].device_id - }); - }); - }); - }); + req.accessTokenId = result.rows[0].id; + req.scopes = result.rows[0].scopes.split(' '); + req.accountId = result.rows[0].account_id; + req.chosenLanguages = result.rows[0].chosen_languages; + req.deviceId = result.rows[0].device_id; + + return { + accessTokenId: result.rows[0].id, + scopes: result.rows[0].scopes.split(' '), + accountId: result.rows[0].account_id, + chosenLanguages: result.rows[0].chosen_languages, + deviceId: result.rows[0].device_id + }; + }; /** * @param {any} req @@ -771,28 +755,15 @@ const startServer = async () => { * @param {any} req * @returns {Promise.} */ - const authorizeListAccess = (listId, req) => new Promise((resolve, reject) => { + const authorizeListAccess = async (listId, req) => { const { accountId } = req; - pgPool.connect((err, client, done) => { - if (err) { - reject(); - return; - } - - // @ts-ignore - client.query('SELECT id, account_id FROM lists WHERE id = $1 LIMIT 1', [listId], (err, result) => { - done(); - - if (err || result.rows.length === 0 || result.rows[0].account_id !== accountId) { - reject(); - return; - } + const result = await pgPool.query('SELECT id, account_id FROM lists WHERE id = $1 AND account_id = $2 LIMIT 1', [listId, accountId]); - resolve(); - }); - }); - }); + if (result.rows.length === 0) { + throw new AuthenticationError('List not found'); + } + }; /** * @param {string[]} channelIds @@ -1114,7 +1085,7 @@ const startServer = async () => { /** * @param {http.IncomingMessage} req - * @param {WebSocket} ws + * @param {import('ws').WebSocket} ws * @param {string[]} streamName * @returns {function(string, string): void} */ @@ -1345,7 +1316,7 @@ const startServer = async () => { /** * @typedef WebSocketSession - * @property {WebSocket & { isAlive: boolean}} websocket + * @property {import('ws').WebSocket & { isAlive: boolean}} websocket * @property {http.IncomingMessage & ResolvedAccount} request * @property {import('pino').Logger} logger * @property {Object.} subscriptions @@ -1471,7 +1442,7 @@ const startServer = async () => { }; /** - * @param {WebSocket & { isAlive: boolean }} ws + * @param {import('ws').WebSocket & { isAlive: boolean }} ws * @param {http.IncomingMessage & ResolvedAccount} req * @param {import('pino').Logger} log */ diff --git a/yarn.lock b/yarn.lock index 59bee13c088a5d..326a0c7f6f8636 100644 --- a/yarn.lock +++ b/yarn.lock @@ -52,45 +52,45 @@ __metadata: languageName: node linkType: hard -"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/compat-data@npm:7.24.7" - checksum: 10c0/dcd93a5632b04536498fbe2be5af1057f635fd7f7090483d8e797878559037e5130b26862ceb359acbae93ed27e076d395ddb4663db6b28a665756ffd02d324f +"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/compat-data@npm:7.24.8" + checksum: 10c0/7f465e9d8e44c5b516eeb3001362a3cd9a6df51dd90d3ac9868e1e7fa631ac57fc781cec6700110d4f555ba37fe59c4a71927b445106fe0062e79e79ffe11091 languageName: node linkType: hard "@babel/core@npm:^7.10.4, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.22.1, @babel/core@npm:^7.24.4": - version: 7.24.7 - resolution: "@babel/core@npm:7.24.7" + version: 7.24.9 + resolution: "@babel/core@npm:7.24.9" dependencies: "@ampproject/remapping": "npm:^2.2.0" "@babel/code-frame": "npm:^7.24.7" - "@babel/generator": "npm:^7.24.7" - "@babel/helper-compilation-targets": "npm:^7.24.7" - "@babel/helper-module-transforms": "npm:^7.24.7" - "@babel/helpers": "npm:^7.24.7" - "@babel/parser": "npm:^7.24.7" + "@babel/generator": "npm:^7.24.9" + "@babel/helper-compilation-targets": "npm:^7.24.8" + "@babel/helper-module-transforms": "npm:^7.24.9" + "@babel/helpers": "npm:^7.24.8" + "@babel/parser": "npm:^7.24.8" "@babel/template": "npm:^7.24.7" - "@babel/traverse": "npm:^7.24.7" - "@babel/types": "npm:^7.24.7" + "@babel/traverse": "npm:^7.24.8" + "@babel/types": "npm:^7.24.9" convert-source-map: "npm:^2.0.0" debug: "npm:^4.1.0" gensync: "npm:^1.0.0-beta.2" json5: "npm:^2.2.3" semver: "npm:^6.3.1" - checksum: 10c0/4004ba454d3c20a46ea66264e06c15b82e9f6bdc35f88819907d24620da70dbf896abac1cb4cc4b6bb8642969e45f4d808497c9054a1388a386cf8c12e9b9e0d + checksum: 10c0/e104ec6efbf099f55184933e9ab078eb5821c792ddfef3e9c6561986ec4ff103f5c11e3d7d6e5e8929e50e2c58db1cc80e5b6f14b530335b6622095ec4b4124c languageName: node linkType: hard -"@babel/generator@npm:^7.24.7, @babel/generator@npm:^7.7.2": - version: 7.24.7 - resolution: "@babel/generator@npm:7.24.7" +"@babel/generator@npm:^7.24.8, @babel/generator@npm:^7.24.9, @babel/generator@npm:^7.7.2": + version: 7.24.9 + resolution: "@babel/generator@npm:7.24.9" dependencies: - "@babel/types": "npm:^7.24.7" + "@babel/types": "npm:^7.24.9" "@jridgewell/gen-mapping": "npm:^0.3.5" "@jridgewell/trace-mapping": "npm:^0.3.25" jsesc: "npm:^2.5.1" - checksum: 10c0/06b1f3350baf527a3309e50ffd7065f7aee04dd06e1e7db794ddfde7fe9d81f28df64edd587173f8f9295496a7ddb74b9a185d4bf4de7bb619e6d4ec45c8fd35 + checksum: 10c0/cd1f7edce7717462546c349e15289d1267a3ed627c6f6583fbf51e78eacacc6500ec2f0024f08f1cc7138989e575635b931acf4549f9e728017a22176a9ea6b6 languageName: node linkType: hard @@ -123,16 +123,16 @@ __metadata: languageName: node linkType: hard -"@babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-compilation-targets@npm:7.24.7" +"@babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.24.7, @babel/helper-compilation-targets@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/helper-compilation-targets@npm:7.24.8" dependencies: - "@babel/compat-data": "npm:^7.24.7" - "@babel/helper-validator-option": "npm:^7.24.7" - browserslist: "npm:^4.22.2" + "@babel/compat-data": "npm:^7.24.8" + "@babel/helper-validator-option": "npm:^7.24.8" + browserslist: "npm:^4.23.1" lru-cache: "npm:^5.1.1" semver: "npm:^6.3.1" - checksum: 10c0/1d580a9bcacefe65e6bf02ba1dafd7ab278269fef45b5e281d8354d95c53031e019890464e7f9351898c01502dd2e633184eb0bcda49ed2ecd538675ce310f51 + checksum: 10c0/2885c44ef6aaf82b7e4352b30089bb09fbe08ed5ec24eb452c2bdc3c021e2a65ab412f74b3d67ec1398da0356c730b33a2ceca1d67d34c85080d31ca6efa9aec languageName: node linkType: hard @@ -231,9 +231,9 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-transforms@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-module-transforms@npm:7.24.7" +"@babel/helper-module-transforms@npm:^7.24.7, @babel/helper-module-transforms@npm:^7.24.8, @babel/helper-module-transforms@npm:^7.24.9": + version: 7.24.9 + resolution: "@babel/helper-module-transforms@npm:7.24.9" dependencies: "@babel/helper-environment-visitor": "npm:^7.24.7" "@babel/helper-module-imports": "npm:^7.24.7" @@ -242,7 +242,7 @@ __metadata: "@babel/helper-validator-identifier": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/4f311755fcc3b4cbdb689386309cdb349cf0575a938f0b9ab5d678e1a81bbb265aa34ad93174838245f2ac7ff6d5ddbd0104638a75e4e961958ed514355687b6 + checksum: 10c0/e27bca43bc113731ee4f2b33a4c5bf9c7eebf4d64487b814c305cbd5feb272c29fcd3d79634ba03131ade171e5972bc7ede8dbc83ba0deb02f1e62d318c87770 languageName: node linkType: hard @@ -255,10 +255,10 @@ __metadata: languageName: node linkType: hard -"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.7, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": - version: 7.24.7 - resolution: "@babel/helper-plugin-utils@npm:7.24.7" - checksum: 10c0/c3d38cd9b3520757bb4a279255cc3f956fc0ac1c193964bd0816ebd5c86e30710be8e35252227e0c9d9e0f4f56d9b5f916537f2bc588084b0988b4787a967d31 +"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.7, @babel/helper-plugin-utils@npm:^7.24.8, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": + version: 7.24.8 + resolution: "@babel/helper-plugin-utils@npm:7.24.8" + checksum: 10c0/0376037f94a3bfe6b820a39f81220ac04f243eaee7193774b983e956c1750883ff236b30785795abbcda43fac3ece74750566830c2daa4d6e3870bb0dff34c2d languageName: node linkType: hard @@ -317,10 +317,10 @@ __metadata: languageName: node linkType: hard -"@babel/helper-string-parser@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-string-parser@npm:7.24.7" - checksum: 10c0/47840c7004e735f3dc93939c77b099bb41a64bf3dda0cae62f60e6f74a5ff80b63e9b7cf77b5ec25a324516381fc994e1f62f922533236a8e3a6af57decb5e1e +"@babel/helper-string-parser@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/helper-string-parser@npm:7.24.8" + checksum: 10c0/6361f72076c17fabf305e252bf6d580106429014b3ab3c1f5c4eb3e6d465536ea6b670cc0e9a637a77a9ad40454d3e41361a2909e70e305116a23d68ce094c08 languageName: node linkType: hard @@ -331,10 +331,10 @@ __metadata: languageName: node linkType: hard -"@babel/helper-validator-option@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-validator-option@npm:7.24.7" - checksum: 10c0/21aea2b7bc5cc8ddfb828741d5c8116a84cbc35b4a3184ec53124f08e09746f1f67a6f9217850188995ca86059a7942e36d8965a6730784901def777b7e8a436 +"@babel/helper-validator-option@npm:^7.24.7, @babel/helper-validator-option@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/helper-validator-option@npm:7.24.8" + checksum: 10c0/73db93a34ae89201351288bee7623eed81a54000779462a986105b54ffe82069e764afd15171a428b82e7c7a9b5fec10b5d5603b216317a414062edf5c67a21f languageName: node linkType: hard @@ -350,13 +350,13 @@ __metadata: languageName: node linkType: hard -"@babel/helpers@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helpers@npm:7.24.7" +"@babel/helpers@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/helpers@npm:7.24.8" dependencies: "@babel/template": "npm:^7.24.7" - "@babel/types": "npm:^7.24.7" - checksum: 10c0/aa8e230f6668773e17e141dbcab63e935c514b4b0bf1fed04d2eaefda17df68e16b61a56573f7f1d4d1e605ce6cc162b5f7e9fdf159fde1fd9b77c920ae47d27 + "@babel/types": "npm:^7.24.8" + checksum: 10c0/42b8939b0a0bf72d6df9721973eb0fd7cd48f42641c5c9c740916397faa586255c06d36c6e6a7e091860723096281c620f6ffaee0011a3bb254a6f5475d89a12 languageName: node linkType: hard @@ -372,12 +372,12 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/parser@npm:7.24.7" +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.24.7, @babel/parser@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/parser@npm:7.24.8" bin: parser: ./bin/babel-parser.js - checksum: 10c0/8b244756872185a1c6f14b979b3535e682ff08cb5a2a5fd97cc36c017c7ef431ba76439e95e419d43000c5b07720495b00cf29a7f0d9a483643d08802b58819b + checksum: 10c0/ce69671de8fa6f649abf849be262707ac700b573b8b1ce1893c66cc6cd76aeb1294a19e8c290b0eadeb2f47d3f413a2e57a281804ffbe76bfb9fa50194cf3c52 languageName: node linkType: hard @@ -755,21 +755,21 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-classes@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-classes@npm:7.24.7" +"@babel/plugin-transform-classes@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/plugin-transform-classes@npm:7.24.8" dependencies: "@babel/helper-annotate-as-pure": "npm:^7.24.7" - "@babel/helper-compilation-targets": "npm:^7.24.7" + "@babel/helper-compilation-targets": "npm:^7.24.8" "@babel/helper-environment-visitor": "npm:^7.24.7" "@babel/helper-function-name": "npm:^7.24.7" - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.8" "@babel/helper-replace-supers": "npm:^7.24.7" "@babel/helper-split-export-declaration": "npm:^7.24.7" globals: "npm:^11.1.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/e51dba7ce8b770d1eee929e098d5a3be3efc3e8b941e22dda7d0097dc4e7be5feabd2da7b707ac06fcac5661b31223c541941dec08ce76c1faa55544d87d06ec + checksum: 10c0/4423da0f747bdb6aab1995d98a74533fa679f637ec20706810dd57fb4ba2b1885ec8cae6a0b2c3f69f27165de6ff6aa2da9c4061c893848736a8267d0c653079 languageName: node linkType: hard @@ -785,14 +785,14 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-destructuring@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-destructuring@npm:7.24.7" +"@babel/plugin-transform-destructuring@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/plugin-transform-destructuring@npm:7.24.8" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.8" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/929f07a807fb62230bfbf881cfcedf187ac5daf2f1b01da94a75c7a0f6f72400268cf4bcfee534479e43260af8193e42c31ee03c8b0278ba77d0036ed6709c27 + checksum: 10c0/804968c1d5f5072c717505296c1e5d5ec33e90550423de66de82bbcb78157156e8470bbe77a04ab8c710a88a06360a30103cf223ac7eff4829adedd6150de5ce languageName: node linkType: hard @@ -938,16 +938,16 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-modules-commonjs@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-modules-commonjs@npm:7.24.7" +"@babel/plugin-transform-modules-commonjs@npm:^7.24.7, @babel/plugin-transform-modules-commonjs@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/plugin-transform-modules-commonjs@npm:7.24.8" dependencies: - "@babel/helper-module-transforms": "npm:^7.24.7" - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-module-transforms": "npm:^7.24.8" + "@babel/helper-plugin-utils": "npm:^7.24.8" "@babel/helper-simple-access": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/9442292b3daf6a5076cdc3c4c32bf423bda824ccaeb0dd0dc8b3effaa1fecfcb0130ae6e647fef12a5d5ff25bcc99a0d6bfc6d24a7525345e1bcf46fcdf81752 + checksum: 10c0/f1cf552307ebfced20d3907c1dd8be941b277f0364aa655e2b5fee828c84c54065745183104dae86f1f93ea0406db970a463ef7ceaaed897623748e99640e5a7 languageName: node linkType: hard @@ -1062,16 +1062,16 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-optional-chaining@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-optional-chaining@npm:7.24.7" +"@babel/plugin-transform-optional-chaining@npm:^7.24.7, @babel/plugin-transform-optional-chaining@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/plugin-transform-optional-chaining@npm:7.24.8" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.8" "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.7" "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/b9e3649b299e103b0d1767bbdba56574d065ff776e5350403b7bfd4e3982743c0cdb373d33bdbf94fa3c322d155e45d0aad946acf0aa741b870aed22dfec8b8e + checksum: 10c0/4ffbe1aad7dec7c9aa2bf6ceb4b2f91f96815b2784f2879bde80e46934f59d64a12cb2c6262e40897c4754d77d2c35d8a5cfed63044fdebf94978b1ed3d14b17 languageName: node linkType: hard @@ -1279,14 +1279,14 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-typeof-symbol@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-typeof-symbol@npm:7.24.7" +"@babel/plugin-transform-typeof-symbol@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/plugin-transform-typeof-symbol@npm:7.24.8" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.8" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/5649e7260a138681e68b296ab5931e2b1f132f287d6b4131d49b24f9dc20d62902b7e9d63c4d2decd5683b41df35ef4b9b03f58c7f9f65e4c25a6d8bbf04e9e9 + checksum: 10c0/2f570a4fbbdc5fd85f48165a97452826560051e3b8efb48c3bb0a0a33ee8485633439e7b71bfe3ef705583a1df43f854f49125bd759abdedc195b2cf7e60012a languageName: node linkType: hard @@ -1352,13 +1352,13 @@ __metadata: linkType: hard "@babel/preset-env@npm:^7.11.0, @babel/preset-env@npm:^7.12.1, @babel/preset-env@npm:^7.22.4": - version: 7.24.7 - resolution: "@babel/preset-env@npm:7.24.7" + version: 7.24.8 + resolution: "@babel/preset-env@npm:7.24.8" dependencies: - "@babel/compat-data": "npm:^7.24.7" - "@babel/helper-compilation-targets": "npm:^7.24.7" - "@babel/helper-plugin-utils": "npm:^7.24.7" - "@babel/helper-validator-option": "npm:^7.24.7" + "@babel/compat-data": "npm:^7.24.8" + "@babel/helper-compilation-targets": "npm:^7.24.8" + "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/helper-validator-option": "npm:^7.24.8" "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "npm:^7.24.7" "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "npm:^7.24.7" "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "npm:^7.24.7" @@ -1389,9 +1389,9 @@ __metadata: "@babel/plugin-transform-block-scoping": "npm:^7.24.7" "@babel/plugin-transform-class-properties": "npm:^7.24.7" "@babel/plugin-transform-class-static-block": "npm:^7.24.7" - "@babel/plugin-transform-classes": "npm:^7.24.7" + "@babel/plugin-transform-classes": "npm:^7.24.8" "@babel/plugin-transform-computed-properties": "npm:^7.24.7" - "@babel/plugin-transform-destructuring": "npm:^7.24.7" + "@babel/plugin-transform-destructuring": "npm:^7.24.8" "@babel/plugin-transform-dotall-regex": "npm:^7.24.7" "@babel/plugin-transform-duplicate-keys": "npm:^7.24.7" "@babel/plugin-transform-dynamic-import": "npm:^7.24.7" @@ -1404,7 +1404,7 @@ __metadata: "@babel/plugin-transform-logical-assignment-operators": "npm:^7.24.7" "@babel/plugin-transform-member-expression-literals": "npm:^7.24.7" "@babel/plugin-transform-modules-amd": "npm:^7.24.7" - "@babel/plugin-transform-modules-commonjs": "npm:^7.24.7" + "@babel/plugin-transform-modules-commonjs": "npm:^7.24.8" "@babel/plugin-transform-modules-systemjs": "npm:^7.24.7" "@babel/plugin-transform-modules-umd": "npm:^7.24.7" "@babel/plugin-transform-named-capturing-groups-regex": "npm:^7.24.7" @@ -1414,7 +1414,7 @@ __metadata: "@babel/plugin-transform-object-rest-spread": "npm:^7.24.7" "@babel/plugin-transform-object-super": "npm:^7.24.7" "@babel/plugin-transform-optional-catch-binding": "npm:^7.24.7" - "@babel/plugin-transform-optional-chaining": "npm:^7.24.7" + "@babel/plugin-transform-optional-chaining": "npm:^7.24.8" "@babel/plugin-transform-parameters": "npm:^7.24.7" "@babel/plugin-transform-private-methods": "npm:^7.24.7" "@babel/plugin-transform-private-property-in-object": "npm:^7.24.7" @@ -1425,7 +1425,7 @@ __metadata: "@babel/plugin-transform-spread": "npm:^7.24.7" "@babel/plugin-transform-sticky-regex": "npm:^7.24.7" "@babel/plugin-transform-template-literals": "npm:^7.24.7" - "@babel/plugin-transform-typeof-symbol": "npm:^7.24.7" + "@babel/plugin-transform-typeof-symbol": "npm:^7.24.8" "@babel/plugin-transform-unicode-escapes": "npm:^7.24.7" "@babel/plugin-transform-unicode-property-regex": "npm:^7.24.7" "@babel/plugin-transform-unicode-regex": "npm:^7.24.7" @@ -1434,11 +1434,11 @@ __metadata: babel-plugin-polyfill-corejs2: "npm:^0.4.10" babel-plugin-polyfill-corejs3: "npm:^0.10.4" babel-plugin-polyfill-regenerator: "npm:^0.6.1" - core-js-compat: "npm:^3.31.0" + core-js-compat: "npm:^3.37.1" semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/c6714346f3ccc1271eaa90051c75b8bb57b20ef57408ab68740e2f3552693ae0ee5a4bcce3a00211d40e4947af1f7b8ab422066b953f0095461937fb72d11274 + checksum: 10c0/a6f29498ec58989845a61f9c10b1b4e80586f1810a33db461d597cdb0ad2cd847381a993038b09f727512a08b2c1a33a330a5d4e6d65463ee98a1b4302d52ec6 languageName: node linkType: hard @@ -1503,11 +1503,11 @@ __metadata: linkType: hard "@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.2.0, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.22.3, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": - version: 7.24.7 - resolution: "@babel/runtime@npm:7.24.7" + version: 7.24.8 + resolution: "@babel/runtime@npm:7.24.8" dependencies: regenerator-runtime: "npm:^0.14.0" - checksum: 10c0/b6fa3ec61a53402f3c1d75f4d808f48b35e0dfae0ec8e2bb5c6fc79fb95935da75766e0ca534d0f1c84871f6ae0d2ebdd950727cfadb745a2cdbef13faef5513 + checksum: 10c0/f24b30af6b3ecae19165b3b032f9bc37b2d1769677bd63b69a6f81061967cfc847aa822518402ea6616b1d301d7eb46986b99c9f69cdb5880834fca2e6b34881 languageName: node linkType: hard @@ -1522,32 +1522,32 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:7, @babel/traverse@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/traverse@npm:7.24.7" +"@babel/traverse@npm:7, @babel/traverse@npm:^7.24.7, @babel/traverse@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/traverse@npm:7.24.8" dependencies: "@babel/code-frame": "npm:^7.24.7" - "@babel/generator": "npm:^7.24.7" + "@babel/generator": "npm:^7.24.8" "@babel/helper-environment-visitor": "npm:^7.24.7" "@babel/helper-function-name": "npm:^7.24.7" "@babel/helper-hoist-variables": "npm:^7.24.7" "@babel/helper-split-export-declaration": "npm:^7.24.7" - "@babel/parser": "npm:^7.24.7" - "@babel/types": "npm:^7.24.7" + "@babel/parser": "npm:^7.24.8" + "@babel/types": "npm:^7.24.8" debug: "npm:^4.3.1" globals: "npm:^11.1.0" - checksum: 10c0/a5135e589c3f1972b8877805f50a084a04865ccb1d68e5e1f3b94a8841b3485da4142e33413d8fd76bc0e6444531d3adf1f59f359c11ffac452b743d835068ab + checksum: 10c0/67a5cc35824455cdb54fb9e196a44b3186283e29018a9c2331f51763921e18e891b3c60c283615a27540ec8eb4c8b89f41c237b91f732a7aa518b2eb7a0d434d languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.0.0-beta.49, @babel/types@npm:^7.12.11, @babel/types@npm:^7.12.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.24.7, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": - version: 7.24.7 - resolution: "@babel/types@npm:7.24.7" +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.0.0-beta.49, @babel/types@npm:^7.12.11, @babel/types@npm:^7.12.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.24.7, @babel/types@npm:^7.24.8, @babel/types@npm:^7.24.9, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": + version: 7.24.9 + resolution: "@babel/types@npm:7.24.9" dependencies: - "@babel/helper-string-parser": "npm:^7.24.7" + "@babel/helper-string-parser": "npm:^7.24.8" "@babel/helper-validator-identifier": "npm:^7.24.7" to-fast-properties: "npm:^2.0.0" - checksum: 10c0/d9ecbfc3eb2b05fb1e6eeea546836ac30d990f395ef3fe3f75ced777a222c3cfc4489492f72e0ce3d9a5a28860a1ce5f81e66b88cf5088909068b3ff4fab72c1 + checksum: 10c0/4970b3481cab39c5c3fdb7c28c834df5c7049f3c7f43baeafe121bb05270ebf0da7c65b097abf314877f213baa591109c82204f30d66cdd46c22ece4a2f32415 languageName: node linkType: hard @@ -1558,13 +1558,13 @@ __metadata: languageName: node linkType: hard -"@csstools/cascade-layer-name-parser@npm:^1.0.12": - version: 1.0.12 - resolution: "@csstools/cascade-layer-name-parser@npm:1.0.12" +"@csstools/cascade-layer-name-parser@npm:^1.0.13": + version: 1.0.13 + resolution: "@csstools/cascade-layer-name-parser@npm:1.0.13" peerDependencies: - "@csstools/css-parser-algorithms": ^2.7.0 - "@csstools/css-tokenizer": ^2.3.2 - checksum: 10c0/5f92aefcbb3f4b660cf7b0db54f6a4ba21a32fa1b64ea4f050a6370233152d4f561ecf5c8e98ca231e73c16e0d9f75b20b0a65153e18b14957658c81e0f68213 + "@csstools/css-parser-algorithms": ^2.7.1 + "@csstools/css-tokenizer": ^2.4.1 + checksum: 10c0/a6412fc8601af1baadc8195934aa668d3476e799891c9d0883390f31ec8678e9b565ac14d919bec633bbc086657ac12aa4cd852c718851a2d34517ee6856ff8e languageName: node linkType: hard @@ -1575,52 +1575,52 @@ __metadata: languageName: node linkType: hard -"@csstools/css-calc@npm:^1.2.3": - version: 1.2.3 - resolution: "@csstools/css-calc@npm:1.2.3" +"@csstools/css-calc@npm:^1.2.4": + version: 1.2.4 + resolution: "@csstools/css-calc@npm:1.2.4" peerDependencies: - "@csstools/css-parser-algorithms": ^2.7.0 - "@csstools/css-tokenizer": ^2.3.2 - checksum: 10c0/fb34767ea9638b837167bcecaf945bcc0c5e8f0d811067c4e8c7a57bc8f0955f61107b1ed5e017b95c54acacc8088473e5497a9986bee95b37ec92999e792871 + "@csstools/css-parser-algorithms": ^2.7.1 + "@csstools/css-tokenizer": ^2.4.1 + checksum: 10c0/6233746eb642797b7fbc2cf6e7651e95700b294e78e3c29e8730c3236bb92cf62903efb6e54639e8f877683c40646e137c95e615c4450809b21b61a6192888ca languageName: node linkType: hard -"@csstools/css-color-parser@npm:^2.0.3": - version: 2.0.3 - resolution: "@csstools/css-color-parser@npm:2.0.3" +"@csstools/css-color-parser@npm:^2.0.4": + version: 2.0.4 + resolution: "@csstools/css-color-parser@npm:2.0.4" dependencies: "@csstools/color-helpers": "npm:^4.2.1" - "@csstools/css-calc": "npm:^1.2.3" + "@csstools/css-calc": "npm:^1.2.4" peerDependencies: - "@csstools/css-parser-algorithms": ^2.7.0 - "@csstools/css-tokenizer": ^2.3.2 - checksum: 10c0/d8860e6b9c65de4f90d4c21e4d66471fd858434cf63af80f812a900371343b753b86a256627e8bd024cb8903a6a0181d2d9c0c65ab5d78cf29d084a761e2adba + "@csstools/css-parser-algorithms": ^2.7.1 + "@csstools/css-tokenizer": ^2.4.1 + checksum: 10c0/e009a2f34b6c328daad54262deb86b71c6a7a9a1da1db8ad39cf719641e1a728ed8ddbd23613d519d26deee33b89ba12cb15a6928718c1b3cc5e24ac1ed02f47 languageName: node linkType: hard -"@csstools/css-parser-algorithms@npm:^2.6.3, @csstools/css-parser-algorithms@npm:^2.7.0": - version: 2.7.0 - resolution: "@csstools/css-parser-algorithms@npm:2.7.0" +"@csstools/css-parser-algorithms@npm:^2.6.3, @csstools/css-parser-algorithms@npm:^2.7.1": + version: 2.7.1 + resolution: "@csstools/css-parser-algorithms@npm:2.7.1" peerDependencies: - "@csstools/css-tokenizer": ^2.3.2 - checksum: 10c0/fb84fefdf37c41d170f81b687bf1ee1847a970e51cc1fe3a320e3eaf225383ae9a3c4eb6208b83357dfe18c5114353d780e0c65f05d86d6435e5a9ad9334c834 + "@csstools/css-tokenizer": ^2.4.1 + checksum: 10c0/7d29bef6f5790ddb67d922ad232253bf910e4fa5293f5e4a5ed8b920ae9bd4e8171942df7d8943af23b42fd4e9fb460181394d20c97da9562e6ce98a875e8c47 languageName: node linkType: hard -"@csstools/css-tokenizer@npm:^2.3.1, @csstools/css-tokenizer@npm:^2.3.2": - version: 2.3.2 - resolution: "@csstools/css-tokenizer@npm:2.3.2" - checksum: 10c0/f7d0d8b3e9e2dcdc6547a387253a09dbbacaaffb5c8718bcd7f15dddeefdd441b73fc5f9fad3f03fabef3b37ec4b62be7ff79caab366427fa90eaf54cd8fc452 +"@csstools/css-tokenizer@npm:^2.3.1, @csstools/css-tokenizer@npm:^2.4.1": + version: 2.4.1 + resolution: "@csstools/css-tokenizer@npm:2.4.1" + checksum: 10c0/fe71cee85ec7372da07083d088b6a704f43e5d3d2d8071c4b8a86fae60408b559a218a43f8625bf2f0be5c7f90c8f3ad20a1aae1921119a1c02b51c310cc2b6b languageName: node linkType: hard -"@csstools/media-query-list-parser@npm:^2.1.11, @csstools/media-query-list-parser@npm:^2.1.12": - version: 2.1.12 - resolution: "@csstools/media-query-list-parser@npm:2.1.12" +"@csstools/media-query-list-parser@npm:^2.1.11, @csstools/media-query-list-parser@npm:^2.1.13": + version: 2.1.13 + resolution: "@csstools/media-query-list-parser@npm:2.1.13" peerDependencies: - "@csstools/css-parser-algorithms": ^2.7.0 - "@csstools/css-tokenizer": ^2.3.2 - checksum: 10c0/7395cc710d8f54670c1e7a418a88dcf1ae726316272294ec645f6d79a8e931f5d390ba7ed5d0141d29ad7280cd447b8773143dc7676659413de79228130e1a65 + "@csstools/css-parser-algorithms": ^2.7.1 + "@csstools/css-tokenizer": ^2.4.1 + checksum: 10c0/8bf72342c15581b8f658633436d83c26a214056f6b960ff121b940271f4b1b5b07e9cc3990a73e684fb72319592f0c392408b4f0e08bbe242b2065aa456e2733 languageName: node linkType: hard @@ -1636,46 +1636,60 @@ __metadata: languageName: node linkType: hard -"@csstools/postcss-color-function@npm:^3.0.17": - version: 3.0.17 - resolution: "@csstools/postcss-color-function@npm:3.0.17" +"@csstools/postcss-color-function@npm:^3.0.19": + version: 3.0.19 + resolution: "@csstools/postcss-color-function@npm:3.0.19" dependencies: - "@csstools/css-color-parser": "npm:^2.0.3" - "@csstools/css-parser-algorithms": "npm:^2.7.0" - "@csstools/css-tokenizer": "npm:^2.3.2" - "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0" + "@csstools/css-color-parser": "npm:^2.0.4" + "@csstools/css-parser-algorithms": "npm:^2.7.1" + "@csstools/css-tokenizer": "npm:^2.4.1" + "@csstools/postcss-progressive-custom-properties": "npm:^3.3.0" "@csstools/utilities": "npm:^1.0.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/6d347fc9fe65cb897c275c129103576e551b74a7c47a1a4dc8160da2fad7752bf51e3cfbff339f86b39c723efac33643168d2dfaac4d3624d072875d18a65a4b + checksum: 10c0/067e33d7dfc32b56fe63d4f97464a3eaf27dde720961e44feab6076bd2c172dd4c1bad16aa37a922dcbba470756bd6a13e728d9e71eab6937d48d83873cd1879 languageName: node linkType: hard -"@csstools/postcss-color-mix-function@npm:^2.0.17": - version: 2.0.17 - resolution: "@csstools/postcss-color-mix-function@npm:2.0.17" +"@csstools/postcss-color-mix-function@npm:^2.0.19": + version: 2.0.19 + resolution: "@csstools/postcss-color-mix-function@npm:2.0.19" dependencies: - "@csstools/css-color-parser": "npm:^2.0.3" - "@csstools/css-parser-algorithms": "npm:^2.7.0" - "@csstools/css-tokenizer": "npm:^2.3.2" - "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0" + "@csstools/css-color-parser": "npm:^2.0.4" + "@csstools/css-parser-algorithms": "npm:^2.7.1" + "@csstools/css-tokenizer": "npm:^2.4.1" + "@csstools/postcss-progressive-custom-properties": "npm:^3.3.0" "@csstools/utilities": "npm:^1.0.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/ba9a406ebe4caba6709878ee26debb06780be5cbf4e6ab7e902d79ca6e21ec6a8409b9dc0a5ef36fc4bf54bf2bd8f9642b72da8d7939145f99dc40fedd2be9d2 + checksum: 10c0/e967d93672a065806dc78da0153f8b4f5087f7c3ddfe361eba4942780760d47b317124913c9b0dda7f9bfff1253f77d1b6debd8a6a2aa3a6c80e263101da5e8c languageName: node linkType: hard -"@csstools/postcss-exponential-functions@npm:^1.0.8": - version: 1.0.8 - resolution: "@csstools/postcss-exponential-functions@npm:1.0.8" +"@csstools/postcss-content-alt-text@npm:^1.0.0": + version: 1.0.0 + resolution: "@csstools/postcss-content-alt-text@npm:1.0.0" + dependencies: + "@csstools/css-parser-algorithms": "npm:^2.7.1" + "@csstools/css-tokenizer": "npm:^2.4.1" + "@csstools/postcss-progressive-custom-properties": "npm:^3.3.0" + "@csstools/utilities": "npm:^1.0.0" + peerDependencies: + postcss: ^8.4 + checksum: 10c0/0c2c64857ac652989d00c3d2ba49d0cd1cc245193cba6724d2f5841aa990ee6a07267cfebc6fabde6a6246616df60373006d17c5ea9b904129fbfd826dc10a8d + languageName: node + linkType: hard + +"@csstools/postcss-exponential-functions@npm:^1.0.9": + version: 1.0.9 + resolution: "@csstools/postcss-exponential-functions@npm:1.0.9" dependencies: - "@csstools/css-calc": "npm:^1.2.3" - "@csstools/css-parser-algorithms": "npm:^2.7.0" - "@csstools/css-tokenizer": "npm:^2.3.2" + "@csstools/css-calc": "npm:^1.2.4" + "@csstools/css-parser-algorithms": "npm:^2.7.1" + "@csstools/css-tokenizer": "npm:^2.4.1" peerDependencies: postcss: ^8.4 - checksum: 10c0/6b049801fc1275b34f43ffbb915f447a54cbff7bf48ab0705c3ad1ffde055cb876c4dc24e7a9162cd65e219457328e298a673f6176446493db17cf7af6f90dc0 + checksum: 10c0/eaec29ef6ec201786c606176235dced4af1922d5ac56c6b0993ad2e7d87464a32702d9b28cae9a76e8527f741b50cbc31d4c646f45d02dc69d520f241b3e7878 languageName: node linkType: hard @@ -1691,59 +1705,59 @@ __metadata: languageName: node linkType: hard -"@csstools/postcss-gamut-mapping@npm:^1.0.10": - version: 1.0.10 - resolution: "@csstools/postcss-gamut-mapping@npm:1.0.10" +"@csstools/postcss-gamut-mapping@npm:^1.0.11": + version: 1.0.11 + resolution: "@csstools/postcss-gamut-mapping@npm:1.0.11" dependencies: - "@csstools/css-color-parser": "npm:^2.0.3" - "@csstools/css-parser-algorithms": "npm:^2.7.0" - "@csstools/css-tokenizer": "npm:^2.3.2" + "@csstools/css-color-parser": "npm:^2.0.4" + "@csstools/css-parser-algorithms": "npm:^2.7.1" + "@csstools/css-tokenizer": "npm:^2.4.1" peerDependencies: postcss: ^8.4 - checksum: 10c0/6c2dab6a84f81904bed89cb584bd9bc6a904b49a4fa315b17be65c7d68baefe592561ee439660d5602b7481bac3be9a93189dc45404764524495400f34c6b6e6 + checksum: 10c0/29e755013f1d1de34eb62a931ed410d2830ca3dfc81476cb3c72d9d3260b85a9adedc51aa548550c6e308f3f9640c489e6953db40e9cac9835d0421d5b14ef1f languageName: node linkType: hard -"@csstools/postcss-gradients-interpolation-method@npm:^4.0.18": - version: 4.0.18 - resolution: "@csstools/postcss-gradients-interpolation-method@npm:4.0.18" +"@csstools/postcss-gradients-interpolation-method@npm:^4.0.20": + version: 4.0.20 + resolution: "@csstools/postcss-gradients-interpolation-method@npm:4.0.20" dependencies: - "@csstools/css-color-parser": "npm:^2.0.3" - "@csstools/css-parser-algorithms": "npm:^2.7.0" - "@csstools/css-tokenizer": "npm:^2.3.2" - "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0" + "@csstools/css-color-parser": "npm:^2.0.4" + "@csstools/css-parser-algorithms": "npm:^2.7.1" + "@csstools/css-tokenizer": "npm:^2.4.1" + "@csstools/postcss-progressive-custom-properties": "npm:^3.3.0" "@csstools/utilities": "npm:^1.0.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/23c431068ac205392b4953dbce411e208e79e221ba8030c5e23c0b82e8fd53bc3bc4f2cdc47050f5d91a4ac69cb80f4f1853b213aa8072fa60a6cb6ff0621e04 + checksum: 10c0/6588825a72a1471e2d6036c8cf7dbad2bf05f369d96dbdd68ff5ce7ff91803b8ee1146f5f1bf6f3ab6299944549da872914664c3f9e8ae5a31847f76f0085c74 languageName: node linkType: hard -"@csstools/postcss-hwb-function@npm:^3.0.16": - version: 3.0.16 - resolution: "@csstools/postcss-hwb-function@npm:3.0.16" +"@csstools/postcss-hwb-function@npm:^3.0.18": + version: 3.0.18 + resolution: "@csstools/postcss-hwb-function@npm:3.0.18" dependencies: - "@csstools/css-color-parser": "npm:^2.0.3" - "@csstools/css-parser-algorithms": "npm:^2.7.0" - "@csstools/css-tokenizer": "npm:^2.3.2" - "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0" + "@csstools/css-color-parser": "npm:^2.0.4" + "@csstools/css-parser-algorithms": "npm:^2.7.1" + "@csstools/css-tokenizer": "npm:^2.4.1" + "@csstools/postcss-progressive-custom-properties": "npm:^3.3.0" "@csstools/utilities": "npm:^1.0.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/4deca8831a69038aff719a77df92c53578bb28e23cc61dc4ea7b1d912b1b685683a9c6232396c2616948ac2e8488ad1e2009c9c8ed30c493d97ba8ad37b6418d + checksum: 10c0/e9d76b0b2f9c54920124ca1804b49e3f5b26e003729418b5ef4b340ff1baa4779da1c02be618888fdbcc2d0747182352efbbd3ffe128e2417928c35c25443789 languageName: node linkType: hard -"@csstools/postcss-ic-unit@npm:^3.0.6": - version: 3.0.6 - resolution: "@csstools/postcss-ic-unit@npm:3.0.6" +"@csstools/postcss-ic-unit@npm:^3.0.7": + version: 3.0.7 + resolution: "@csstools/postcss-ic-unit@npm:3.0.7" dependencies: - "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0" + "@csstools/postcss-progressive-custom-properties": "npm:^3.3.0" "@csstools/utilities": "npm:^1.0.0" postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/a4b962327d433419fdcfdcf620ce6a5cf09aa3c93029ad08b035df1e2bc35caae31de49f1d14218de0656fced35c0d2e07e5ff7b8099c29dbfb40395fc283234 + checksum: 10c0/2add905b75860c64d7174886fecfc76d86e3818f42f003f4bbfc0604cc7f0f31c6dbd1651e6b9512fea876190d80033578ae49e813b64b17c8cf3b1f03d8e146 languageName: node linkType: hard @@ -1768,17 +1782,17 @@ __metadata: languageName: node linkType: hard -"@csstools/postcss-light-dark-function@npm:^1.0.6": - version: 1.0.6 - resolution: "@csstools/postcss-light-dark-function@npm:1.0.6" +"@csstools/postcss-light-dark-function@npm:^1.0.8": + version: 1.0.8 + resolution: "@csstools/postcss-light-dark-function@npm:1.0.8" dependencies: - "@csstools/css-parser-algorithms": "npm:^2.7.0" - "@csstools/css-tokenizer": "npm:^2.3.2" - "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0" + "@csstools/css-parser-algorithms": "npm:^2.7.1" + "@csstools/css-tokenizer": "npm:^2.4.1" + "@csstools/postcss-progressive-custom-properties": "npm:^3.3.0" "@csstools/utilities": "npm:^1.0.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/6b2c64860d789cd3e3ce875c01259333911f6e32a751a7475604de8022c13abcb578e5cb941b51bd3a2022bee883df3f6b64800c6e3559b06da283d968aeb615 + checksum: 10c0/78fa6d799d38f14af1b32b534eedbec9478033e1fbc5a4e820f2421e865673d010b69b391546686ceb408ead64d79bb4eba2a4fb1fc9f0de70ff21e3ff8477c6 languageName: node linkType: hard @@ -1820,42 +1834,42 @@ __metadata: languageName: node linkType: hard -"@csstools/postcss-logical-viewport-units@npm:^2.0.10": - version: 2.0.10 - resolution: "@csstools/postcss-logical-viewport-units@npm:2.0.10" +"@csstools/postcss-logical-viewport-units@npm:^2.0.11": + version: 2.0.11 + resolution: "@csstools/postcss-logical-viewport-units@npm:2.0.11" dependencies: - "@csstools/css-tokenizer": "npm:^2.3.2" + "@csstools/css-tokenizer": "npm:^2.4.1" "@csstools/utilities": "npm:^1.0.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/fe142b11e0e8ccab4667cc5db90b45e67b7d11eaf5c038e91d867e1b18a315ef0859114185aeb48fdc1ce05986be8b644d6157fe9e19da7281f7023c99eb8877 + checksum: 10c0/20207e9b7fc3ab52df5fcd06fde71fca4fd22bd6bd451cfc2ec6ea69994708b7fc5381e203dc4367293a8de00b1eca7a3ebe89cfa9b933d2f2cb8e3ac4d5aa86 languageName: node linkType: hard -"@csstools/postcss-media-minmax@npm:^1.1.7": - version: 1.1.7 - resolution: "@csstools/postcss-media-minmax@npm:1.1.7" +"@csstools/postcss-media-minmax@npm:^1.1.8": + version: 1.1.8 + resolution: "@csstools/postcss-media-minmax@npm:1.1.8" dependencies: - "@csstools/css-calc": "npm:^1.2.3" - "@csstools/css-parser-algorithms": "npm:^2.7.0" - "@csstools/css-tokenizer": "npm:^2.3.2" - "@csstools/media-query-list-parser": "npm:^2.1.12" + "@csstools/css-calc": "npm:^1.2.4" + "@csstools/css-parser-algorithms": "npm:^2.7.1" + "@csstools/css-tokenizer": "npm:^2.4.1" + "@csstools/media-query-list-parser": "npm:^2.1.13" peerDependencies: postcss: ^8.4 - checksum: 10c0/a02943a17b540cbd909b55bbb1f8c9331badc51b613279bbdb7127c9921a5d0675bb41675a3b4d0f15e9586120e5a96d9b9786b63b2c594fbb3a238e860c6ad8 + checksum: 10c0/7d666905282c7a89387dbce84f3429bad04870e0de264c5b1ce3e6f042b8eb72d585a18b2d7ac5e1a8c7f6785892da3cc7f6ea0b48069b06e9d383bdbc149b4a languageName: node linkType: hard -"@csstools/postcss-media-queries-aspect-ratio-number-values@npm:^2.0.10": - version: 2.0.10 - resolution: "@csstools/postcss-media-queries-aspect-ratio-number-values@npm:2.0.10" +"@csstools/postcss-media-queries-aspect-ratio-number-values@npm:^2.0.11": + version: 2.0.11 + resolution: "@csstools/postcss-media-queries-aspect-ratio-number-values@npm:2.0.11" dependencies: - "@csstools/css-parser-algorithms": "npm:^2.7.0" - "@csstools/css-tokenizer": "npm:^2.3.2" - "@csstools/media-query-list-parser": "npm:^2.1.12" + "@csstools/css-parser-algorithms": "npm:^2.7.1" + "@csstools/css-tokenizer": "npm:^2.4.1" + "@csstools/media-query-list-parser": "npm:^2.1.13" peerDependencies: postcss: ^8.4 - checksum: 10c0/d7879e72df98d9fe2e5d85a64837e7a73c2df1aea8659d65516f0acb070317edd353531882f0bdfd81510703d1da30d6da861052a0bda85fde1f9eab94b1e467 + checksum: 10c0/b4023a1951b7661196332852ce714a4e2fb4f1a67164ec0944e28a009b389e59c67e9de790920fcd082b122276414dd39c12ae12a4566e59e1bbcc794560a870 languageName: node linkType: hard @@ -1882,44 +1896,44 @@ __metadata: languageName: node linkType: hard -"@csstools/postcss-oklab-function@npm:^3.0.17": - version: 3.0.17 - resolution: "@csstools/postcss-oklab-function@npm:3.0.17" +"@csstools/postcss-oklab-function@npm:^3.0.19": + version: 3.0.19 + resolution: "@csstools/postcss-oklab-function@npm:3.0.19" dependencies: - "@csstools/css-color-parser": "npm:^2.0.3" - "@csstools/css-parser-algorithms": "npm:^2.7.0" - "@csstools/css-tokenizer": "npm:^2.3.2" - "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0" + "@csstools/css-color-parser": "npm:^2.0.4" + "@csstools/css-parser-algorithms": "npm:^2.7.1" + "@csstools/css-tokenizer": "npm:^2.4.1" + "@csstools/postcss-progressive-custom-properties": "npm:^3.3.0" "@csstools/utilities": "npm:^1.0.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/ff27a4b6fd8490439aa0f3c91ffa2a42a8cf539d7306d9329cef7ca59f28317cee40253f402d19a18c196471fd39a05842d2974d92f1b131dc748074d91ac4ee + checksum: 10c0/2909f76ba408c9f60b61c479994c96200b0e1d3dbf524d5ae6dc5ca1e21d38caf974595e0d071c3900dbe3568376928085dd811aa24ea3e715bcd9de26fb0fa9 languageName: node linkType: hard -"@csstools/postcss-progressive-custom-properties@npm:^3.2.0": - version: 3.2.0 - resolution: "@csstools/postcss-progressive-custom-properties@npm:3.2.0" +"@csstools/postcss-progressive-custom-properties@npm:^3.3.0": + version: 3.3.0 + resolution: "@csstools/postcss-progressive-custom-properties@npm:3.3.0" dependencies: postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/829880844fbbeef1c67e0b380057e574659b4caed38c8414c17d7eb4a0cc727afa1cd74a889bc7ca79c819ecae757810356706901cf6bb677a36ca123915cbb7 + checksum: 10c0/6c9987d65049a70b5090dcfe42fde9ab2b3cb88911a81bb6651ed81c8baf99502ff2cbec0cb3e022426fa994b558b4bf33fd791ccdcdf683dde75b4865d34f39 languageName: node linkType: hard -"@csstools/postcss-relative-color-syntax@npm:^2.0.17": - version: 2.0.17 - resolution: "@csstools/postcss-relative-color-syntax@npm:2.0.17" +"@csstools/postcss-relative-color-syntax@npm:^2.0.19": + version: 2.0.19 + resolution: "@csstools/postcss-relative-color-syntax@npm:2.0.19" dependencies: - "@csstools/css-color-parser": "npm:^2.0.3" - "@csstools/css-parser-algorithms": "npm:^2.7.0" - "@csstools/css-tokenizer": "npm:^2.3.2" - "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0" + "@csstools/css-color-parser": "npm:^2.0.4" + "@csstools/css-parser-algorithms": "npm:^2.7.1" + "@csstools/css-tokenizer": "npm:^2.4.1" + "@csstools/postcss-progressive-custom-properties": "npm:^3.3.0" "@csstools/utilities": "npm:^1.0.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/46226351b3825323e3496dcee44ff354cd3ccc9241d837659e1311f428f0b4dc878d9bb762cbb8f63243b7af346728ab7a46c311f9dc38bb609147523c698eab + checksum: 10c0/f0aff764f4889ff664b6fa94ddfa5a22daf39354aa2d2ac0eab893eb3ed841b7d2a72131393334d6a5379445fc80f92ab5bd63d4dc3b43746bc7c9055da46591 languageName: node linkType: hard @@ -1934,16 +1948,16 @@ __metadata: languageName: node linkType: hard -"@csstools/postcss-stepped-value-functions@npm:^3.0.9": - version: 3.0.9 - resolution: "@csstools/postcss-stepped-value-functions@npm:3.0.9" +"@csstools/postcss-stepped-value-functions@npm:^3.0.10": + version: 3.0.10 + resolution: "@csstools/postcss-stepped-value-functions@npm:3.0.10" dependencies: - "@csstools/css-calc": "npm:^1.2.3" - "@csstools/css-parser-algorithms": "npm:^2.7.0" - "@csstools/css-tokenizer": "npm:^2.3.2" + "@csstools/css-calc": "npm:^1.2.4" + "@csstools/css-parser-algorithms": "npm:^2.7.1" + "@csstools/css-tokenizer": "npm:^2.4.1" peerDependencies: postcss: ^8.4 - checksum: 10c0/bafe80947abc8613903f1f3f1939ece9780696774f15960aef229733e40e483dc2830145426d49c4f6d0b1dabb35f812c8a2dda0d0dcddc930321e36b5c6ca0b + checksum: 10c0/f9ebe50fb884d002aa40070196a827816f635b891fd2147ae5ddf1ad6df5bddbb50783d6786897bb3dffa33052565e38289392040cf4454aaa179ab00353117d languageName: node linkType: hard @@ -1959,16 +1973,16 @@ __metadata: languageName: node linkType: hard -"@csstools/postcss-trigonometric-functions@npm:^3.0.9": - version: 3.0.9 - resolution: "@csstools/postcss-trigonometric-functions@npm:3.0.9" +"@csstools/postcss-trigonometric-functions@npm:^3.0.10": + version: 3.0.10 + resolution: "@csstools/postcss-trigonometric-functions@npm:3.0.10" dependencies: - "@csstools/css-calc": "npm:^1.2.3" - "@csstools/css-parser-algorithms": "npm:^2.7.0" - "@csstools/css-tokenizer": "npm:^2.3.2" + "@csstools/css-calc": "npm:^1.2.4" + "@csstools/css-parser-algorithms": "npm:^2.7.1" + "@csstools/css-tokenizer": "npm:^2.4.1" peerDependencies: postcss: ^8.4 - checksum: 10c0/7a439d31a63d35986dab634d9e415f7ce7c32a2d3d382052b5b730a259a12e44c5f1b14e318d79086253e3d5d4f7d942d0e7317d92eb3421dd08824eebec45fb + checksum: 10c0/31adcc66510d9788ccb0669d2761517a6135b13692007d8e4334bc0e8d3515dfecfbdcd04e060d0c09a0f5fc2f12db92221b9d53e92b65b044c89cde9a3424cb languageName: node linkType: hard @@ -2899,6 +2913,7 @@ __metadata: tiny-queue: "npm:^0.2.1" twitter-text: "npm:3.1.0" typescript: "npm:^5.0.4" + use-debounce: "npm:^10.0.0" webpack: "npm:^4.47.0" webpack-assets-manifest: "npm:^4.0.6" webpack-bundle-analyzer: "npm:^4.8.0" @@ -3360,8 +3375,8 @@ __metadata: linkType: hard "@testing-library/dom@npm:^10.2.0": - version: 10.2.0 - resolution: "@testing-library/dom@npm:10.2.0" + version: 10.3.1 + resolution: "@testing-library/dom@npm:10.3.1" dependencies: "@babel/code-frame": "npm:^7.10.4" "@babel/runtime": "npm:^7.12.5" @@ -3371,7 +3386,7 @@ __metadata: dom-accessibility-api: "npm:^0.5.9" lz-string: "npm:^1.5.0" pretty-format: "npm:^27.0.2" - checksum: 10c0/de582dfbeb632436547a0ca5851b5a714a4a17f8e96ab3dc4fb4e454eef52c912b648b7cb6e9fdf477f3eeef97e698f3250f0ce50846f39d04677a44169209f2 + checksum: 10c0/e898475cd4932225c2962bf9f94353d7d88462c8912881af8e9866cee714c967b21badb0895ec8626123759cddc6663bc40300b1d1bf789957a603086eda6329 languageName: node linkType: hard @@ -5672,7 +5687,7 @@ __metadata: languageName: node linkType: hard -"browserslist@npm:^4.0.0, browserslist@npm:^4.22.2, browserslist@npm:^4.23.0, browserslist@npm:^4.23.1": +"browserslist@npm:^4.0.0, browserslist@npm:^4.23.0, browserslist@npm:^4.23.1": version: 4.23.1 resolution: "browserslist@npm:4.23.1" dependencies: @@ -6388,12 +6403,12 @@ __metadata: languageName: node linkType: hard -"core-js-compat@npm:^3.31.0, core-js-compat@npm:^3.36.1": - version: 3.36.1 - resolution: "core-js-compat@npm:3.36.1" +"core-js-compat@npm:^3.36.1, core-js-compat@npm:^3.37.1": + version: 3.37.1 + resolution: "core-js-compat@npm:3.37.1" dependencies: browserslist: "npm:^4.23.0" - checksum: 10c0/70fba18a4095cd8ac04e5ba8cee251e328935859cf2851c1f67770068ea9f9fe71accb1b7de17cd3c9a28d304a4c41712bd9aa895110ebb6e3be71b666b029d1 + checksum: 10c0/4e2da9c900f2951a57947af7aeef4d16f2c75d7f7e966c0d0b62953f65225003ade5e84d3ae98847f65b24c109c606821d9dc925db8ca418fb761e7c81963c2a languageName: node linkType: hard @@ -6736,10 +6751,10 @@ __metadata: languageName: node linkType: hard -"cssdb@npm:^8.0.0": - version: 8.0.0 - resolution: "cssdb@npm:8.0.0" - checksum: 10c0/d9a31b760214624352000b16a8f7194c357f66b6c445e663ab58dd03b6f0f53efaaca6d6f96200d666e205894d2d1c346664ad993d9522ff9fc1c331804a8d62 +"cssdb@npm:^8.1.0": + version: 8.1.0 + resolution: "cssdb@npm:8.1.0" + checksum: 10c0/1fa1f1566c7e9964f5c71e443583eaba16a90933a3ef6803815c4281d084b75da948c415bade33d7085894fe0929c082fcb3135bf4400048cfff40d227ebd5dd languageName: node linkType: hard @@ -6752,16 +6767,16 @@ __metadata: languageName: node linkType: hard -"cssnano-preset-default@npm:^7.0.3": - version: 7.0.3 - resolution: "cssnano-preset-default@npm:7.0.3" +"cssnano-preset-default@npm:^7.0.4": + version: 7.0.4 + resolution: "cssnano-preset-default@npm:7.0.4" dependencies: browserslist: "npm:^4.23.1" css-declaration-sorter: "npm:^7.2.0" cssnano-utils: "npm:^5.0.0" postcss-calc: "npm:^10.0.0" postcss-colormin: "npm:^7.0.1" - postcss-convert-values: "npm:^7.0.1" + postcss-convert-values: "npm:^7.0.2" postcss-discard-comments: "npm:^7.0.1" postcss-discard-duplicates: "npm:^7.0.0" postcss-discard-empty: "npm:^7.0.0" @@ -6788,7 +6803,7 @@ __metadata: postcss-unique-selectors: "npm:^7.0.1" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/ab3e51003efed6542a12d43c10ca693ab26138a1d035697b9be8f07e084e37a78617cbb8028b0a7e7841302ec151f4ecf35cbd763efe291846b62c35ea4c0bb4 + checksum: 10c0/0083821e778bdf7b8aa9589408a01a717be730f73584e7b81756a6fcf87af05b8f17342025e666572a8d573cc30783f2d817b0f7ad63670398bc3135b017ccad languageName: node linkType: hard @@ -6802,14 +6817,14 @@ __metadata: linkType: hard "cssnano@npm:^7.0.0": - version: 7.0.3 - resolution: "cssnano@npm:7.0.3" + version: 7.0.4 + resolution: "cssnano@npm:7.0.4" dependencies: - cssnano-preset-default: "npm:^7.0.3" + cssnano-preset-default: "npm:^7.0.4" lilconfig: "npm:^3.1.2" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/4cbcd1e0ebe0bd83196cc5b16b3a60d3ebc98326c79b2f71df597bb73c8e3ee1f42b89159d7a038acc398251184d648d9dd516f4194e46746f3af6fa74b4aec7 + checksum: 10c0/3939a0b37b11cb4bae92f7916517c7ba21257551f92517b49a640d5df32e855fb7e73321f4be44d2c2de578309c05d711cdcb1976e95607b1b7f92bd4cbd1350 languageName: node linkType: hard @@ -9019,8 +9034,8 @@ __metadata: linkType: hard "glob@npm:^10.2.2, glob@npm:^10.2.6, glob@npm:^10.3.10": - version: 10.4.2 - resolution: "glob@npm:10.4.2" + version: 10.4.5 + resolution: "glob@npm:10.4.5" dependencies: foreground-child: "npm:^3.1.0" jackspeak: "npm:^3.1.2" @@ -9030,7 +9045,7 @@ __metadata: path-scurry: "npm:^1.11.1" bin: glob: dist/esm/bin.mjs - checksum: 10c0/2c7296695fa75a935f3ad17dc62e4e170a8bb8752cf64d328be8992dd6ad40777939003754e10e9741ff8fbe43aa52fba32d6930d0ffa0e3b74bc3fb5eebaa2f + checksum: 10c0/19a9759ea77b8e3ca0a43c2f07ecddc2ad46216b786bb8f993c445aee80d345925a21e5280c7b7c6c59e860a0154b84e4b2b60321fea92cd3c56b4a7489f160e languageName: node linkType: hard @@ -13206,8 +13221,8 @@ __metadata: linkType: hard "pino@npm:^9.0.0": - version: 9.2.0 - resolution: "pino@npm:9.2.0" + version: 9.3.1 + resolution: "pino@npm:9.3.1" dependencies: atomic-sleep: "npm:^1.0.0" fast-redact: "npm:^3.1.1" @@ -13222,7 +13237,7 @@ __metadata: thread-stream: "npm:^3.0.0" bin: pino: bin.js - checksum: 10c0/5fbd226ff7dab0961232b5aa5eca0530cdc5bb29f6bf17d929e42239293b1a587a26cc311db6abc1090c9dd57e8f7b031eae341b41d00d4a642b4f1736474c80 + checksum: 10c0/ab1e81b3e5a91852136d80a592939883eeb81442e5d3a2c070bdbdeb47c5aaa297ead246530b10eb6d5ff59445f4645d1333d342f255d9f002f73aea843e74ee languageName: node linkType: hard @@ -13310,18 +13325,18 @@ __metadata: languageName: node linkType: hard -"postcss-color-functional-notation@npm:^6.0.12": - version: 6.0.12 - resolution: "postcss-color-functional-notation@npm:6.0.12" +"postcss-color-functional-notation@npm:^6.0.14": + version: 6.0.14 + resolution: "postcss-color-functional-notation@npm:6.0.14" dependencies: - "@csstools/css-color-parser": "npm:^2.0.3" - "@csstools/css-parser-algorithms": "npm:^2.7.0" - "@csstools/css-tokenizer": "npm:^2.3.2" - "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0" + "@csstools/css-color-parser": "npm:^2.0.4" + "@csstools/css-parser-algorithms": "npm:^2.7.1" + "@csstools/css-tokenizer": "npm:^2.4.1" + "@csstools/postcss-progressive-custom-properties": "npm:^3.3.0" "@csstools/utilities": "npm:^1.0.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/2e8faecd2609e1b4eb8c1cab21ecca5e746916795df20e6997d66eb61c29fbb01d3e75fef3e0b3e1c181918a2186570441b81779b1fc429d6d8823fbfa164231 + checksum: 10c0/fdc5188e19c3923da32fe08d50e55d0b3ca1cedf99f46331baa0a4bbd73a1fc6b4447b0346ab16049032b56ab84b98b4758a0ede7c237637e35a4cc60caac141 languageName: node linkType: hard @@ -13363,58 +13378,58 @@ __metadata: languageName: node linkType: hard -"postcss-convert-values@npm:^7.0.1": - version: 7.0.1 - resolution: "postcss-convert-values@npm:7.0.1" +"postcss-convert-values@npm:^7.0.2": + version: 7.0.2 + resolution: "postcss-convert-values@npm:7.0.2" dependencies: browserslist: "npm:^4.23.1" postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4.31 - checksum: 10c0/612f025f179f0f2ad7365db8c0b423614dcb8e1e4061875a4691a39dede0bca758d1a8f9f5c8b08e12af053e9e884f65ca5626ccc723d5b3f420650d67fe3046 + checksum: 10c0/beb59faf6aae97e6d3c233c5e6ed06cc60d65c49eec576036e3d0da1a831a1e827e3d41f5e81d016440b4f0bdf1406268ae069c4d5b38a6667b310c3da079d22 languageName: node linkType: hard -"postcss-custom-media@npm:^10.0.7": - version: 10.0.7 - resolution: "postcss-custom-media@npm:10.0.7" +"postcss-custom-media@npm:^10.0.8": + version: 10.0.8 + resolution: "postcss-custom-media@npm:10.0.8" dependencies: - "@csstools/cascade-layer-name-parser": "npm:^1.0.12" - "@csstools/css-parser-algorithms": "npm:^2.7.0" - "@csstools/css-tokenizer": "npm:^2.3.2" - "@csstools/media-query-list-parser": "npm:^2.1.12" + "@csstools/cascade-layer-name-parser": "npm:^1.0.13" + "@csstools/css-parser-algorithms": "npm:^2.7.1" + "@csstools/css-tokenizer": "npm:^2.4.1" + "@csstools/media-query-list-parser": "npm:^2.1.13" peerDependencies: postcss: ^8.4 - checksum: 10c0/4171385ab9370806861dcf7597e53fd6aa1862e77b475c9c565c95bfcc2b950f920f8da26a6dbec42e257388bca97c274635662b5e81fe3905b5e37babe06569 + checksum: 10c0/673ca0058a2f2357a83b33ce00bbeee7cda92621c08472fa55d7ac7ae56f5f8f979132528d537f2dedf715d35a8f9b14b2f0ab6b45423d49e2554c19aab3c827 languageName: node linkType: hard -"postcss-custom-properties@npm:^13.3.11": - version: 13.3.11 - resolution: "postcss-custom-properties@npm:13.3.11" +"postcss-custom-properties@npm:^13.3.12": + version: 13.3.12 + resolution: "postcss-custom-properties@npm:13.3.12" dependencies: - "@csstools/cascade-layer-name-parser": "npm:^1.0.12" - "@csstools/css-parser-algorithms": "npm:^2.7.0" - "@csstools/css-tokenizer": "npm:^2.3.2" + "@csstools/cascade-layer-name-parser": "npm:^1.0.13" + "@csstools/css-parser-algorithms": "npm:^2.7.1" + "@csstools/css-tokenizer": "npm:^2.4.1" "@csstools/utilities": "npm:^1.0.0" postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/4aa95628aa5d5b6df4dfeedbc3891b9666db88d75930cadc14d2fbba0a1b72f4e3cc3d83b5a0c0b8ce44f85b4fda6ebd7fe7792a1abc0a14d7d63b9f170d299c + checksum: 10c0/6af9f6ac94a6ac887749cd38d4586349f6aca29269ebfdb837019a3ba0130032f0ff4899b431b5c348f4ac79a7b16fb7300a256514a6a68e32a63489c18a70e7 languageName: node linkType: hard -"postcss-custom-selectors@npm:^7.1.11": - version: 7.1.11 - resolution: "postcss-custom-selectors@npm:7.1.11" +"postcss-custom-selectors@npm:^7.1.12": + version: 7.1.12 + resolution: "postcss-custom-selectors@npm:7.1.12" dependencies: - "@csstools/cascade-layer-name-parser": "npm:^1.0.12" - "@csstools/css-parser-algorithms": "npm:^2.7.0" - "@csstools/css-tokenizer": "npm:^2.3.2" + "@csstools/cascade-layer-name-parser": "npm:^1.0.13" + "@csstools/css-parser-algorithms": "npm:^2.7.1" + "@csstools/css-tokenizer": "npm:^2.4.1" postcss-selector-parser: "npm:^6.1.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/f37d2e34239e868b35b7970ec97a7a8f657a9f92ed2b221af44f19949f7c3aedcecd0abb5fa1acb120c5ceffdf7a20869338956a37d7bfc37a83d8088f5d3dd2 + checksum: 10c0/78a7930e4f97c42b544f00c06272264432d47f9df777684b57673bb971b7ab49d5d6fb9289a5a869125e7e50dcd0cad65cf8846501253084b73a42ffab41b2c5 languageName: node linkType: hard @@ -13467,16 +13482,16 @@ __metadata: languageName: node linkType: hard -"postcss-double-position-gradients@npm:^5.0.6": - version: 5.0.6 - resolution: "postcss-double-position-gradients@npm:5.0.6" +"postcss-double-position-gradients@npm:^5.0.7": + version: 5.0.7 + resolution: "postcss-double-position-gradients@npm:5.0.7" dependencies: - "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0" + "@csstools/postcss-progressive-custom-properties": "npm:^3.3.0" "@csstools/utilities": "npm:^1.0.0" postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/9b24b13043fe506c0ddd94e707fe4f21f4f9a6c05ca49a4f45e23412951fd6a4cfa0095002d10b322ca8be60df0badae3715a27eefdeb7bf8da4fdd1ecd5d7a2 + checksum: 10c0/52d96a34aa3e2e251edeaa2d4c2dd106c687f7910ec18266693656c0edd003384b927c855cecac07f52b5c7bdccd140abdc7e27082ce4c3755e3a966206a2cb9 languageName: node linkType: hard @@ -13532,18 +13547,18 @@ __metadata: languageName: node linkType: hard -"postcss-lab-function@npm:^6.0.17": - version: 6.0.17 - resolution: "postcss-lab-function@npm:6.0.17" +"postcss-lab-function@npm:^6.0.19": + version: 6.0.19 + resolution: "postcss-lab-function@npm:6.0.19" dependencies: - "@csstools/css-color-parser": "npm:^2.0.3" - "@csstools/css-parser-algorithms": "npm:^2.7.0" - "@csstools/css-tokenizer": "npm:^2.3.2" - "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0" + "@csstools/css-color-parser": "npm:^2.0.4" + "@csstools/css-parser-algorithms": "npm:^2.7.1" + "@csstools/css-tokenizer": "npm:^2.4.1" + "@csstools/postcss-progressive-custom-properties": "npm:^3.3.0" "@csstools/utilities": "npm:^1.0.0" peerDependencies: postcss: ^8.4 - checksum: 10c0/a331f188b02cc8beb315150232b6b58bc5793e8d61585973d352a9b4d370b908ff354ccf9ea1ba20a956fd37ea4ada918ea975c8d4f69e850d26edf0106436e8 + checksum: 10c0/d9a91fb57dcbe967260df86e22ca335a5444f1f34d128fa7b5dbf2522772f2138ad708f1f20f0a59035d66ed736e82972ca7f1b669a157534a17ee8898af1921 languageName: node linkType: hard @@ -13864,60 +13879,61 @@ __metadata: linkType: hard "postcss-preset-env@npm:^9.5.2": - version: 9.5.15 - resolution: "postcss-preset-env@npm:9.5.15" + version: 9.6.0 + resolution: "postcss-preset-env@npm:9.6.0" dependencies: "@csstools/postcss-cascade-layers": "npm:^4.0.6" - "@csstools/postcss-color-function": "npm:^3.0.17" - "@csstools/postcss-color-mix-function": "npm:^2.0.17" - "@csstools/postcss-exponential-functions": "npm:^1.0.8" + "@csstools/postcss-color-function": "npm:^3.0.19" + "@csstools/postcss-color-mix-function": "npm:^2.0.19" + "@csstools/postcss-content-alt-text": "npm:^1.0.0" + "@csstools/postcss-exponential-functions": "npm:^1.0.9" "@csstools/postcss-font-format-keywords": "npm:^3.0.2" - "@csstools/postcss-gamut-mapping": "npm:^1.0.10" - "@csstools/postcss-gradients-interpolation-method": "npm:^4.0.18" - "@csstools/postcss-hwb-function": "npm:^3.0.16" - "@csstools/postcss-ic-unit": "npm:^3.0.6" + "@csstools/postcss-gamut-mapping": "npm:^1.0.11" + "@csstools/postcss-gradients-interpolation-method": "npm:^4.0.20" + "@csstools/postcss-hwb-function": "npm:^3.0.18" + "@csstools/postcss-ic-unit": "npm:^3.0.7" "@csstools/postcss-initial": "npm:^1.0.1" "@csstools/postcss-is-pseudo-class": "npm:^4.0.8" - "@csstools/postcss-light-dark-function": "npm:^1.0.6" + "@csstools/postcss-light-dark-function": "npm:^1.0.8" "@csstools/postcss-logical-float-and-clear": "npm:^2.0.1" "@csstools/postcss-logical-overflow": "npm:^1.0.1" "@csstools/postcss-logical-overscroll-behavior": "npm:^1.0.1" "@csstools/postcss-logical-resize": "npm:^2.0.1" - "@csstools/postcss-logical-viewport-units": "npm:^2.0.10" - "@csstools/postcss-media-minmax": "npm:^1.1.7" - "@csstools/postcss-media-queries-aspect-ratio-number-values": "npm:^2.0.10" + "@csstools/postcss-logical-viewport-units": "npm:^2.0.11" + "@csstools/postcss-media-minmax": "npm:^1.1.8" + "@csstools/postcss-media-queries-aspect-ratio-number-values": "npm:^2.0.11" "@csstools/postcss-nested-calc": "npm:^3.0.2" "@csstools/postcss-normalize-display-values": "npm:^3.0.2" - "@csstools/postcss-oklab-function": "npm:^3.0.17" - "@csstools/postcss-progressive-custom-properties": "npm:^3.2.0" - "@csstools/postcss-relative-color-syntax": "npm:^2.0.17" + "@csstools/postcss-oklab-function": "npm:^3.0.19" + "@csstools/postcss-progressive-custom-properties": "npm:^3.3.0" + "@csstools/postcss-relative-color-syntax": "npm:^2.0.19" "@csstools/postcss-scope-pseudo-class": "npm:^3.0.1" - "@csstools/postcss-stepped-value-functions": "npm:^3.0.9" + "@csstools/postcss-stepped-value-functions": "npm:^3.0.10" "@csstools/postcss-text-decoration-shorthand": "npm:^3.0.7" - "@csstools/postcss-trigonometric-functions": "npm:^3.0.9" + "@csstools/postcss-trigonometric-functions": "npm:^3.0.10" "@csstools/postcss-unset-value": "npm:^3.0.1" autoprefixer: "npm:^10.4.19" browserslist: "npm:^4.23.1" css-blank-pseudo: "npm:^6.0.2" css-has-pseudo: "npm:^6.0.5" css-prefers-color-scheme: "npm:^9.0.1" - cssdb: "npm:^8.0.0" + cssdb: "npm:^8.1.0" postcss-attribute-case-insensitive: "npm:^6.0.3" postcss-clamp: "npm:^4.1.0" - postcss-color-functional-notation: "npm:^6.0.12" + postcss-color-functional-notation: "npm:^6.0.14" postcss-color-hex-alpha: "npm:^9.0.4" postcss-color-rebeccapurple: "npm:^9.0.3" - postcss-custom-media: "npm:^10.0.7" - postcss-custom-properties: "npm:^13.3.11" - postcss-custom-selectors: "npm:^7.1.11" + postcss-custom-media: "npm:^10.0.8" + postcss-custom-properties: "npm:^13.3.12" + postcss-custom-selectors: "npm:^7.1.12" postcss-dir-pseudo-class: "npm:^8.0.1" - postcss-double-position-gradients: "npm:^5.0.6" + postcss-double-position-gradients: "npm:^5.0.7" postcss-focus-visible: "npm:^9.0.1" postcss-focus-within: "npm:^8.0.1" postcss-font-variant: "npm:^5.0.0" postcss-gap-properties: "npm:^5.0.1" postcss-image-set-function: "npm:^6.0.3" - postcss-lab-function: "npm:^6.0.17" + postcss-lab-function: "npm:^6.0.19" postcss-logical: "npm:^7.0.1" postcss-nesting: "npm:^12.1.5" postcss-opacity-percentage: "npm:^2.0.0" @@ -13929,7 +13945,7 @@ __metadata: postcss-selector-not: "npm:^7.0.2" peerDependencies: postcss: ^8.4 - checksum: 10c0/e2ee0b5d7dbaddb82ff6d51b5882120862d6be184973ae3d55642923183ab441d421d5f9810fe02e680a70dbc85b20b1c2eb02c68f167dcaf3ef80a71dd40e78 + checksum: 10c0/caa91ba4d3b897d43ab2669b3edf40b24ef32c88e23b113be8956412e64b28deed6ba229c331848fcbc0d143bfde155173fb1e1ada9ccae5037b2ee8f7e554b7 languageName: node linkType: hard @@ -15471,15 +15487,15 @@ __metadata: linkType: hard "sass@npm:^1.62.1": - version: 1.77.6 - resolution: "sass@npm:1.77.6" + version: 1.77.8 + resolution: "sass@npm:1.77.8" dependencies: chokidar: "npm:>=3.0.0 <4.0.0" immutable: "npm:^4.0.0" source-map-js: "npm:>=0.6.2 <2.0.0" bin: sass: sass.js - checksum: 10c0/fe5a393c0aa29eda9f83c06be9b94788b61fe8bad0616ee6e3a25d21ab504f430d40c0064fdca89b02b8e426411ae6dcd906c91f2e48c263575c3d392b6daeb1 + checksum: 10c0/2bfd62794070352c804f949e69bd8bb5b4ec846deeb924251b2c3f7b503170fb1ae186f513f0166907749eb34e0277dee747edcb78c886fb471aac01be1e864c languageName: node linkType: hard @@ -17299,22 +17315,22 @@ __metadata: linkType: hard "typescript@npm:5, typescript@npm:^5.0.4": - version: 5.5.2 - resolution: "typescript@npm:5.5.2" + version: 5.5.3 + resolution: "typescript@npm:5.5.3" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10c0/8ca39b27b5f9bd7f32db795045933ab5247897660627251e8254180b792a395bf061ea7231947d5d7ffa5cb4cc771970fd4ef543275f9b559f08c9325cccfce3 + checksum: 10c0/f52c71ccbc7080b034b9d3b72051d563601a4815bf3e39ded188e6ce60813f75dbedf11ad15dd4d32a12996a9ed8c7155b46c93a9b9c9bad1049766fe614bbdd languageName: node linkType: hard "typescript@patch:typescript@npm%3A5#optional!builtin, typescript@patch:typescript@npm%3A^5.0.4#optional!builtin": - version: 5.5.2 - resolution: "typescript@patch:typescript@npm%3A5.5.2#optional!builtin::version=5.5.2&hash=379a07" + version: 5.5.3 + resolution: "typescript@patch:typescript@npm%3A5.5.3#optional!builtin::version=5.5.3&hash=379a07" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10c0/a7b7ede75dc7fc32a76d0d0af6b91f5fbd8620890d84c906f663d8783bf3de6d7bd50f0430b8bb55eac88a38934af847ff709e7156e5138b95ae94cbd5f73e5b + checksum: 10c0/911c7811d61f57f07df79c4a35f56a0f426a65426a020e5fcd792f66559f399017205f5f10255329ab5a3d8c2d1f1d19530aeceffda70758a521fae1d469432e languageName: node linkType: hard @@ -17552,6 +17568,15 @@ __metadata: languageName: node linkType: hard +"use-debounce@npm:^10.0.0": + version: 10.0.1 + resolution: "use-debounce@npm:10.0.1" + peerDependencies: + react: ">=16.8.0" + checksum: 10c0/377a11814a708f5c392f465cbbe2d119a8a2635c8226cc5e30eba397c4436f8e8234385d069467b369d105ed0d3be733c6a08d8ae1004017c6d6f58f4d4c24d8 + languageName: node + linkType: hard + "use-isomorphic-layout-effect@npm:^1.1.1, use-isomorphic-layout-effect@npm:^1.1.2": version: 1.1.2 resolution: "use-isomorphic-layout-effect@npm:1.1.2"