about summary refs log tree commit diff
diff options
context:
space:
mode:
authorClaire <claire.github-309c@sitedethib.com>2023-04-09 11:40:14 +0200
committerClaire <claire.github-309c@sitedethib.com>2023-04-09 11:45:08 +0200
commitce12934f5b1804cc144014d9d0a93fdd16d13bf1 (patch)
treee6cb0c166392c28b38d86abe8f27344ce1d7752f
parentff168ef2024626f37fa776fde5739dcd58ecb9f2 (diff)
parent99e3e152cd2180cfa9a5bcafae208d44f31078f8 (diff)
Merge branch 'main' into glitch-soc/merge-upstream
Conflicts:
- `package.json`:
  Upstream removed a dependency that was textually close to a glitch-soc-only
  dependency.
  Removed the dependency as upstream did, while keeping the glitch-soc-only
  dependency.
-rwxr-xr-x.devcontainer/post-create.sh10
-rw-r--r--.github/workflows/check-i18n.yml17
-rw-r--r--.github/workflows/lint-js.yml9
-rw-r--r--.nvmrc2
-rw-r--r--.prettierignore2
-rw-r--r--CHANGELOG.md14
-rw-r--r--Dockerfile3
-rw-r--r--Gemfile6
-rw-r--r--Gemfile.lock26
-rw-r--r--app/controllers/backups_controller.rb2
-rw-r--r--app/controllers/settings/two_factor_authentication/otp_authentication_controller.rb9
-rw-r--r--app/javascript/mastodon/actions/markers.js2
-rw-r--r--app/javascript/mastodon/base_polyfills.js5
-rw-r--r--app/javascript/mastodon/components/admin/ReportReasonSelector.jsx4
-rw-r--r--app/javascript/mastodon/components/autosuggest_input.jsx2
-rw-r--r--app/javascript/mastodon/components/autosuggest_textarea.jsx2
-rw-r--r--app/javascript/mastodon/components/column_back_button_slim.jsx2
-rw-r--r--app/javascript/mastodon/components/dropdown_menu.jsx2
-rw-r--r--app/javascript/mastodon/components/gifv.jsx4
-rw-r--r--app/javascript/mastodon/components/icon_button.jsx4
-rw-r--r--app/javascript/mastodon/components/intersection_observer_article.jsx4
-rw-r--r--app/javascript/mastodon/components/picture_in_picture_placeholder.jsx2
-rw-r--r--app/javascript/mastodon/components/poll.jsx2
-rw-r--r--app/javascript/mastodon/components/status.jsx4
-rw-r--r--app/javascript/mastodon/components/status_content.jsx6
-rw-r--r--app/javascript/mastodon/containers/media_container.jsx2
-rw-r--r--app/javascript/mastodon/features/about/index.jsx2
-rw-r--r--app/javascript/mastodon/features/audio/index.jsx8
-rw-r--r--app/javascript/mastodon/features/compose/components/language_dropdown.jsx2
-rw-r--r--app/javascript/mastodon/features/compose/components/poll_form.jsx2
-rw-r--r--app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx2
-rw-r--r--app/javascript/mastodon/features/compose/components/search.jsx2
-rw-r--r--app/javascript/mastodon/features/compose/components/upload.jsx2
-rw-r--r--app/javascript/mastodon/features/direct_timeline/components/conversation.jsx2
-rw-r--r--app/javascript/mastodon/features/direct_timeline/components/conversations_list.jsx4
-rw-r--r--app/javascript/mastodon/features/direct_timeline/index.jsx2
-rw-r--r--app/javascript/mastodon/features/emoji/emoji.js4
-rw-r--r--app/javascript/mastodon/features/filters/select_filter.jsx4
-rw-r--r--app/javascript/mastodon/features/getting_started/components/announcements.jsx2
-rw-r--r--app/javascript/mastodon/features/list_editor/components/search.jsx2
-rw-r--r--app/javascript/mastodon/features/list_editor/index.jsx2
-rw-r--r--app/javascript/mastodon/features/list_timeline/index.jsx4
-rw-r--r--app/javascript/mastodon/features/notifications/components/clear_column_button.jsx2
-rw-r--r--app/javascript/mastodon/features/notifications/components/grant_permission_button.jsx2
-rw-r--r--app/javascript/mastodon/features/notifications/components/notification.jsx18
-rw-r--r--app/javascript/mastodon/features/report/components/option.jsx2
-rw-r--r--app/javascript/mastodon/features/status/index.jsx2
-rw-r--r--app/javascript/mastodon/features/ui/components/actions_modal.jsx2
-rw-r--r--app/javascript/mastodon/features/ui/components/media_modal.jsx4
-rw-r--r--app/javascript/mastodon/features/ui/components/modal_root.jsx2
-rw-r--r--app/javascript/mastodon/features/video/index.jsx6
-rw-r--r--app/javascript/mastodon/initial_state.js2
-rw-r--r--app/javascript/mastodon/load_polyfills.js1
-rw-r--r--app/javascript/mastodon/locales/ast.json14
-rw-r--r--app/javascript/mastodon/locales/be.json18
-rw-r--r--app/javascript/mastodon/locales/ca.json16
-rw-r--r--app/javascript/mastodon/locales/ckb.json94
-rw-r--r--app/javascript/mastodon/locales/cs.json30
-rw-r--r--app/javascript/mastodon/locales/da.json16
-rw-r--r--app/javascript/mastodon/locales/de.json16
-rw-r--r--app/javascript/mastodon/locales/el.json16
-rw-r--r--app/javascript/mastodon/locales/eo.json18
-rw-r--r--app/javascript/mastodon/locales/es-AR.json16
-rw-r--r--app/javascript/mastodon/locales/es-MX.json16
-rw-r--r--app/javascript/mastodon/locales/es.json28
-rw-r--r--app/javascript/mastodon/locales/et.json18
-rw-r--r--app/javascript/mastodon/locales/eu.json16
-rw-r--r--app/javascript/mastodon/locales/fa.json38
-rw-r--r--app/javascript/mastodon/locales/fi.json24
-rw-r--r--app/javascript/mastodon/locales/fo.json16
-rw-r--r--app/javascript/mastodon/locales/fy.json16
-rw-r--r--app/javascript/mastodon/locales/gl.json16
-rw-r--r--app/javascript/mastodon/locales/he.json16
-rw-r--r--app/javascript/mastodon/locales/hi.json16
-rw-r--r--app/javascript/mastodon/locales/hu.json16
-rw-r--r--app/javascript/mastodon/locales/is.json16
-rw-r--r--app/javascript/mastodon/locales/it.json16
-rw-r--r--app/javascript/mastodon/locales/ja.json16
-rw-r--r--app/javascript/mastodon/locales/ko.json16
-rw-r--r--app/javascript/mastodon/locales/lv.json16
-rw-r--r--app/javascript/mastodon/locales/my.json34
-rw-r--r--app/javascript/mastodon/locales/nl.json22
-rw-r--r--app/javascript/mastodon/locales/pl.json16
-rw-r--r--app/javascript/mastodon/locales/pt-BR.json16
-rw-r--r--app/javascript/mastodon/locales/pt-PT.json16
-rw-r--r--app/javascript/mastodon/locales/sq.json16
-rw-r--r--app/javascript/mastodon/locales/th.json18
-rw-r--r--app/javascript/mastodon/locales/tr.json20
-rw-r--r--app/javascript/mastodon/locales/uk.json16
-rw-r--r--app/javascript/mastodon/locales/vi.json16
-rw-r--r--app/javascript/mastodon/locales/zh-CN.json42
-rw-r--r--app/javascript/mastodon/locales/zh-TW.json16
-rw-r--r--app/javascript/packs/public.jsx9
-rw-r--r--app/javascript/styles/mastodon/accounts.scss8
-rw-r--r--app/javascript/styles/mastodon/admin.scss6
-rw-r--r--app/javascript/styles/mastodon/components.scss26
-rw-r--r--app/javascript/styles/mastodon/rich_text.scss2
-rw-r--r--app/javascript/styles/mastodon/rtl.scss12
-rw-r--r--app/javascript/styles/mastodon/tables.scss4
-rw-r--r--app/services/notify_service.rb1
-rw-r--r--config/locales/cs.yml3
-rw-r--r--config/locales/devise.my.yml2
-rw-r--r--config/locales/devise.zh-CN.yml4
-rw-r--r--config/locales/doorkeeper.my.yml2
-rw-r--r--config/locales/en-GB.yml84
-rw-r--r--config/locales/eo.yml1
-rw-r--r--config/locales/my.yml35
-rw-r--r--config/locales/simple_form.el.yml64
-rw-r--r--config/locales/simple_form.my.yml2
-rw-r--r--config/locales/simple_form.zh-CN.yml4
-rw-r--r--config/locales/zh-CN.yml8
-rw-r--r--config/locales/zh-TW.yml2
-rw-r--r--db/migrate/20230215074423_move_user_settings.rb2
-rw-r--r--lib/mastodon/version.rb2
-rw-r--r--package.json3
-rw-r--r--spec/lib/admin/system_check/base_check_spec.rb27
-rw-r--r--spec/lib/admin/system_check/database_schema_check_spec.rb45
-rw-r--r--spec/lib/admin/system_check/elasticsearch_check_spec.rb100
-rw-r--r--spec/lib/admin/system_check/media_privacy_check_spec.rb33
-rw-r--r--spec/lib/admin/system_check/message_spec.rb14
-rw-r--r--spec/lib/admin/system_check/rules_check_spec.rb53
-rw-r--r--spec/lib/admin/system_check/sidekiq_process_check_spec.rb45
-rw-r--r--spec/lib/admin/system_check_spec.rb15
-rw-r--r--spec/support/examples/lib/admin/checks.rb21
-rw-r--r--stylelint.config.js15
-rw-r--r--yarn.lock8
126 files changed, 1155 insertions, 561 deletions
diff --git a/.devcontainer/post-create.sh b/.devcontainer/post-create.sh
index 7c3852e7e..a075cc7b3 100755
--- a/.devcontainer/post-create.sh
+++ b/.devcontainer/post-create.sh
@@ -3,14 +3,16 @@
 set -e # Fail the whole script on first error
 
 # Fetch Ruby gem dependencies
-bundle install --path vendor/bundle --with='development test'
-
-# Fetch Javascript dependencies
-yarn install
+bundle config path 'vendor/bundle'
+bundle config with 'development test'
+bundle install
 
 # Make Gemfile.lock pristine again
 git checkout -- Gemfile.lock
 
+# Fetch Javascript dependencies
+yarn --frozen-lockfile
+
 # [re]create, migrate, and seed the test database
 RAILS_ENV=test ./bin/rails db:setup
 
diff --git a/.github/workflows/check-i18n.yml b/.github/workflows/check-i18n.yml
index aa8f1f584..df0d75c9f 100644
--- a/.github/workflows/check-i18n.yml
+++ b/.github/workflows/check-i18n.yml
@@ -30,13 +30,28 @@ jobs:
           ruby-version: .ruby-version
           bundler-cache: true
 
+      - name: Set up Node.js
+        uses: actions/setup-node@v3
+        with:
+          cache: yarn
+          node-version-file: '.nvmrc'
+
+      - name: Install all yarn packages
+        run: yarn --frozen-lockfile
+
+      - name: Check for missing strings in English JSON
+        run: |
+          yarn build:development
+          yarn manage:translations
+          git diff --exit-code
+
       - name: Check locale file normalization
         run: bundle exec i18n-tasks check-normalized
 
       - name: Check for unused strings
         run: bundle exec i18n-tasks unused
 
-      - name: Check for missing strings in English
+      - name: Check for missing strings in English YML
         run: |
           bundle exec i18n-tasks add-missing -l en
           git diff --exit-code
diff --git a/.github/workflows/lint-js.yml b/.github/workflows/lint-js.yml
index 44929f63d..e0c309c73 100644
--- a/.github/workflows/lint-js.yml
+++ b/.github/workflows/lint-js.yml
@@ -6,22 +6,28 @@ on:
     paths:
       - 'package.json'
       - 'yarn.lock'
+      - 'tsconfig.json'
       - '.nvmrc'
       - '.prettier*'
       - '.eslint*'
       - '**/*.js'
       - '**/*.jsx'
+      - '**/*.ts'
+      - '**/*.tsx'
       - '.github/workflows/lint-js.yml'
 
   pull_request:
     paths:
       - 'package.json'
       - 'yarn.lock'
+      - 'tsconfig.json'
       - '.nvmrc'
       - '.prettier*'
       - '.eslint*'
       - '**/*.js'
       - '**/*.jsx'
+      - '**/*.ts'
+      - '**/*.tsx'
       - '.github/workflows/lint-js.yml'
 
 jobs:
@@ -43,3 +49,6 @@ jobs:
 
       - name: ESLint
         run: yarn test:lint:js
+
+      - name: Typecheck
+        run: yarn test:typecheck
diff --git a/.nvmrc b/.nvmrc
index 030fcd56b..59ea99ee6 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-16.19
+16.20
diff --git a/.prettierignore b/.prettierignore
index af0411e9c..36ba57bfb 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -70,6 +70,8 @@ app/javascript/styles/mastodon/reset.scss
 # Ignore Javascript pending https://github.com/mastodon/mastodon/pull/23631
 *.js
 *.jsx
+*.ts
+*.tsx
 
 # Ignore HTML till cleaned and included in CI
 *.html
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4527c50d9..91a2c48a1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,20 @@
 
 All notable changes to this project will be documented in this file.
 
+## [4.1.2] - 2023-04-04
+
+### Fixed
+
+- Fix crash in `tootctl` commands making use of parallelization when Elasticsearch is enabled ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/24182), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/24377))
+- Fix crash in `db:setup` when Elasticsearch is enabled ([rrgeorge](https://github.com/mastodon/mastodon/pull/24302))
+- Fix user archive takeout when using OpenStack Swift or S3 providers with no ACL support ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/24200))
+- Fix invalid/expired invites being processed on sign-up ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/24337))
+
+### Security
+
+- Update Ruby to 3.0.6 due to ReDoS vulnerabilities ([saizai](https://github.com/mastodon/mastodon/pull/24334))
+- Fix unescaped user input in LDAP query ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/24379))
+
 ## [4.1.1] - 2023-03-16
 
 ### Added
diff --git a/Dockerfile b/Dockerfile
index dca547c6d..978933421 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,6 +1,6 @@
 # syntax=docker/dockerfile:1.4
 # This needs to be bullseye-slim because the Ruby image is built on bullseye-slim
-ARG NODE_VERSION="16.19-bullseye-slim"
+ARG NODE_VERSION="16.20-bullseye-slim"
 
 FROM ghcr.io/moritzheiber/ruby-jemalloc:3.2.2-slim as ruby
 FROM node:${NODE_VERSION} as build
@@ -18,7 +18,6 @@ COPY Gemfile* package.json yarn.lock /opt/mastodon/
 # hadolint ignore=DL3008
 RUN apt-get update && \
     apt-get install -y --no-install-recommends build-essential \
-        ca-certificates \
         git \
         libicu-dev \
         libidn11-dev \
diff --git a/Gemfile b/Gemfile
index 46f3e0106..d175d7412 100644
--- a/Gemfile
+++ b/Gemfile
@@ -5,7 +5,7 @@ ruby '>= 2.7.0', '< 3.3.0'
 
 gem 'pkg-config', '~> 1.5'
 
-gem 'puma', '~> 6.1'
+gem 'puma', '~> 6.2'
 gem 'rails', '~> 6.1.7'
 gem 'sprockets', '~> 3.7.2'
 gem 'thor', '~> 1.2'
@@ -17,7 +17,7 @@ gem 'makara', '~> 0.5'
 gem 'pghero'
 gem 'dotenv-rails', '~> 2.8'
 
-gem 'aws-sdk-s3', '~> 1.119', require: false
+gem 'aws-sdk-s3', '~> 1.120', require: false
 gem 'fog-core', '<= 2.4.0'
 gem 'fog-openstack', '~> 0.3', require: false
 gem 'kt-paperclip', '~> 7.1', github: 'kreeti/kt-paperclip', ref: '11abf222dc31bff71160a1d138b445214f434b2b'
@@ -118,7 +118,7 @@ group :production, :test do
 end
 
 group :test do
-  gem 'capybara', '~> 3.38'
+  gem 'capybara', '~> 3.39'
   gem 'climate_control'
   gem 'faker', '~> 3.1'
   gem 'json-schema', '~> 3.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index 683539844..5b05b79d6 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -94,7 +94,7 @@ GEM
       minitest (>= 5.1)
       tzinfo (~> 2.0)
       zeitwerk (~> 2.3)
-    addressable (2.8.1)
+    addressable (2.8.2)
       public_suffix (>= 2.0.2, < 6.0)
     aes_key_wrap (1.1.0)
     airbrussh (1.4.1)
@@ -109,7 +109,7 @@ GEM
     attr_required (1.0.1)
     awrence (1.2.1)
     aws-eventstream (1.2.0)
-    aws-partitions (1.735.0)
+    aws-partitions (1.739.0)
     aws-sdk-core (3.171.0)
       aws-eventstream (~> 1, >= 1.0.2)
       aws-partitions (~> 1, >= 1.651.0)
@@ -118,7 +118,7 @@ GEM
     aws-sdk-kms (1.63.0)
       aws-sdk-core (~> 3, >= 3.165.0)
       aws-sigv4 (~> 1.1)
-    aws-sdk-s3 (1.119.2)
+    aws-sdk-s3 (1.120.0)
       aws-sdk-core (~> 3, >= 3.165.0)
       aws-sdk-kms (~> 1)
       aws-sigv4 (~> 1.4)
@@ -166,7 +166,7 @@ GEM
       sshkit (~> 1.3)
     capistrano-yarn (2.0.2)
       capistrano (~> 3.0)
-    capybara (3.38.0)
+    capybara (3.39.0)
       addressable
       matrix
       mini_mime (>= 0.1.3)
@@ -438,7 +438,7 @@ GEM
     net-smtp (0.3.3)
       net-protocol
     net-ssh (7.0.1)
-    nio4r (2.5.8)
+    nio4r (2.5.9)
     nokogiri (1.14.2)
       mini_portile2 (~> 2.8.0)
       racc (~> 1.4)
@@ -481,7 +481,7 @@ GEM
     orm_adapter (0.5.0)
     ox (2.14.14)
     parallel (1.22.1)
-    parser (3.2.1.1)
+    parser (3.2.2.0)
       ast (~> 2.4.1)
     parslet (2.0.0)
     pastel (0.8.0)
@@ -501,7 +501,7 @@ GEM
       premailer (~> 1.7, >= 1.7.9)
     private_address_check (0.5.0)
     public_suffix (5.0.1)
-    puma (6.1.1)
+    puma (6.2.1)
       nio4r (~> 2.0)
     pundit (2.3.0)
       activesupport (>= 3.0.0)
@@ -603,17 +603,17 @@ GEM
     rspec_chunked (0.6)
     rspec_junit_formatter (0.6.0)
       rspec-core (>= 2, < 4, != 2.12.0)
-    rubocop (1.48.1)
+    rubocop (1.49.0)
       json (~> 2.3)
       parallel (~> 1.10)
       parser (>= 3.2.0.0)
       rainbow (>= 2.2.2, < 4.0)
       regexp_parser (>= 1.8, < 3.0)
       rexml (>= 3.2.5, < 4.0)
-      rubocop-ast (>= 1.26.0, < 2.0)
+      rubocop-ast (>= 1.28.0, < 2.0)
       ruby-progressbar (~> 1.7)
       unicode-display_width (>= 2.4.0, < 3.0)
-    rubocop-ast (1.27.0)
+    rubocop-ast (1.28.0)
       parser (>= 3.2.1.0)
     rubocop-capybara (2.17.1)
       rubocop (~> 1.41)
@@ -771,7 +771,7 @@ DEPENDENCIES
   active_model_serializers (~> 0.10)
   addressable (~> 2.8)
   annotate (~> 3.2)
-  aws-sdk-s3 (~> 1.119)
+  aws-sdk-s3 (~> 1.120)
   better_errors (~> 2.9)
   binding_of_caller (~> 1.0)
   blurhash (~> 0.1)
@@ -783,7 +783,7 @@ DEPENDENCIES
   capistrano-rails (~> 1.6)
   capistrano-rbenv (~> 2.2)
   capistrano-yarn (~> 2.0)
-  capybara (~> 3.38)
+  capybara (~> 3.39)
   charlock_holmes (~> 0.7.7)
   chewy (~> 7.2)
   climate_control
@@ -847,7 +847,7 @@ DEPENDENCIES
   premailer-rails
   private_address_check (~> 0.5)
   public_suffix (~> 5.0)
-  puma (~> 6.1)
+  puma (~> 6.2)
   pundit (~> 2.3)
   rack (~> 2.2.6)
   rack-attack (~> 6.6)
diff --git a/app/controllers/backups_controller.rb b/app/controllers/backups_controller.rb
index 0687b62c5..5891da6f6 100644
--- a/app/controllers/backups_controller.rb
+++ b/app/controllers/backups_controller.rb
@@ -13,7 +13,7 @@ class BackupsController < ApplicationController
     when :s3
       redirect_to @backup.dump.expiring_url(10)
     when :fog
-      if Paperclip::Attachment.default_options.dig(:storage, :fog_credentials, :openstack_temp_url_key).present?
+      if Paperclip::Attachment.default_options.dig(:fog_credentials, :openstack_temp_url_key).present?
         redirect_to @backup.dump.expiring_url(Time.now.utc + 10)
       else
         redirect_to full_asset_url(@backup.dump.url)
diff --git a/app/controllers/settings/two_factor_authentication/otp_authentication_controller.rb b/app/controllers/settings/two_factor_authentication/otp_authentication_controller.rb
index cbba842a9..0bff01ec2 100644
--- a/app/controllers/settings/two_factor_authentication/otp_authentication_controller.rb
+++ b/app/controllers/settings/two_factor_authentication/otp_authentication_controller.rb
@@ -22,18 +22,9 @@ module Settings
 
       private
 
-      def confirmation_params
-        params.require(:form_two_factor_confirmation).permit(:otp_attempt)
-      end
-
       def verify_otp_not_enabled
         redirect_to settings_two_factor_authentication_methods_path if current_user.otp_enabled?
       end
-
-      def acceptable_code?
-        current_user.validate_and_consume_otp!(confirmation_params[:otp_attempt]) ||
-          current_user.invalidate_otp_backup_code!(confirmation_params[:otp_attempt])
-      end
     end
   end
 end
diff --git a/app/javascript/mastodon/actions/markers.js b/app/javascript/mastodon/actions/markers.js
index 16ec7fe77..ca246dce7 100644
--- a/app/javascript/mastodon/actions/markers.js
+++ b/app/javascript/mastodon/actions/markers.js
@@ -55,7 +55,7 @@ export const synchronouslySubmitMarkers = () => (dispatch, getState) => {
     client.open('POST', '/api/v1/markers', false);
     client.setRequestHeader('Content-Type', 'application/json');
     client.setRequestHeader('Authorization', `Bearer ${accessToken}`);
-    client.SUBMIT(JSON.stringify(params));
+    client.send(JSON.stringify(params));
   } catch (e) {
     // Do not make the BeforeUnload handler error out
   }
diff --git a/app/javascript/mastodon/base_polyfills.js b/app/javascript/mastodon/base_polyfills.js
index d3ac0d510..91bc5d6dc 100644
--- a/app/javascript/mastodon/base_polyfills.js
+++ b/app/javascript/mastodon/base_polyfills.js
@@ -1,16 +1,11 @@
 import 'intl';
 import 'intl/locale-data/jsonp/en';
 import 'es6-symbol/implement';
-import includes from 'array-includes';
 import assign from 'object-assign';
 import values from 'object.values';
 import { decode as decodeBase64 } from './utils/base64';
 import promiseFinally from 'promise.prototype.finally';
 
-if (!Array.prototype.includes) {
-  includes.shim();
-}
-
 if (!Object.assign) {
   Object.assign = assign;
 }
diff --git a/app/javascript/mastodon/components/admin/ReportReasonSelector.jsx b/app/javascript/mastodon/components/admin/ReportReasonSelector.jsx
index 58a861fde..cd14dac4e 100644
--- a/app/javascript/mastodon/components/admin/ReportReasonSelector.jsx
+++ b/app/javascript/mastodon/components/admin/ReportReasonSelector.jsx
@@ -33,7 +33,7 @@ class Category extends React.PureComponent {
     const { id, text, disabled, selected, children } = this.props;
 
     return (
-      <div tabIndex='0' role='button' className={classNames('report-reason-selector__category', { selected, disabled })} onClick={this.handleClick}>
+      <div tabIndex={0} role='button' className={classNames('report-reason-selector__category', { selected, disabled })} onClick={this.handleClick}>
         {selected && <input type='hidden' name='report[category]' value={id} />}
 
         <div className='report-reason-selector__category__label'>
@@ -74,7 +74,7 @@ class Rule extends React.PureComponent {
     const { id, text, disabled, selected } = this.props;
 
     return (
-      <div tabIndex='0' role='button' className={classNames('report-reason-selector__rule', { selected, disabled })} onClick={this.handleClick}>
+      <div tabIndex={0} role='button' className={classNames('report-reason-selector__rule', { selected, disabled })} onClick={this.handleClick}>
         <span className={classNames('poll__input', { checkbox: true, active: selected, disabled })} />
         {selected && <input type='hidden' name='report[rule_ids][]' value={id} />}
         {text}
diff --git a/app/javascript/mastodon/components/autosuggest_input.jsx b/app/javascript/mastodon/components/autosuggest_input.jsx
index f9616c581..a68e2a01b 100644
--- a/app/javascript/mastodon/components/autosuggest_input.jsx
+++ b/app/javascript/mastodon/components/autosuggest_input.jsx
@@ -180,7 +180,7 @@ export default class AutosuggestInput extends ImmutablePureComponent {
     }
 
     return (
-      <div role='button' tabIndex='0' key={key} data-index={i} className={classNames('autosuggest-textarea__suggestions__item', { selected: i === selectedSuggestion })} onMouseDown={this.onSuggestionClick}>
+      <div role='button' tabIndex={0} key={key} data-index={i} className={classNames('autosuggest-textarea__suggestions__item', { selected: i === selectedSuggestion })} onMouseDown={this.onSuggestionClick}>
         {inner}
       </div>
     );
diff --git a/app/javascript/mastodon/components/autosuggest_textarea.jsx b/app/javascript/mastodon/components/autosuggest_textarea.jsx
index c04491298..a627bc1ec 100644
--- a/app/javascript/mastodon/components/autosuggest_textarea.jsx
+++ b/app/javascript/mastodon/components/autosuggest_textarea.jsx
@@ -186,7 +186,7 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
     }
 
     return (
-      <div role='button' tabIndex='0' key={key} data-index={i} className={classNames('autosuggest-textarea__suggestions__item', { selected: i === selectedSuggestion })} onMouseDown={this.onSuggestionClick}>
+      <div role='button' tabIndex={0} key={key} data-index={i} className={classNames('autosuggest-textarea__suggestions__item', { selected: i === selectedSuggestion })} onMouseDown={this.onSuggestionClick}>
         {inner}
       </div>
     );
diff --git a/app/javascript/mastodon/components/column_back_button_slim.jsx b/app/javascript/mastodon/components/column_back_button_slim.jsx
index cc8bfb151..46ac23736 100644
--- a/app/javascript/mastodon/components/column_back_button_slim.jsx
+++ b/app/javascript/mastodon/components/column_back_button_slim.jsx
@@ -8,7 +8,7 @@ export default class ColumnBackButtonSlim extends ColumnBackButton {
   render () {
     return (
       <div className='column-back-button--slim'>
-        <div role='button' tabIndex='0' onClick={this.handleClick} className='column-back-button column-back-button--slim-button'>
+        <div role='button' tabIndex={0} onClick={this.handleClick} className='column-back-button column-back-button--slim-button'>
           <Icon id='chevron-left' className='column-back-button__icon' fixedWidth />
           <FormattedMessage id='column_back_button.label' defaultMessage='Back' />
         </div>
diff --git a/app/javascript/mastodon/components/dropdown_menu.jsx b/app/javascript/mastodon/components/dropdown_menu.jsx
index c04c513fb..eaaa72fd8 100644
--- a/app/javascript/mastodon/components/dropdown_menu.jsx
+++ b/app/javascript/mastodon/components/dropdown_menu.jsx
@@ -119,7 +119,7 @@ class DropdownMenu extends React.PureComponent {
 
     return (
       <li className='dropdown-menu__item' key={`${text}-${i}`}>
-        <a href={href} target={target} data-method={method} rel='noopener noreferrer' role='button' tabIndex='0' ref={i === 0 ? this.setFocusRef : null} onClick={this.handleClick} onKeyPress={this.handleItemKeyPress} data-index={i}>
+        <a href={href} target={target} data-method={method} rel='noopener noreferrer' role='button' tabIndex={0} ref={i === 0 ? this.setFocusRef : null} onClick={this.handleClick} onKeyPress={this.handleItemKeyPress} data-index={i}>
           {text}
         </a>
       </li>
diff --git a/app/javascript/mastodon/components/gifv.jsx b/app/javascript/mastodon/components/gifv.jsx
index 9ec201c6c..1ce7e7c29 100644
--- a/app/javascript/mastodon/components/gifv.jsx
+++ b/app/javascript/mastodon/components/gifv.jsx
@@ -46,7 +46,7 @@ export default class GIFV extends React.PureComponent {
             width={width}
             height={height}
             role='button'
-            tabIndex='0'
+            tabIndex={0}
             aria-label={alt}
             title={alt}
             lang={lang}
@@ -57,7 +57,7 @@ export default class GIFV extends React.PureComponent {
         <video
           src={src}
           role='button'
-          tabIndex='0'
+          tabIndex={0}
           aria-label={alt}
           title={alt}
           lang={lang}
diff --git a/app/javascript/mastodon/components/icon_button.jsx b/app/javascript/mastodon/components/icon_button.jsx
index 003692373..989cae440 100644
--- a/app/javascript/mastodon/components/icon_button.jsx
+++ b/app/javascript/mastodon/components/icon_button.jsx
@@ -23,7 +23,7 @@ export default class IconButton extends React.PureComponent {
     inverted: PropTypes.bool,
     animate: PropTypes.bool,
     overlay: PropTypes.bool,
-    tabIndex: PropTypes.string,
+    tabIndex: PropTypes.number,
     counter: PropTypes.number,
     obfuscateCount: PropTypes.bool,
     href: PropTypes.string,
@@ -36,7 +36,7 @@ export default class IconButton extends React.PureComponent {
     disabled: false,
     animate: false,
     overlay: false,
-    tabIndex: '0',
+    tabIndex: 0,
     ariaHidden: false,
   };
 
diff --git a/app/javascript/mastodon/components/intersection_observer_article.jsx b/app/javascript/mastodon/components/intersection_observer_article.jsx
index c2feb003a..77957a21d 100644
--- a/app/javascript/mastodon/components/intersection_observer_article.jsx
+++ b/app/javascript/mastodon/components/intersection_observer_article.jsx
@@ -113,7 +113,7 @@ export default class IntersectionObserverArticle extends React.Component {
           aria-setsize={listLength}
           style={{ height: `${this.height || cachedHeight}px`, opacity: 0, overflow: 'hidden' }}
           data-id={id}
-          tabIndex='0'
+          tabIndex={0}
         >
           {children && React.cloneElement(children, { hidden: true })}
         </article>
@@ -121,7 +121,7 @@ export default class IntersectionObserverArticle extends React.Component {
     }
 
     return (
-      <article ref={this.handleRef} aria-posinset={index + 1} aria-setsize={listLength} data-id={id} tabIndex='0'>
+      <article ref={this.handleRef} aria-posinset={index + 1} aria-setsize={listLength} data-id={id} tabIndex={0}>
         {children && React.cloneElement(children, { hidden: false })}
       </article>
     );
diff --git a/app/javascript/mastodon/components/picture_in_picture_placeholder.jsx b/app/javascript/mastodon/components/picture_in_picture_placeholder.jsx
index c8aa8f757..6322b1c66 100644
--- a/app/javascript/mastodon/components/picture_in_picture_placeholder.jsx
+++ b/app/javascript/mastodon/components/picture_in_picture_placeholder.jsx
@@ -58,7 +58,7 @@ class PictureInPicturePlaceholder extends React.PureComponent {
     const { height } = this.state;
 
     return (
-      <div ref={this.setRef} className='picture-in-picture-placeholder' style={{ height }} role='button' tabIndex='0' onClick={this.handleClick}>
+      <div ref={this.setRef} className='picture-in-picture-placeholder' style={{ height }} role='button' tabIndex={0} onClick={this.handleClick}>
         <Icon id='window-restore' />
         <FormattedMessage id='picture_in_picture.restore' defaultMessage='Put it back' />
       </div>
diff --git a/app/javascript/mastodon/components/poll.jsx b/app/javascript/mastodon/components/poll.jsx
index 360557d00..b9b96a700 100644
--- a/app/javascript/mastodon/components/poll.jsx
+++ b/app/javascript/mastodon/components/poll.jsx
@@ -154,7 +154,7 @@ class Poll extends ImmutablePureComponent {
           {!showResults && (
             <span
               className={classNames('poll__input', { checkbox: poll.get('multiple'), active })}
-              tabIndex='0'
+              tabIndex={0}
               role={poll.get('multiple') ? 'checkbox' : 'radio'}
               onKeyPress={this.handleOptionKeyPress}
               aria-checked={active}
diff --git a/app/javascript/mastodon/components/status.jsx b/app/javascript/mastodon/components/status.jsx
index 281e69874..923dc892d 100644
--- a/app/javascript/mastodon/components/status.jsx
+++ b/app/javascript/mastodon/components/status.jsx
@@ -337,7 +337,7 @@ class Status extends ImmutablePureComponent {
     if (hidden) {
       return (
         <HotKeys handlers={handlers}>
-          <div ref={this.handleRef} className={classNames('status__wrapper', { focusable: !this.props.muted })} tabIndex='0'>
+          <div ref={this.handleRef} className={classNames('status__wrapper', { focusable: !this.props.muted })} tabIndex={0}>
             <span>{status.getIn(['account', 'display_name']) || status.getIn(['account', 'username'])}</span>
             <span>{status.get('content')}</span>
           </div>
@@ -354,7 +354,7 @@ class Status extends ImmutablePureComponent {
 
       return (
         <HotKeys handlers={minHandlers}>
-          <div className='status__wrapper status__wrapper--filtered focusable' tabIndex='0' ref={this.handleRef}>
+          <div className='status__wrapper status__wrapper--filtered focusable' tabIndex={0} ref={this.handleRef}>
             <FormattedMessage id='status.filtered' defaultMessage='Filtered' />: {matchedFilters.join(', ')}.
             {' '}
             <button className='status__wrapper--filtered__button' onClick={this.handleUnfilterClick}>
diff --git a/app/javascript/mastodon/components/status_content.jsx b/app/javascript/mastodon/components/status_content.jsx
index 8d3a80248..fb953b9dd 100644
--- a/app/javascript/mastodon/components/status_content.jsx
+++ b/app/javascript/mastodon/components/status_content.jsx
@@ -268,7 +268,7 @@ class StatusContent extends React.PureComponent {
       }
 
       return (
-        <div className={classNames} ref={this.setRef} tabIndex='0' onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
+        <div className={classNames} ref={this.setRef} tabIndex={0} onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
           <p style={{ marginBottom: hidden && status.get('mentions').isEmpty() ? '0px' : null }}>
             <span dangerouslySetInnerHTML={spoilerContent} className='translate' lang={lang} />
             {' '}
@@ -286,7 +286,7 @@ class StatusContent extends React.PureComponent {
     } else if (this.props.onClick) {
       return (
         <>
-          <div className={classNames} ref={this.setRef} tabIndex='0' onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp} key='status-content' onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
+          <div className={classNames} ref={this.setRef} tabIndex={0} onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp} key='status-content' onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
             <div className='status__content__text status__content__text--visible translate' lang={lang} dangerouslySetInnerHTML={content} />
 
             {poll}
@@ -298,7 +298,7 @@ class StatusContent extends React.PureComponent {
       );
     } else {
       return (
-        <div className={classNames} ref={this.setRef} tabIndex='0' onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
+        <div className={classNames} ref={this.setRef} tabIndex={0} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
           <div className='status__content__text status__content__text--visible translate' lang={lang} dangerouslySetInnerHTML={content} />
 
           {poll}
diff --git a/app/javascript/mastodon/containers/media_container.jsx b/app/javascript/mastodon/containers/media_container.jsx
index 25dc17444..f9244f8dd 100644
--- a/app/javascript/mastodon/containers/media_container.jsx
+++ b/app/javascript/mastodon/containers/media_container.jsx
@@ -54,7 +54,7 @@ export default class MediaContainer extends PureComponent {
 
   handleCloseMedia = () => {
     document.body.classList.remove('with-modals--active');
-    document.documentElement.style.marginRight = 0;
+    document.documentElement.style.marginRight = '0';
 
     this.setState({
       media: null,
diff --git a/app/javascript/mastodon/features/about/index.jsx b/app/javascript/mastodon/features/about/index.jsx
index 2804c4a21..bb35f3203 100644
--- a/app/javascript/mastodon/features/about/index.jsx
+++ b/app/javascript/mastodon/features/about/index.jsx
@@ -67,7 +67,7 @@ class Section extends React.PureComponent {
 
     return (
       <div className={classNames('about__section', { active: !collapsed })}>
-        <div className='about__section__title' role='button' tabIndex='0' onClick={this.handleClick}>
+        <div className='about__section__title' role='button' tabIndex={0} onClick={this.handleClick}>
           <Icon id={collapsed ? 'chevron-right' : 'chevron-down'} fixedWidth /> {title}
         </div>
 
diff --git a/app/javascript/mastodon/features/audio/index.jsx b/app/javascript/mastodon/features/audio/index.jsx
index b0c6eeee6..df40b48f0 100644
--- a/app/javascript/mastodon/features/audio/index.jsx
+++ b/app/javascript/mastodon/features/audio/index.jsx
@@ -470,7 +470,7 @@ class Audio extends React.PureComponent {
     }
 
     return (
-      <div className={classNames('audio-player', { editable, inactive: !revealed })} ref={this.setPlayerRef} style={{ backgroundColor: this._getBackgroundColor(), color: this._getForegroundColor(), width: '100%', height: this.props.fullscreen ? '100%' : (this.state.height || this.props.height) }} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} tabIndex='0' onKeyDown={this.handleKeyDown}>
+      <div className={classNames('audio-player', { editable, inactive: !revealed })} ref={this.setPlayerRef} style={{ backgroundColor: this._getBackgroundColor(), color: this._getForegroundColor(), width: '100%', height: this.props.fullscreen ? '100%' : (this.state.height || this.props.height) }} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} tabIndex={0} onKeyDown={this.handleKeyDown}>
 
         <Blurhash
           hash={blurhash}
@@ -493,7 +493,7 @@ class Audio extends React.PureComponent {
 
         <canvas
           role='button'
-          tabIndex='0'
+          tabIndex={0}
           className='audio-player__canvas'
           width={this.state.width}
           height={this.state.height}
@@ -526,7 +526,7 @@ class Audio extends React.PureComponent {
 
           <span
             className={classNames('video-player__seek__handle', { active: dragging })}
-            tabIndex='0'
+            tabIndex={0}
             style={{ left: `${progress}%`, backgroundColor: this._getAccentColor() }}
             onKeyDown={this.handleAudioKeyDown}
           />
@@ -543,7 +543,7 @@ class Audio extends React.PureComponent {
 
                 <span
                   className='video-player__volume__handle'
-                  tabIndex='0'
+                  tabIndex={0}
                   style={{ left: `${volume * 100}%`, backgroundColor: this._getAccentColor() }}
                 />
               </div>
diff --git a/app/javascript/mastodon/features/compose/components/language_dropdown.jsx b/app/javascript/mastodon/features/compose/components/language_dropdown.jsx
index 908cb61a7..08542e3a9 100644
--- a/app/javascript/mastodon/features/compose/components/language_dropdown.jsx
+++ b/app/javascript/mastodon/features/compose/components/language_dropdown.jsx
@@ -209,7 +209,7 @@ class LanguageDropdownMenu extends React.PureComponent {
     const { value } = this.props;
 
     return (
-      <div key={lang[0]} role='option' tabIndex='0' data-index={lang[0]} className={classNames('language-dropdown__dropdown__results__item', { active: lang[0] === value })} aria-selected={lang[0] === value} onClick={this.handleClick} onKeyDown={this.handleKeyDown}>
+      <div key={lang[0]} role='option' tabIndex={0} data-index={lang[0]} className={classNames('language-dropdown__dropdown__results__item', { active: lang[0] === value })} aria-selected={lang[0] === value} onClick={this.handleClick} onKeyDown={this.handleKeyDown}>
         <span className='language-dropdown__dropdown__results__item__native-name' lang={lang[0]}>{lang[2]}</span> <span className='language-dropdown__dropdown__results__item__common-name'>({lang[1]})</span>
       </div>
     );
diff --git a/app/javascript/mastodon/features/compose/components/poll_form.jsx b/app/javascript/mastodon/features/compose/components/poll_form.jsx
index 967d9321b..f81d7355a 100644
--- a/app/javascript/mastodon/features/compose/components/poll_form.jsx
+++ b/app/javascript/mastodon/features/compose/components/poll_form.jsx
@@ -82,7 +82,7 @@ class OptionIntl extends React.PureComponent {
             onClick={this.handleToggleMultiple}
             onKeyPress={this.handleCheckboxKeypress}
             role='button'
-            tabIndex='0'
+            tabIndex={0}
             title={intl.formatMessage(isPollMultiple ? messages.switchToSingle : messages.switchToMultiple)}
             aria-label={intl.formatMessage(isPollMultiple ? messages.switchToSingle : messages.switchToMultiple)}
           />
diff --git a/app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx b/app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx
index 6c4b1064e..e65c9cb72 100644
--- a/app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx
+++ b/app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx
@@ -115,7 +115,7 @@ class PrivacyDropdownMenu extends React.PureComponent {
     return (
       <div style={{ ...style }} role='listbox' ref={this.setRef}>
         {items.map(item => (
-          <div role='option' tabIndex='0' key={item.value} data-index={item.value} onKeyDown={this.handleKeyDown} onClick={this.handleClick} className={classNames('privacy-dropdown__option', { active: item.value === value })} aria-selected={item.value === value} ref={item.value === value ? this.setFocusRef : null}>
+          <div role='option' tabIndex={0} key={item.value} data-index={item.value} onKeyDown={this.handleKeyDown} onClick={this.handleClick} className={classNames('privacy-dropdown__option', { active: item.value === value })} aria-selected={item.value === value} ref={item.value === value ? this.setFocusRef : null}>
             <div className='privacy-dropdown__option__icon'>
               <Icon id={item.icon} fixedWidth />
             </div>
diff --git a/app/javascript/mastodon/features/compose/components/search.jsx b/app/javascript/mastodon/features/compose/components/search.jsx
index 717ecea37..46723f5cc 100644
--- a/app/javascript/mastodon/features/compose/components/search.jsx
+++ b/app/javascript/mastodon/features/compose/components/search.jsx
@@ -287,7 +287,7 @@ class Search extends React.PureComponent {
           onBlur={this.handleBlur}
         />
 
-        <div role='button' tabIndex='0' className='search__icon' onClick={this.handleClear}>
+        <div role='button' tabIndex={0} className='search__icon' onClick={this.handleClear}>
           <Icon id='search' className={hasValue ? '' : 'active'} />
           <Icon id='times-circle' className={hasValue ? 'active' : ''} aria-label={intl.formatMessage(messages.placeholder)} />
         </div>
diff --git a/app/javascript/mastodon/features/compose/components/upload.jsx b/app/javascript/mastodon/features/compose/components/upload.jsx
index f114680b9..e3651c229 100644
--- a/app/javascript/mastodon/features/compose/components/upload.jsx
+++ b/app/javascript/mastodon/features/compose/components/upload.jsx
@@ -42,7 +42,7 @@ export default class Upload extends ImmutablePureComponent {
     const y = ((focusY / -2) + .5) * 100;
 
     return (
-      <div className='compose-form__upload' tabIndex='0' role='button'>
+      <div className='compose-form__upload' tabIndex={0} role='button'>
         <Motion defaultStyle={{ scale: 0.8 }} style={{ scale: spring(1, { stiffness: 180, damping: 12 }) }}>
           {({ scale }) => (
             <div className='compose-form__upload-thumbnail' style={{ transform: `scale(${scale})`, backgroundImage: `url(${media.get('preview_url')})`, backgroundPosition: `${x}% ${y}%` }}>
diff --git a/app/javascript/mastodon/features/direct_timeline/components/conversation.jsx b/app/javascript/mastodon/features/direct_timeline/components/conversation.jsx
index 5996dd666..d0dbffe65 100644
--- a/app/javascript/mastodon/features/direct_timeline/components/conversation.jsx
+++ b/app/javascript/mastodon/features/direct_timeline/components/conversation.jsx
@@ -144,7 +144,7 @@ class Conversation extends ImmutablePureComponent {
 
     return (
       <HotKeys handlers={handlers}>
-        <div className={classNames('conversation focusable muted', { 'conversation--unread': unread })} tabIndex='0'>
+        <div className={classNames('conversation focusable muted', { 'conversation--unread': unread })} tabIndex={0}>
           <div className='conversation__avatar' onClick={this.handleClick} role='presentation'>
             <AvatarComposite accounts={accounts} size={48} />
           </div>
diff --git a/app/javascript/mastodon/features/direct_timeline/components/conversations_list.jsx b/app/javascript/mastodon/features/direct_timeline/components/conversations_list.jsx
index 27e9a593f..04c404e1d 100644
--- a/app/javascript/mastodon/features/direct_timeline/components/conversations_list.jsx
+++ b/app/javascript/mastodon/features/direct_timeline/components/conversations_list.jsx
@@ -55,10 +55,10 @@ export default class ConversationsList extends ImmutablePureComponent {
   }, 300, { leading: true });
 
   render () {
-    const { conversations, onLoadMore, ...other } = this.props;
+    const { conversations, isLoading, onLoadMore, ...other } = this.props;
 
     return (
-      <ScrollableList {...other} onLoadMore={onLoadMore && this.handleLoadOlder} ref={this.setRef}>
+      <ScrollableList {...other} isLoading={isLoading} showLoading={isLoading && conversations.isEmpty()} onLoadMore={onLoadMore && this.handleLoadOlder} ref={this.setRef}>
         {conversations.map(item => (
           <ConversationContainer
             key={item.get('id')}
diff --git a/app/javascript/mastodon/features/direct_timeline/index.jsx b/app/javascript/mastodon/features/direct_timeline/index.jsx
index 5d4a7c49a..fc45ea69a 100644
--- a/app/javascript/mastodon/features/direct_timeline/index.jsx
+++ b/app/javascript/mastodon/features/direct_timeline/index.jsx
@@ -89,8 +89,10 @@ class DirectTimeline extends React.PureComponent {
           trackScroll={!pinned}
           scrollKey={`direct_timeline-${columnId}`}
           timelineId='direct'
+          bindToDocument={!multiColumn}
           onLoadMore={this.handleLoadMore}
           prepend={<div className='follow_requests-unlocked_explanation'><span><FormattedMessage id='compose_form.encryption_warning' defaultMessage='Posts on Mastodon are not end-to-end encrypted. Do not share any dangerous information over Mastodon.' /> <a href='/terms' target='_blank'><FormattedMessage id='compose_form.direct_message_warning_learn_more' defaultMessage='Learn more' /></a></span></div>}
+          alwaysPrepend
           emptyMessage={<FormattedMessage id='empty_column.direct' defaultMessage="You don't have any private mentions yet. When you send or receive one, it will show up here." />}
         />
 
diff --git a/app/javascript/mastodon/features/emoji/emoji.js b/app/javascript/mastodon/features/emoji/emoji.js
index bc3dd8c60..6ae406624 100644
--- a/app/javascript/mastodon/features/emoji/emoji.js
+++ b/app/javascript/mastodon/features/emoji/emoji.js
@@ -50,7 +50,7 @@ const emojifyTextNode = (node, customEmojis) => {
         if (shortname in customEmojis) {
           const filename = autoPlayGif ? customEmojis[shortname].url : customEmojis[shortname].static_url;
           replacement = document.createElement('img');
-          replacement.setAttribute('draggable', false);
+          replacement.setAttribute('draggable', 'false');
           replacement.setAttribute('class', 'emojione custom-emoji');
           replacement.setAttribute('alt', shortname);
           replacement.setAttribute('title', shortname);
@@ -65,7 +65,7 @@ const emojifyTextNode = (node, customEmojis) => {
       const { filename, shortCode } = unicodeMapping[match];
       const title = shortCode ? `:${shortCode}:` : '';
       replacement = document.createElement('img');
-      replacement.setAttribute('draggable', false);
+      replacement.setAttribute('draggable', 'false');
       replacement.setAttribute('class', 'emojione');
       replacement.setAttribute('alt', match);
       replacement.setAttribute('title', title);
diff --git a/app/javascript/mastodon/features/filters/select_filter.jsx b/app/javascript/mastodon/features/filters/select_filter.jsx
index b0aede187..5778eec8e 100644
--- a/app/javascript/mastodon/features/filters/select_filter.jsx
+++ b/app/javascript/mastodon/features/filters/select_filter.jsx
@@ -65,7 +65,7 @@ class SelectFilter extends React.PureComponent {
     }
 
     return (
-      <div key={filter[0]} role='button' tabIndex='0' data-index={filter[0]} className='language-dropdown__dropdown__results__item' onClick={this.handleItemClick} onKeyDown={this.handleKeyDown}>
+      <div key={filter[0]} role='button' tabIndex={0} data-index={filter[0]} className='language-dropdown__dropdown__results__item' onClick={this.handleItemClick} onKeyDown={this.handleKeyDown}>
         <span className='language-dropdown__dropdown__results__item__native-name'>{filter[1]}</span> {warning}
       </div>
     );
@@ -73,7 +73,7 @@ class SelectFilter extends React.PureComponent {
 
   renderCreateNew (name) {
     return (
-      <div key='add-new-filter' role='button' tabIndex='0' className='language-dropdown__dropdown__results__item' onClick={this.handleNewFilterClick} onKeyDown={this.handleKeyDown}>
+      <div key='add-new-filter' role='button' tabIndex={0} className='language-dropdown__dropdown__results__item' onClick={this.handleNewFilterClick} onKeyDown={this.handleKeyDown}>
         <Icon id='plus' fixedWidth /> <FormattedMessage id='filter_modal.select_filter.prompt_new' defaultMessage='New category: {name}' values={{ name }} />
       </div>
     );
diff --git a/app/javascript/mastodon/features/getting_started/components/announcements.jsx b/app/javascript/mastodon/features/getting_started/components/announcements.jsx
index 954f407f5..5f993d2c5 100644
--- a/app/javascript/mastodon/features/getting_started/components/announcements.jsx
+++ b/app/javascript/mastodon/features/getting_started/components/announcements.jsx
@@ -418,7 +418,7 @@ class Announcements extends ImmutablePureComponent {
         <img className='announcements__mastodon' alt='' draggable='false' src={mascot || elephantUIPlane} />
 
         <div className='announcements__container'>
-          <ReactSwipeableViews animateHeight={!reduceMotion} adjustHeight={reduceMotion} index={index} onChangeIndex={this.handleChangeIndex}>
+          <ReactSwipeableViews animateHeight animateTransitions={!reduceMotion} index={index} onChangeIndex={this.handleChangeIndex}>
             {announcements.map((announcement, idx) => (
               <Announcement
                 key={announcement.get('id')}
diff --git a/app/javascript/mastodon/features/list_editor/components/search.jsx b/app/javascript/mastodon/features/list_editor/components/search.jsx
index b9745e0a8..f70e272f7 100644
--- a/app/javascript/mastodon/features/list_editor/components/search.jsx
+++ b/app/javascript/mastodon/features/list_editor/components/search.jsx
@@ -63,7 +63,7 @@ class Search extends React.PureComponent {
           />
         </label>
 
-        <div role='button' tabIndex='0' className='search__icon' onClick={this.handleClear}>
+        <div role='button' tabIndex={0} className='search__icon' onClick={this.handleClear}>
           <Icon id='search' className={classNames({ active: !hasValue })} />
           <Icon id='times-circle' aria-label={intl.formatMessage(messages.search)} className={classNames({ active: hasValue })} />
         </div>
diff --git a/app/javascript/mastodon/features/list_editor/index.jsx b/app/javascript/mastodon/features/list_editor/index.jsx
index 65cebbdc8..ed9d09132 100644
--- a/app/javascript/mastodon/features/list_editor/index.jsx
+++ b/app/javascript/mastodon/features/list_editor/index.jsx
@@ -60,7 +60,7 @@ class ListEditor extends ImmutablePureComponent {
             {accountIds.map(accountId => <Account key={accountId} accountId={accountId} added />)}
           </div>
 
-          {showSearch && <div role='button' tabIndex='-1' className='drawer__backdrop' onClick={onClear} />}
+          {showSearch && <div role='button' tabIndex={-1} className='drawer__backdrop' onClick={onClear} />}
 
           <Motion defaultStyle={{ x: -100 }} style={{ x: spring(showSearch ? 0 : -100, { stiffness: 210, damping: 20 }) }}>
             {({ x }) => (
diff --git a/app/javascript/mastodon/features/list_timeline/index.jsx b/app/javascript/mastodon/features/list_timeline/index.jsx
index d0ba2a186..c0b9a62ff 100644
--- a/app/javascript/mastodon/features/list_timeline/index.jsx
+++ b/app/javascript/mastodon/features/list_timeline/index.jsx
@@ -176,11 +176,11 @@ class ListTimeline extends React.PureComponent {
           multiColumn={multiColumn}
         >
           <div className='column-settings__row column-header__links'>
-            <button type='button' className='text-btn column-header__setting-btn' tabIndex='0' onClick={this.handleEditClick}>
+            <button type='button' className='text-btn column-header__setting-btn' tabIndex={0} onClick={this.handleEditClick}>
               <Icon id='pencil' /> <FormattedMessage id='lists.edit' defaultMessage='Edit list' />
             </button>
 
-            <button type='button' className='text-btn column-header__setting-btn' tabIndex='0' onClick={this.handleDeleteClick}>
+            <button type='button' className='text-btn column-header__setting-btn' tabIndex={0} onClick={this.handleDeleteClick}>
               <Icon id='trash' /> <FormattedMessage id='lists.delete' defaultMessage='Delete list' />
             </button>
           </div>
diff --git a/app/javascript/mastodon/features/notifications/components/clear_column_button.jsx b/app/javascript/mastodon/features/notifications/components/clear_column_button.jsx
index b82fd092f..9a076ce5e 100644
--- a/app/javascript/mastodon/features/notifications/components/clear_column_button.jsx
+++ b/app/javascript/mastodon/features/notifications/components/clear_column_button.jsx
@@ -11,7 +11,7 @@ export default class ClearColumnButton extends React.PureComponent {
 
   render () {
     return (
-      <button className='text-btn column-header__setting-btn' tabIndex='0' onClick={this.props.onClick}><Icon id='eraser' /> <FormattedMessage id='notifications.clear' defaultMessage='Clear notifications' /></button>
+      <button className='text-btn column-header__setting-btn' tabIndex={0} onClick={this.props.onClick}><Icon id='eraser' /> <FormattedMessage id='notifications.clear' defaultMessage='Clear notifications' /></button>
     );
   }
 
diff --git a/app/javascript/mastodon/features/notifications/components/grant_permission_button.jsx b/app/javascript/mastodon/features/notifications/components/grant_permission_button.jsx
index 798e4c787..5b2db48fd 100644
--- a/app/javascript/mastodon/features/notifications/components/grant_permission_button.jsx
+++ b/app/javascript/mastodon/features/notifications/components/grant_permission_button.jsx
@@ -10,7 +10,7 @@ export default class GrantPermissionButton extends React.PureComponent {
 
   render () {
     return (
-      <button className='text-btn column-header__permission-btn' tabIndex='0' onClick={this.props.onClick}>
+      <button className='text-btn column-header__permission-btn' tabIndex={0} onClick={this.props.onClick}>
         <FormattedMessage id='notifications.grant_permission' defaultMessage='Grant permission.' />
       </button>
     );
diff --git a/app/javascript/mastodon/features/notifications/components/notification.jsx b/app/javascript/mastodon/features/notifications/components/notification.jsx
index cf9d9f72c..f3104cee0 100644
--- a/app/javascript/mastodon/features/notifications/components/notification.jsx
+++ b/app/javascript/mastodon/features/notifications/components/notification.jsx
@@ -123,7 +123,7 @@ class Notification extends ImmutablePureComponent {
 
     return (
       <HotKeys handlers={this.getHandlers()}>
-        <div className={classNames('notification notification-follow focusable', { unread })} tabIndex='0' aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.follow, { name: account.get('acct') }), notification.get('created_at'))}>
+        <div className={classNames('notification notification-follow focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.follow, { name: account.get('acct') }), notification.get('created_at'))}>
           <div className='notification__message'>
             <div className='notification__favourite-icon-wrapper'>
               <Icon id='user-plus' fixedWidth />
@@ -145,7 +145,7 @@ class Notification extends ImmutablePureComponent {
 
     return (
       <HotKeys handlers={this.getHandlers()}>
-        <div className={classNames('notification notification-follow-request focusable', { unread })} tabIndex='0' aria-label={notificationForScreenReader(intl, intl.formatMessage({ id: 'notification.follow_request', defaultMessage: '{name} has requested to follow you' }, { name: account.get('acct') }), notification.get('created_at'))}>
+        <div className={classNames('notification notification-follow-request focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage({ id: 'notification.follow_request', defaultMessage: '{name} has requested to follow you' }, { name: account.get('acct') }), notification.get('created_at'))}>
           <div className='notification__message'>
             <div className='notification__favourite-icon-wrapper'>
               <Icon id='user' fixedWidth />
@@ -185,7 +185,7 @@ class Notification extends ImmutablePureComponent {
 
     return (
       <HotKeys handlers={this.getHandlers()}>
-        <div className={classNames('notification notification-favourite focusable', { unread })} tabIndex='0' aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.favourite, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
+        <div className={classNames('notification notification-favourite focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.favourite, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
           <div className='notification__message'>
             <div className='notification__favourite-icon-wrapper'>
               <Icon id='star' className='star-icon' fixedWidth />
@@ -217,7 +217,7 @@ class Notification extends ImmutablePureComponent {
 
     return (
       <HotKeys handlers={this.getHandlers()}>
-        <div className={classNames('notification notification-reblog focusable', { unread })} tabIndex='0' aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.reblog, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
+        <div className={classNames('notification notification-reblog focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.reblog, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
           <div className='notification__message'>
             <div className='notification__favourite-icon-wrapper'>
               <Icon id='retweet' fixedWidth />
@@ -253,7 +253,7 @@ class Notification extends ImmutablePureComponent {
 
     return (
       <HotKeys handlers={this.getHandlers()}>
-        <div className={classNames('notification notification-status focusable', { unread })} tabIndex='0' aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.status, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
+        <div className={classNames('notification notification-status focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.status, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
           <div className='notification__message'>
             <div className='notification__favourite-icon-wrapper'>
               <Icon id='home' fixedWidth />
@@ -290,7 +290,7 @@ class Notification extends ImmutablePureComponent {
 
     return (
       <HotKeys handlers={this.getHandlers()}>
-        <div className={classNames('notification notification-update focusable', { unread })} tabIndex='0' aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.update, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
+        <div className={classNames('notification notification-update focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.update, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
           <div className='notification__message'>
             <div className='notification__favourite-icon-wrapper'>
               <Icon id='pencil' fixedWidth />
@@ -329,7 +329,7 @@ class Notification extends ImmutablePureComponent {
 
     return (
       <HotKeys handlers={this.getHandlers()}>
-        <div className={classNames('notification notification-poll focusable', { unread })} tabIndex='0' aria-label={notificationForScreenReader(intl, message, notification.get('created_at'))}>
+        <div className={classNames('notification notification-poll focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, message, notification.get('created_at'))}>
           <div className='notification__message'>
             <div className='notification__favourite-icon-wrapper'>
               <Icon id='tasks' fixedWidth />
@@ -366,7 +366,7 @@ class Notification extends ImmutablePureComponent {
 
     return (
       <HotKeys handlers={this.getHandlers()}>
-        <div className={classNames('notification notification-admin-sign-up focusable', { unread })} tabIndex='0' aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.adminSignUp, { name: account.get('acct') }), notification.get('created_at'))}>
+        <div className={classNames('notification notification-admin-sign-up focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.adminSignUp, { name: account.get('acct') }), notification.get('created_at'))}>
           <div className='notification__message'>
             <div className='notification__favourite-icon-wrapper'>
               <Icon id='user-plus' fixedWidth />
@@ -396,7 +396,7 @@ class Notification extends ImmutablePureComponent {
 
     return (
       <HotKeys handlers={this.getHandlers()}>
-        <div className={classNames('notification notification-admin-report focusable', { unread })} tabIndex='0' aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.adminReport, { name: account.get('acct'), target: notification.getIn(['report', 'target_account', 'acct']) }), notification.get('created_at'))}>
+        <div className={classNames('notification notification-admin-report focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.adminReport, { name: account.get('acct'), target: notification.getIn(['report', 'target_account', 'acct']) }), notification.get('created_at'))}>
           <div className='notification__message'>
             <div className='notification__favourite-icon-wrapper'>
               <Icon id='flag' fixedWidth />
diff --git a/app/javascript/mastodon/features/report/components/option.jsx b/app/javascript/mastodon/features/report/components/option.jsx
index 42c04b018..342204e22 100644
--- a/app/javascript/mastodon/features/report/components/option.jsx
+++ b/app/javascript/mastodon/features/report/components/option.jsx
@@ -40,7 +40,7 @@ export default class Option extends React.PureComponent {
 
         <span
           className={classNames('poll__input', { active: checked, checkbox: multiple })}
-          tabIndex='0'
+          tabIndex={0}
           role='radio'
           onKeyPress={this.handleKeyPress}
           aria-checked={checked}
diff --git a/app/javascript/mastodon/features/status/index.jsx b/app/javascript/mastodon/features/status/index.jsx
index 1d7cb685f..2d18c6e9d 100644
--- a/app/javascript/mastodon/features/status/index.jsx
+++ b/app/javascript/mastodon/features/status/index.jsx
@@ -630,7 +630,7 @@ class Status extends ImmutablePureComponent {
             {ancestors}
 
             <HotKeys handlers={handlers}>
-              <div className={classNames('focusable', 'detailed-status__wrapper', `detailed-status__wrapper-${status.get('visibility')}`)} tabIndex='0' aria-label={textForScreenReader(intl, status, false)}>
+              <div className={classNames('focusable', 'detailed-status__wrapper', `detailed-status__wrapper-${status.get('visibility')}`)} tabIndex={0} aria-label={textForScreenReader(intl, status, false)}>
                 <DetailedStatus
                   key={`details-${status.get('id')}`}
                   status={status}
diff --git a/app/javascript/mastodon/features/ui/components/actions_modal.jsx b/app/javascript/mastodon/features/ui/components/actions_modal.jsx
index fd59c1e20..35090e242 100644
--- a/app/javascript/mastodon/features/ui/components/actions_modal.jsx
+++ b/app/javascript/mastodon/features/ui/components/actions_modal.jsx
@@ -23,7 +23,7 @@ export default class ActionsModal extends ImmutablePureComponent {
     return (
       <li key={`${text}-${i}`}>
         <a href={href} target='_blank' rel='noopener noreferrer' onClick={this.props.onClick} data-index={i} className={classNames({ active })}>
-          {icon && <IconButton title={text} icon={icon} role='presentation' tabIndex='-1' inverted />}
+          {icon && <IconButton title={text} icon={icon} role='presentation' tabIndex={-1} inverted />}
           <div>
             <div className={classNames({ 'actions-modal__item-label': !!meta })}>{text}</div>
             <div>{meta}</div>
diff --git a/app/javascript/mastodon/features/ui/components/media_modal.jsx b/app/javascript/mastodon/features/ui/components/media_modal.jsx
index aa179a965..52bd75453 100644
--- a/app/javascript/mastodon/features/ui/components/media_modal.jsx
+++ b/app/javascript/mastodon/features/ui/components/media_modal.jsx
@@ -138,8 +138,8 @@ class MediaModal extends ImmutablePureComponent {
 
     const index = this.getIndex();
 
-    const leftNav  = media.size > 1 && <button tabIndex='0' className='media-modal__nav media-modal__nav--left' onClick={this.handlePrevClick} aria-label={intl.formatMessage(messages.previous)}><Icon id='chevron-left' fixedWidth /></button>;
-    const rightNav = media.size > 1 && <button tabIndex='0' className='media-modal__nav  media-modal__nav--right' onClick={this.handleNextClick} aria-label={intl.formatMessage(messages.next)}><Icon id='chevron-right' fixedWidth /></button>;
+    const leftNav  = media.size > 1 && <button tabIndex={0} className='media-modal__nav media-modal__nav--left' onClick={this.handlePrevClick} aria-label={intl.formatMessage(messages.previous)}><Icon id='chevron-left' fixedWidth /></button>;
+    const rightNav = media.size > 1 && <button tabIndex={0} className='media-modal__nav  media-modal__nav--right' onClick={this.handleNextClick} aria-label={intl.formatMessage(messages.next)}><Icon id='chevron-right' fixedWidth /></button>;
 
     const content = media.map((image) => {
       const width  = image.getIn(['meta', 'original', 'width']) || null;
diff --git a/app/javascript/mastodon/features/ui/components/modal_root.jsx b/app/javascript/mastodon/features/ui/components/modal_root.jsx
index 5a1734977..c252e6caa 100644
--- a/app/javascript/mastodon/features/ui/components/modal_root.jsx
+++ b/app/javascript/mastodon/features/ui/components/modal_root.jsx
@@ -73,7 +73,7 @@ export default class ModalRoot extends React.PureComponent {
       document.documentElement.style.marginRight = `${getScrollbarWidth()}px`;
     } else {
       document.body.classList.remove('with-modals--active');
-      document.documentElement.style.marginRight = 0;
+      document.documentElement.style.marginRight = '0';
     }
   }
 
diff --git a/app/javascript/mastodon/features/video/index.jsx b/app/javascript/mastodon/features/video/index.jsx
index 58bb45908..e2637e0be 100644
--- a/app/javascript/mastodon/features/video/index.jsx
+++ b/app/javascript/mastodon/features/video/index.jsx
@@ -582,7 +582,7 @@ class Video extends React.PureComponent {
           poster={preview}
           preload={preload}
           role='button'
-          tabIndex='0'
+          tabIndex={0}
           aria-label={alt}
           title={alt}
           lang={lang}
@@ -611,7 +611,7 @@ class Video extends React.PureComponent {
 
             <span
               className={classNames('video-player__seek__handle', { active: dragging })}
-              tabIndex='0'
+              tabIndex={0}
               style={{ left: `${progress}%` }}
               onKeyDown={this.handleVideoKeyDown}
             />
@@ -627,7 +627,7 @@ class Video extends React.PureComponent {
 
                 <span
                   className={classNames('video-player__volume__handle')}
-                  tabIndex='0'
+                  tabIndex={0}
                   style={{ left: `${volume * 100}%` }}
                 />
               </div>
diff --git a/app/javascript/mastodon/initial_state.js b/app/javascript/mastodon/initial_state.js
index af022e16b..56b2f4eb2 100644
--- a/app/javascript/mastodon/initial_state.js
+++ b/app/javascript/mastodon/initial_state.js
@@ -55,7 +55,7 @@
  * @property {boolean=} delete_modal
  * @property {boolean=} disable_swiping
  * @property {string=} disabled_account_id
- * @property {boolean} display_media
+ * @property {string} display_media
  * @property {string} domain
  * @property {boolean=} expand_spoilers
  * @property {boolean} limited_federation_mode
diff --git a/app/javascript/mastodon/load_polyfills.js b/app/javascript/mastodon/load_polyfills.js
index b2c41303a..7909dc4ea 100644
--- a/app/javascript/mastodon/load_polyfills.js
+++ b/app/javascript/mastodon/load_polyfills.js
@@ -12,7 +12,6 @@ function importExtraPolyfills() {
 
 function loadPolyfills() {
   const needsBasePolyfills = !(
-    Array.prototype.includes &&
     HTMLCanvasElement.prototype.toBlob &&
     window.Intl &&
     Object.assign &&
diff --git a/app/javascript/mastodon/locales/ast.json b/app/javascript/mastodon/locales/ast.json
index fd4959185..c0920bbec 100644
--- a/app/javascript/mastodon/locales/ast.json
+++ b/app/javascript/mastodon/locales/ast.json
@@ -20,7 +20,7 @@
   "account.blocked": "Blocked",
   "account.browse_more_on_origin_server": "Restolar más nel perfil orixinal",
   "account.cancel_follow_request": "Withdraw follow request",
-  "account.direct": "Privately mention @{name}",
+  "account.direct": "Mentar a @{name} per privao",
   "account.disable_notifications": "Dexar d'avisame cuando @{name} espublice artículos",
   "account.domain_blocked": "Domain blocked",
   "account.edit_profile": "Editar el perfil",
@@ -102,7 +102,7 @@
   "column.blocks": "Perfiles bloquiaos",
   "column.bookmarks": "Marcadores",
   "column.community": "Llinia de tiempu llocal",
-  "column.direct": "Private mentions",
+  "column.direct": "Menciones privaes",
   "column.directory": "Browse profiles",
   "column.domain_blocks": "Dominios bloquiaos",
   "column.favourites": "Favoritos",
@@ -216,7 +216,7 @@
   "empty_column.blocks": "Entá nun bloquiesti a nengún perfil.",
   "empty_column.bookmarked_statuses": "Entá nun tienes nengún artículu en Marcadores. Cuando amiestes dalgún, apaez equí.",
   "empty_column.community": "La llinia de tiempu llocal ta balera. ¡Espubliza daqué públicamente pa comenzar l'alderique!",
-  "empty_column.direct": "You don't have any private mentions yet. When you send or receive one, it will show up here.",
+  "empty_column.direct": "Entá nun tienes nenguna mención privada. Cuando unvies o recibas dalguna, apaez equí.",
   "empty_column.domain_blocks": "Entá nun hai nengún dominiu bloquiáu.",
   "empty_column.explore_statuses": "Agora nun hai nada en tendencia. ¡Volvi equí dempués!",
   "empty_column.favourited_statuses": "Entá nun marquesti nengún artículu como favoritu. Cuando marques dalgún, apaez equí.",
@@ -314,7 +314,7 @@
   "keyboard_shortcuts.column": "Enfocar una columna",
   "keyboard_shortcuts.compose": "Enfocar l'área de composición",
   "keyboard_shortcuts.description": "Descripción",
-  "keyboard_shortcuts.direct": "to open direct messages column",
+  "keyboard_shortcuts.direct": "p'abrir la columna de les menciones privaes",
   "keyboard_shortcuts.down": "Baxar na llista",
   "keyboard_shortcuts.enter": "Abrir un artículu",
   "keyboard_shortcuts.favourite": "Marcar un artículu como favoritu",
@@ -376,7 +376,7 @@
   "navigation_bar.bookmarks": "Marcadores",
   "navigation_bar.community_timeline": "Llinia de tiempu llocal",
   "navigation_bar.compose": "Compose new post",
-  "navigation_bar.direct": "Private mentions",
+  "navigation_bar.direct": "Menciones privaes",
   "navigation_bar.discover": "Discover",
   "navigation_bar.domain_blocks": "Dominios bloquiaos",
   "navigation_bar.edit_profile": "Editar el perfil",
@@ -559,8 +559,8 @@
   "status.copy": "Copiar l'enllaz al artículu",
   "status.delete": "Desaniciar",
   "status.detailed_status": "Detailed conversation view",
-  "status.direct": "Privately mention @{name}",
-  "status.direct_indicator": "Private mention",
+  "status.direct": "Mentar a @{name} per privao",
+  "status.direct_indicator": "Mención privada",
   "status.edit": "Edit",
   "status.edited": "Editóse'l {date}",
   "status.edited_x_times": "Editóse {count, plural, one {{count} vegada} other {{count} vegaes}}",
diff --git a/app/javascript/mastodon/locales/be.json b/app/javascript/mastodon/locales/be.json
index 6af78717a..72224a71c 100644
--- a/app/javascript/mastodon/locales/be.json
+++ b/app/javascript/mastodon/locales/be.json
@@ -522,17 +522,17 @@
   "report_notification.categories.spam": "Спам",
   "report_notification.categories.violation": "Парушэнне правілаў",
   "report_notification.open": "Адкрыць скаргу",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Гісторыя пошуку пустая",
   "search.placeholder": "Пошук",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Супадзенне профіляў {x}",
+  "search.quick_action.go_to_account": "Перайсці да профілю {x}",
+  "search.quick_action.go_to_hashtag": "Перайсці да хэштэгу {x}",
+  "search.quick_action.open_url": "Адкрыць спасылку ў Mastodon",
+  "search.quick_action.status_search": "Супадзенне паведамленняў {x}",
   "search.search_or_paste": "Увядзіце спасылку або пошукавы запыт",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
-  "search_results.accounts": "Profiles",
+  "search_popout.quick_actions": "Хуткія дзеянні",
+  "search_popout.recent": "Нядаўнія запыты",
+  "search_results.accounts": "Профілі",
   "search_results.all": "Усё",
   "search_results.hashtags": "Хэштэгі",
   "search_results.nothing_found": "Па дадзенаму запыту нічога не знойдзена",
diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json
index f8a7767d5..dd30da215 100644
--- a/app/javascript/mastodon/locales/ca.json
+++ b/app/javascript/mastodon/locales/ca.json
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "Brossa",
   "report_notification.categories.violation": "Violació de norma",
   "report_notification.open": "Obre un informe",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "No hi ha cerques recents",
   "search.placeholder": "Cerca",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Perfils coincidents {x}",
+  "search.quick_action.go_to_account": "Anar al perfil {x}",
+  "search.quick_action.go_to_hashtag": "Anar a la etiqueta {x}",
+  "search.quick_action.open_url": "Obrir URL a Mastodon",
+  "search.quick_action.status_search": "Tuts coincidents {x}",
   "search.search_or_paste": "Cerca o escriu l'URL",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "Accions ràpides",
+  "search_popout.recent": "Cerques recents",
   "search_results.accounts": "Perfils",
   "search_results.all": "Tots",
   "search_results.hashtags": "Etiquetes",
diff --git a/app/javascript/mastodon/locales/ckb.json b/app/javascript/mastodon/locales/ckb.json
index 45e8df0b0..ca0ca6f19 100644
--- a/app/javascript/mastodon/locales/ckb.json
+++ b/app/javascript/mastodon/locales/ckb.json
@@ -20,7 +20,7 @@
   "account.blocked": "بلۆککرا",
   "account.browse_more_on_origin_server": "گەڕانی فرەتر لە سەر پرۆفایلی سەرەکی",
   "account.cancel_follow_request": "داواکاری فۆڵۆو بکشێنەوە",
-  "account.direct": "Privately mention @{name}",
+  "account.direct": "بە شێوەیەکی تایبەت باسی @{name} بکە",
   "account.disable_notifications": "ئاگانامە مەنێرە بۆم کاتێک @{name} پۆست دەکرێت",
   "account.domain_blocked": "دۆمەین قەپاتکرا",
   "account.edit_profile": "دەستکاری پرۆفایل",
@@ -29,14 +29,14 @@
   "account.featured_tags.last_status_at": "دوایین پۆست لە {date}",
   "account.featured_tags.last_status_never": "هیچ پۆستێک نییە",
   "account.featured_tags.title": "هاشتاگە تایبەتەکانی {name}",
-  "account.follow": "شوێنکەوتن",
+  "account.follow": "بەدواداچوون",
   "account.followers": "شوێنکەوتووان",
   "account.followers.empty": "کەسێک شوێن ئەم بەکارهێنەرە نەکەوتووە",
   "account.followers_counter": "{count, plural, one {{counter} شوێنکەوتوو} other {{counter} شوێنکەوتوو}}",
-  "account.following": "دواکەوتن",
+  "account.following": "بەدوادا",
   "account.following_counter": "{count, plural, one {{counter} شوێنکەوتوو} other {{counter} شوێنکەوتوو}}",
   "account.follows.empty": "ئەم بەکارهێنەرە تا ئێستا شوێن کەس نەکەوتووە.",
-  "account.follows_you": "شوێنکەوتووەکانت",
+  "account.follows_you": "شوێنت دەکەوێت",
   "account.go_to_profile": "بڕۆ بۆ پڕۆفایلی",
   "account.hide_reblogs": "داشاردنی بووستەکان لە @{name}",
   "account.joined_short": "بەشداری کردووە",
@@ -50,7 +50,7 @@
   "account.mute_notifications": "هۆشیارکەرەوەکان لاببە لە @{name}",
   "account.muted": "بێ دەنگ",
   "account.open_original_page": "لاپەڕەی ئەسڵی بکەرەوە",
-  "account.posts": "توتس",
+  "account.posts": "نووسراوەکان",
   "account.posts_with_replies": "توتس و وەڵامەکان",
   "account.report": "گوزارشت @{name}",
   "account.requested": "چاوەڕێی ڕەزامەندین. کرتە بکە بۆ هەڵوەشاندنەوەی داواکاری شوێنکەوتن",
@@ -102,7 +102,7 @@
   "column.blocks": "بەکارهێنەرە بلۆککراوەکان",
   "column.bookmarks": "نیشانەکان",
   "column.community": "هێڵی کاتی ناوخۆیی",
-  "column.direct": "Private mentions",
+  "column.direct": "ئاماژەی تایبەت",
   "column.directory": "گەڕان لە پرۆفایلەکان",
   "column.domain_blocks": "دۆمەینە داخراوەکان",
   "column.favourites": "دڵخوازترینەکان",
@@ -216,7 +216,7 @@
   "empty_column.blocks": "تۆ هێشتا هیچ بەکارهێنەرێکت بلۆک نەکردووە.",
   "empty_column.bookmarked_statuses": "تۆ هێشتا هیچ توتێکی دیاریکراوت نیە کاتێک نیشانەیەک نیشان دەکەیت، لێرە دەرئەکەویت.",
   "empty_column.community": "هێڵی کاتی ناوخۆیی بەتاڵە. شتێک بە ئاشکرا بنووسە بۆ ئەوەی تۆپەکە بسووڕێت!",
-  "empty_column.direct": "You don't have any private mentions yet. When you send or receive one, it will show up here.",
+  "empty_column.direct": "تا ئێستا هیچ نامەیەکی ڕاستەوخۆت نییە. کاتێک یەکێکیان دەنێری یان وەریدەگریت، لێرە دەردەکەوێت.",
   "empty_column.domain_blocks": "هێشتا هیچ دۆمەینێکی بلۆک کراو نییە.",
   "empty_column.explore_statuses": "لە ئێستادا هیچ شتێک ترێند نییە. دواتر سەیری بکە!",
   "empty_column.favourited_statuses": "تۆ هێشتا هیچ توتێکی دڵخوازت نییە، کاتێک حەزت لە دانەیەکی باشە، لێرە دەرئەکەویت.",
@@ -299,12 +299,12 @@
   "interaction_modal.description.reply": "بە هەژمارێک لەسەر ماستدۆن، ئەتوانیت وەڵامی ئەم بڵاوکراوەیە بدەیتەوە.",
   "interaction_modal.on_another_server": "لەسەر ڕاژەیەکی جیا",
   "interaction_modal.on_this_server": "لەسەر ئەم ڕاژەیە",
-  "interaction_modal.other_server_instructions": "Copy and paste this URL into the search field of your favourite Mastodon app or the web interface of your Mastodon server.",
-  "interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.",
-  "interaction_modal.title.favourite": "Favourite {name}'s post",
-  "interaction_modal.title.follow": "Follow {name}",
-  "interaction_modal.title.reblog": "Boost {name}'s post",
-  "interaction_modal.title.reply": "Reply to {name}'s post",
+  "interaction_modal.other_server_instructions": "ئەم URLە کۆپی بکە و بیخە ناو بواری گەڕانی ئەپی دڵخوازت لە ماستۆدۆن یان ڕووکاری وێبی سێرڤەری ماستۆدۆنەکەت.",
+  "interaction_modal.preamble": "بەو پێیەی ماستۆدۆن لامەرکەزییە، دەتوانیت ئەکاونتی ئێستات بەکاربهێنیت کە لەلایەن سێرڤەرێکی تری ماستۆدۆن یان پلاتفۆرمی گونجاوەوە هۆست کراوە ئەگەر ئەکاونتێکت لەسەر ئەم ئەکاونتە نەبێت.",
+  "interaction_modal.title.favourite": "پۆستی {name}ی دڵخواز",
+  "interaction_modal.title.follow": "دوای {name} بکەوە",
+  "interaction_modal.title.reblog": "پۆستی {name} زیاد بکە",
+  "interaction_modal.title.reply": "وەڵامی پۆستەکەی {name} بدەرەوە",
   "intervals.full.days": "{number, plural, one {# ڕۆژ} other {# ڕۆژەک}}",
   "intervals.full.hours": "{number, plural, one {# کات} other {# کات}}",
   "intervals.full.minutes": "{number, plural, one {# خولەک} other {# خولەک}}",
@@ -314,7 +314,7 @@
   "keyboard_shortcuts.column": "بۆ ئەوەی تیشک بخاتە سەر توتێک لە یەکێک لە ستوونەکان",
   "keyboard_shortcuts.compose": "بۆ سەرنجدان بە نووسینی ناوچەی دەق",
   "keyboard_shortcuts.description": "وه‌سف",
-  "keyboard_shortcuts.direct": "to open direct messages column",
+  "keyboard_shortcuts.direct": "بۆ کردنەوەی ستوونی ئاماژەی تایبەت",
   "keyboard_shortcuts.down": "بۆ چوونە خوارەوە لە لیستەکەدا",
   "keyboard_shortcuts.enter": "بۆ کردنەوەی توت",
   "keyboard_shortcuts.favourite": "بۆ دڵخواز",
@@ -348,7 +348,7 @@
   "lightbox.next": "داهاتوو",
   "lightbox.previous": "پێشوو",
   "limited_account_hint.action": "بەهەر حاڵ پڕۆفایلی پیشان بدە",
-  "limited_account_hint.title": "This profile has been hidden by the moderators of {domain}.",
+  "limited_account_hint.title": "ئەم پرۆفایلە لەلایەن بەڕێوەبەرانی {domain} شاراوەتەوە.",
   "lists.account.add": "زیادکردن بۆ لیست",
   "lists.account.remove": "لابردن لە لیست",
   "lists.delete": "سڕینەوەی لیست",
@@ -367,16 +367,16 @@
   "media_gallery.toggle_visible": "شاردنەوەی {number, plural, one {image} other {images}}",
   "missing_indicator.label": "نەدۆزرایەوە",
   "missing_indicator.sublabel": "ئەو سەرچاوەیە نادۆزرێتەوە",
-  "moved_to_account_banner.text": "Your account {disabledAccount} is currently disabled because you moved to {movedToAccount}.",
+  "moved_to_account_banner.text": "ئەکاونتەکەت {disabledAccount} لە ئێستادا لەکارخراوە چونکە تۆ چوویتە {movedToAccount}.",
   "mute_modal.duration": "ماوە",
   "mute_modal.hide_notifications": "شاردنەوەی ئاگانامەکان لەم بەکارهێنەرە؟ ",
   "mute_modal.indefinite": "نادیار",
-  "navigation_bar.about": "About",
+  "navigation_bar.about": "دەربارە",
   "navigation_bar.blocks": "بەکارهێنەرە بلۆککراوەکان",
   "navigation_bar.bookmarks": "نیشانکراوەکان",
   "navigation_bar.community_timeline": "دەمنامەی ناوخۆیی",
   "navigation_bar.compose": "نووسینی توتی نوێ",
-  "navigation_bar.direct": "Private mentions",
+  "navigation_bar.direct": "ئاماژەی تایبەت",
   "navigation_bar.discover": "دۆزینەوە",
   "navigation_bar.domain_blocks": "دۆمەینە بلۆک کراوەکان",
   "navigation_bar.edit_profile": "دەستکاری پرۆفایل بکە",
@@ -384,7 +384,7 @@
   "navigation_bar.favourites": "دڵخوازەکان",
   "navigation_bar.filters": "وشە کپەکان",
   "navigation_bar.follow_requests": "بەدواداچوی داواکاریەکان بکە",
-  "navigation_bar.followed_tags": "Followed hashtags",
+  "navigation_bar.followed_tags": "هاشتاگی بەدوادا هات",
   "navigation_bar.follows_and_followers": "شوێنکەوتوو و شوێنکەوتوان",
   "navigation_bar.lists": "لیستەکان",
   "navigation_bar.logout": "دەرچوون",
@@ -393,10 +393,10 @@
   "navigation_bar.pins": "توتی چەسپاو",
   "navigation_bar.preferences": "پەسەندەکان",
   "navigation_bar.public_timeline": "نووسراوەکانی هەمووشوێنێک",
-  "navigation_bar.search": "Search",
+  "navigation_bar.search": "گەڕان",
   "navigation_bar.security": "ئاسایش",
-  "not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.",
-  "notification.admin.report": "{name} reported {target}",
+  "not_signed_in_indicator.not_signed_in": "پێویستە بچیتە ژوورەوە بۆ دەستگەیشتن بەم سەرچاوەیە.",
+  "notification.admin.report": "{name} ڕاپۆرت کراوە {target}",
   "notification.admin.sign_up": "{name} تۆمارکرا",
   "notification.favourite": "{name} نووسراوەکەتی پەسەند کرد",
   "notification.follow": "{name} دوای تۆ کەوت",
@@ -409,7 +409,7 @@
   "notification.update": "{name} پۆستێکی دەستکاریکرد",
   "notifications.clear": "ئاگانامەکان بسڕیەوە",
   "notifications.clear_confirmation": "ئایا دڵنیایت لەوەی دەتەوێت بە هەمیشەیی هەموو ئاگانامەکانت بسڕیتەوە?",
-  "notifications.column_settings.admin.report": "New reports:",
+  "notifications.column_settings.admin.report": "ڕاپۆرتە نوێیەکان:",
   "notifications.column_settings.admin.sign_up": "چوونەژوورەوەی نوێ:",
   "notifications.column_settings.alert": "ئاگانامەکانی پیشانگەرر ڕومێزی",
   "notifications.column_settings.favourite": "دڵخوازترین:",
@@ -463,8 +463,8 @@
   "privacy.public.short": "گشتی",
   "privacy.unlisted.long": "بۆ هەمووان دیارە، بەڵام لە تایبەتمەندییەکانی دۆزینەوە دەرچووە",
   "privacy.unlisted.short": "لە لیست نەکراو",
-  "privacy_policy.last_updated": "Last updated {date}",
-  "privacy_policy.title": "Privacy Policy",
+  "privacy_policy.last_updated": "دوایین نوێکردنەوە {date}",
+  "privacy_policy.title": "سیاسەتی تایبەتێتی",
   "refresh": "نوێکردنەوە",
   "regeneration_indicator.label": "بارکردن…",
   "regeneration_indicator.sublabel": "ڕاگەیەنەری ماڵەوەت ئامادە دەکرێت!",
@@ -518,29 +518,29 @@
   "report.unfollow": "بەدوادانەچوو@{name}",
   "report.unfollow_explanation": "تۆ شوێنکەوتووی ئەم هەژماررەی دەکەیت. بۆ ئەوەی چیتر نووسراوەکانیان لە هۆم فیدی خۆت نەبینی، بەدوایان مەچۆ.",
   "report_notification.attached_statuses": "{count, plural, one {{count} post} other {{count} posts}} attached",
-  "report_notification.categories.other": "Other",
-  "report_notification.categories.spam": "Spam",
-  "report_notification.categories.violation": "Rule violation",
-  "report_notification.open": "Open report",
-  "search.no_recent_searches": "No recent searches",
+  "report_notification.categories.other": "هی تر",
+  "report_notification.categories.spam": "سپام",
+  "report_notification.categories.violation": "پێشێلکردنی یاسا",
+  "report_notification.open": "ڕاپۆرتەکان بکەوە",
+  "search.no_recent_searches": "گەڕانەکانی ئەم دواییە",
   "search.placeholder": "گەڕان",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
-  "search.search_or_paste": "Search or paste URL",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
-  "search_results.accounts": "Profiles",
+  "search.quick_action.account_search": "پڕۆفایلی هاوتا لەگەڵ {x}",
+  "search.quick_action.go_to_account": "بڕۆ بۆ پڕۆفایلی{x}",
+  "search.quick_action.go_to_hashtag": "بڕۆ بۆ هاشتاگی {x}",
+  "search.quick_action.open_url": "بەستەرەکان لەناو ماستۆدۆن بکەوە",
+  "search.quick_action.status_search": "پڕۆفایلی هاوتا لەگەڵ {x}",
+  "search.search_or_paste": "گەڕان یان لێدانی URL",
+  "search_popout.quick_actions": "کرداری خێرا",
+  "search_popout.recent": "گەڕانەکانی ئەم دواییە",
+  "search_results.accounts": "پرۆفایلەکان",
   "search_results.all": "هەموو",
   "search_results.hashtags": "هەشتاگ",
-  "search_results.nothing_found": "Could not find anything for these search terms",
+  "search_results.nothing_found": "هیچ بۆ ئەم زاراوە گەڕانانە نەدۆزراوەتەوە",
   "search_results.statuses": "توتەکان",
   "search_results.statuses_fts_disabled": "گەڕانی توتەکان بە ناوەڕۆکیان لەسەر ئەم ڕاژەی ماستۆدۆن چالاک نەکراوە.",
-  "search_results.title": "Search for {q}",
+  "search_results.title": "گەڕان بەدوای {q}",
   "search_results.total": "{count, number} {count, plural, one {دەرئەنجام} other {دەرئەنجام}}",
-  "server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)",
+  "server_banner.about_active_users": "ئەو کەسانەی لە ماوەی ٣٠ ڕۆژی ڕابردوودا ئەم سێرڤەرە بەکاردەهێنن (بەکارهێنەرانی چالاک مانگانە)",
   "server_banner.active_users": "بەکارهێنەرانی چالاک",
   "server_banner.administered_by": "بەڕێوەبردن لەلایەن:",
   "server_banner.introduction": "{domain} بەشێکە لەو تۆڕە کۆمەڵایەتییە لامەرکەزییەی کە لەلایەن {mastodon}ەوە بەهێز دەکرێت.",
@@ -548,9 +548,9 @@
   "server_banner.server_stats": "دۆخی ڕاژەکار:",
   "sign_in_banner.create_account": "هەژمار دروستبکە",
   "sign_in_banner.sign_in": "بچۆ ژوورەوە",
-  "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts. You can also interact from your account on a different server.",
+  "sign_in_banner.text": "چوونەژوورەوە بۆ فۆڵۆوکردنی پڕۆفایلی یان هاشتاگەکان، دڵخوازەکان، شەیرکردن و وەڵامدانەوەی پۆستەکان. هەروەها دەتوانیت لە ئەکاونتەکەتەوە لەسەر سێرڤەرێکی جیاواز کارلێک بکەیت.",
   "status.admin_account": "کردنەوەی میانڕەوی بەڕێوەبەر بۆ @{name}",
-  "status.admin_domain": "Open moderation interface for {domain}",
+  "status.admin_domain": "ڕووکاری مامناوەندی بکەرەوە بۆ {domain}",
   "status.admin_status": "ئەم توتە بکەوە لە ناو ڕووکاری بەڕیوەبەر",
   "status.block": "@{name} ئاستەنگ بکە",
   "status.bookmark": "نیشانه",
@@ -559,8 +559,8 @@
   "status.copy": "ڕوونووسی بەستەر بۆ توت",
   "status.delete": "سڕینەوە",
   "status.detailed_status": "ڕوانگەی گفتوگۆ بە وردەکاری",
-  "status.direct": "Privately mention @{name}",
-  "status.direct_indicator": "Private mention",
+  "status.direct": "بە شێوەیەکی تایبەت باسی @{name} بکە",
+  "status.direct_indicator": "ئاماژەی تایبەت",
   "status.edit": "دەستکاری",
   "status.edited": "بەشداری {date}",
   "status.edited_x_times": "دەستکاریکراوە {count, plural, one {{count} کات} other {{count} کات}}",
@@ -568,7 +568,7 @@
   "status.favourite": "دڵخواز",
   "status.filter": "ئەم پۆستە فلتەر بکە",
   "status.filtered": "پاڵاوتن",
-  "status.hide": "Hide post",
+  "status.hide": "شاردنەوەی پۆست",
   "status.history.created": "{name} دروستکراوە لە{date}",
   "status.history.edited": "{name} دروستکاریکراوە لە{date}",
   "status.load_more": "زیاتر بار بکە",
diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json
index 29b5e3a46..a8cc9a5b2 100644
--- a/app/javascript/mastodon/locales/cs.json
+++ b/app/javascript/mastodon/locales/cs.json
@@ -20,7 +20,7 @@
   "account.blocked": "Blokovaný",
   "account.browse_more_on_origin_server": "Více na původním profilu",
   "account.cancel_follow_request": "Zrušit žádost o sledování",
-  "account.direct": "Privately mention @{name}",
+  "account.direct": "Soukromě zmínit @{name}",
   "account.disable_notifications": "Přestat mě upozorňovat, když @{name} zveřejní příspěvek",
   "account.domain_blocked": "Doména blokována",
   "account.edit_profile": "Upravit profil",
@@ -102,7 +102,7 @@
   "column.blocks": "Blokovaní uživatelé",
   "column.bookmarks": "Záložky",
   "column.community": "Místní časová osa",
-  "column.direct": "Private mentions",
+  "column.direct": "Soukromé zmínky",
   "column.directory": "Prozkoumat profily",
   "column.domain_blocks": "Blokované domény",
   "column.favourites": "Oblíbené",
@@ -163,7 +163,7 @@
   "confirmations.domain_block.confirm": "Blokovat celou doménu",
   "confirmations.domain_block.message": "Opravdu chcete blokovat celou doménu {domain}? Ve většině případů stačí blokovat nebo skrýt pár konkrétních uživatelů, což také doporučujeme. Z této domény neuvidíte obsah v žádné veřejné časové ose ani v oznámeních. Vaši sledující z této domény budou odstraněni.",
   "confirmations.edit.confirm": "Upravit",
-  "confirmations.edit.message": "Editing now will overwrite the message you are currently composing. Are you sure you want to proceed?",
+  "confirmations.edit.message": "Editovat teď znamená přepsání zprávy, kterou právě tvoříte. Opravdu chcete pokračovat?",
   "confirmations.logout.confirm": "Odhlásit se",
   "confirmations.logout.message": "Opravdu se chcete odhlásit?",
   "confirmations.mute.confirm": "Skrýt",
@@ -216,7 +216,7 @@
   "empty_column.blocks": "Ještě jste nezablokovali žádného uživatele.",
   "empty_column.bookmarked_statuses": "Zatím v záložkách nemáte žádné příspěvky. Až si do nich nějaký přidáte, zobrazí se zde.",
   "empty_column.community": "Místní časová osa je prázdná. Napište něco veřejně a rozhýbejte to tu!",
-  "empty_column.direct": "You don't have any private mentions yet. When you send or receive one, it will show up here.",
+  "empty_column.direct": "Zatím nemáte žádné soukromé zmínky. Až nějakou pošlete nebo dostanete, zobrazí se zde.",
   "empty_column.domain_blocks": "Ještě nemáte žádné zablokované domény.",
   "empty_column.explore_statuses": "Momentálně není nic populární. Vraťte se později!",
   "empty_column.favourited_statuses": "Zatím nemáte žádné oblíbené příspěvky. Až si nějaký oblíbíte, zobrazí se zde.",
@@ -376,7 +376,7 @@
   "navigation_bar.bookmarks": "Záložky",
   "navigation_bar.community_timeline": "Místní časová osa",
   "navigation_bar.compose": "Vytvořit nový příspěvek",
-  "navigation_bar.direct": "Private mentions",
+  "navigation_bar.direct": "Soukromé zmínky",
   "navigation_bar.discover": "Objevit",
   "navigation_bar.domain_blocks": "Blokované domény",
   "navigation_bar.edit_profile": "Upravit profil",
@@ -522,17 +522,17 @@
   "report_notification.categories.spam": "Spam",
   "report_notification.categories.violation": "Porušení pravidla",
   "report_notification.open": "Otevřít hlášení",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Žádná nedávná vyhledávání",
   "search.placeholder": "Hledat",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Profily odpovídající {x}",
+  "search.quick_action.go_to_account": "Přejít na profil {x}",
+  "search.quick_action.go_to_hashtag": "Přejít na hashtag {x}",
+  "search.quick_action.open_url": "Otevřít URL v Mastodonu",
+  "search.quick_action.status_search": "Příspěvky odpovídající {x}",
   "search.search_or_paste": "Hledat nebo vložit URL",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
-  "search_results.accounts": "Profiles",
+  "search_popout.quick_actions": "Rychlé akce",
+  "search_popout.recent": "Nedávná vyhledávání",
+  "search_results.accounts": "Profily",
   "search_results.all": "Vše",
   "search_results.hashtags": "Hashtagy",
   "search_results.nothing_found": "Pro tyto hledané výrazy nebylo nic nenalezeno",
@@ -560,7 +560,7 @@
   "status.delete": "Smazat",
   "status.detailed_status": "Podrobné zobrazení konverzace",
   "status.direct": "Privately mention @{name}",
-  "status.direct_indicator": "Private mention",
+  "status.direct_indicator": "Soukromá zmínka",
   "status.edit": "Upravit",
   "status.edited": "Upraveno {date}",
   "status.edited_x_times": "Upraveno {count, plural, one {{count}krát} few {{count}krát} many {{count}krát} other {{count}krát}}",
diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json
index 0116221e0..ca9caf79d 100644
--- a/app/javascript/mastodon/locales/da.json
+++ b/app/javascript/mastodon/locales/da.json
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "Spam",
   "report_notification.categories.violation": "Regelovertrædelse",
   "report_notification.open": "Åbn anmeldelse",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Ingen seneste søgninger",
   "search.placeholder": "Søg",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Profiler matchende {x}",
+  "search.quick_action.go_to_account": "Gå til profilen {x}",
+  "search.quick_action.go_to_hashtag": "Gå til hashtagget {x}",
+  "search.quick_action.open_url": "Åbn URL i Mastodon",
+  "search.quick_action.status_search": "Indlæg matchende {x}",
   "search.search_or_paste": "Søg efter eller angiv URL",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "Hurtige handlinger",
+  "search_popout.recent": "Seneste søgninger",
   "search_results.accounts": "Profiler",
   "search_results.all": "Alle",
   "search_results.hashtags": "Hashtags",
diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json
index f06954790..2312ca2fb 100644
--- a/app/javascript/mastodon/locales/de.json
+++ b/app/javascript/mastodon/locales/de.json
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "Spam",
   "report_notification.categories.violation": "Regelverstoß",
   "report_notification.open": "Meldung öffnen",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Keine kürzlichen Suchanfragen",
   "search.placeholder": "Suche",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Profile passend zu {x}",
+  "search.quick_action.go_to_account": "Profil {x} aufrufen",
+  "search.quick_action.go_to_hashtag": "Hashtag {x} aufrufen",
+  "search.quick_action.open_url": "URL in Mastodon öffnen",
+  "search.quick_action.status_search": "Beiträge passend zu {x}",
   "search.search_or_paste": "Suchen oder URL einfügen",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "Schnellaktionen",
+  "search_popout.recent": "Kürzliche Suchanfragen",
   "search_results.accounts": "Profile",
   "search_results.all": "Alles",
   "search_results.hashtags": "Hashtags",
diff --git a/app/javascript/mastodon/locales/el.json b/app/javascript/mastodon/locales/el.json
index f59cd38d7..cefc86853 100644
--- a/app/javascript/mastodon/locales/el.json
+++ b/app/javascript/mastodon/locales/el.json
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "Ανεπιθύμητα",
   "report_notification.categories.violation": "Παραβίαση κανόνα",
   "report_notification.open": "Ανοικτό",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Καμμία πρόσφατη αναζήτηση",
   "search.placeholder": "Αναζήτηση",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Προφίλ που ταιριάζουν με {x}",
+  "search.quick_action.go_to_account": "Μετάβαση στο προφίλ {x}",
+  "search.quick_action.go_to_hashtag": "Μετάβαση στην ετικέτα {x}",
+  "search.quick_action.open_url": "Άνοιγμα διεύθυνσης URL στο Mastodon",
+  "search.quick_action.status_search": "Αναρτήσεις που ταιριάζουν με {x}",
   "search.search_or_paste": "Αναζήτηση ή εισαγωγή URL",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "Γρήγορες ενέργειες",
+  "search_popout.recent": "Πρόσφατες αναζητήσεις",
   "search_results.accounts": "Προφίλ",
   "search_results.all": "Όλα",
   "search_results.hashtags": "Ετικέτες",
diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json
index 27b33c31f..be5ec1dc7 100644
--- a/app/javascript/mastodon/locales/eo.json
+++ b/app/javascript/mastodon/locales/eo.json
@@ -522,17 +522,17 @@
   "report_notification.categories.spam": "Trudmesaĝo",
   "report_notification.categories.violation": "Malobservo de la regulo",
   "report_notification.open": "Malfermi la raporton",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Neniuj lastaj serĉoj",
   "search.placeholder": "Serĉi",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Profiloj kiuj kongruas kun {x}",
+  "search.quick_action.go_to_account": "Iri al profilo {x}",
+  "search.quick_action.go_to_hashtag": "Iri al kradvorto {x}",
+  "search.quick_action.open_url": "Malfermi URL en Mastodono",
+  "search.quick_action.status_search": "Afiŝoj kiuj kongruas kun {x}",
   "search.search_or_paste": "Serĉu aŭ algluu URL-on",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
-  "search_results.accounts": "Profiles",
+  "search_popout.quick_actions": "Rapidaj agoj",
+  "search_popout.recent": "Lastaj serĉoj",
+  "search_results.accounts": "Profiloj",
   "search_results.all": "Ĉiuj",
   "search_results.hashtags": "Kradvortoj",
   "search_results.nothing_found": "Povis trovi nenion por ĉi tiuj serĉaj terminoj",
diff --git a/app/javascript/mastodon/locales/es-AR.json b/app/javascript/mastodon/locales/es-AR.json
index 1636229ed..a577cec79 100644
--- a/app/javascript/mastodon/locales/es-AR.json
+++ b/app/javascript/mastodon/locales/es-AR.json
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "Spam",
   "report_notification.categories.violation": "Violación de regla",
   "report_notification.open": "Abrir denuncia",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Sin búsquedas recientes",
   "search.placeholder": "Buscar",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Perfiles que coinciden con {x}",
+  "search.quick_action.go_to_account": "Ir al perfil de {x}",
+  "search.quick_action.go_to_hashtag": "Ir a la etiqueta {x}",
+  "search.quick_action.open_url": "Abrir enlace en Mastodon",
+  "search.quick_action.status_search": "Mensajes que coinciden con {x}",
   "search.search_or_paste": "Buscar o pegar dirección web",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "Acciones rápidas",
+  "search_popout.recent": "Búsquedas recientes",
   "search_results.accounts": "Perfiles",
   "search_results.all": "Todos",
   "search_results.hashtags": "Etiquetas",
diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json
index 4fc226b96..1338b8b46 100644
--- a/app/javascript/mastodon/locales/es-MX.json
+++ b/app/javascript/mastodon/locales/es-MX.json
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "Spam",
   "report_notification.categories.violation": "Infracción de regla",
   "report_notification.open": "Abrir denuncia",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Sin búsquedas recientes",
   "search.placeholder": "Buscar",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Perfiles que coinciden con {x}",
+  "search.quick_action.go_to_account": "Ir al perfil {x}",
+  "search.quick_action.go_to_hashtag": "Ir a la etiqueta {x}",
+  "search.quick_action.open_url": "Abrir enlace en Mastodon",
+  "search.quick_action.status_search": "Publicaciones que coinciden con {x}",
   "search.search_or_paste": "Buscar o pegar URL",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "Acciones rápidas",
+  "search_popout.recent": "Búsquedas recientes",
   "search_results.accounts": "Perfiles",
   "search_results.all": "Todos",
   "search_results.hashtags": "Etiquetas",
diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json
index 5eb68c4f8..d9f254055 100644
--- a/app/javascript/mastodon/locales/es.json
+++ b/app/javascript/mastodon/locales/es.json
@@ -59,13 +59,13 @@
   "account.show_reblogs": "Mostrar impulsos de @{name}",
   "account.statuses_counter": "{count, plural, one {{counter} Publicación} other {{counter} Publicaciones}}",
   "account.unblock": "Desbloquear a @{name}",
-  "account.unblock_domain": "Mostrar {domain}",
+  "account.unblock_domain": "Desbloquear dominio {domain}",
   "account.unblock_short": "Desbloquear",
   "account.unendorse": "No destacar en el perfil",
   "account.unfollow": "Dejar de seguir",
   "account.unmute": "Dejar de silenciar a @{name}",
   "account.unmute_notifications": "Dejar de silenciar las notificaciones de @{name}",
-  "account.unmute_short": "Desilenciar",
+  "account.unmute_short": "Dejar de silenciar",
   "account_note.placeholder": "Clic para añadir nota",
   "admin.dashboard.daily_retention": "Tasa de retención de usuarios por día después del registro",
   "admin.dashboard.monthly_retention": "Tasa de retención de usuarios por mes después del registro",
@@ -76,7 +76,7 @@
   "alert.rate_limited.title": "Tráfico limitado",
   "alert.unexpected.message": "Hubo un error inesperado.",
   "alert.unexpected.title": "¡Ups!",
-  "announcement.announcement": "Comunicación",
+  "announcement.announcement": "Anuncio",
   "attachments_list.unprocessed": "(sin procesar)",
   "audio.hide": "Ocultar audio",
   "autosuggest_hashtag.per_week": "{count} por semana",
@@ -140,12 +140,12 @@
   "compose_form.poll.switch_to_single": "Modificar encuesta para permitir una única opción",
   "compose_form.publish": "Publicar",
   "compose_form.publish_form": "Publicar",
-  "compose_form.publish_loud": "{publish}!",
+  "compose_form.publish_loud": "¡{publish}!",
   "compose_form.save_changes": "Guardar cambios",
   "compose_form.sensitive.hide": "{count, plural, one {Marcar material como sensible} other {Marcar material como sensible}}",
   "compose_form.sensitive.marked": "{count, plural, one {Material marcado como sensible} other {Material marcado como sensible}}",
   "compose_form.sensitive.unmarked": "{count, plural, one {Material no marcado como sensible} other {Material no marcado como sensible}}",
-  "compose_form.spoiler.marked": "Texto oculto tras la advertencia",
+  "compose_form.spoiler.marked": "Quitar advertencia de contenido",
   "compose_form.spoiler.unmarked": "Añadir advertencia de contenido",
   "compose_form.spoiler_placeholder": "Escribe aquí tu advertencia",
   "confirmation_modal.cancel": "Cancelar",
@@ -160,7 +160,7 @@
   "confirmations.delete_list.message": "¿Seguro que quieres borrar esta lista permanentemente?",
   "confirmations.discard_edit_media.confirm": "Descartar",
   "confirmations.discard_edit_media.message": "Tienes cambios sin guardar en la descripción o vista previa del archivo audiovisual, ¿descartarlos de todos modos?",
-  "confirmations.domain_block.confirm": "Ocultar dominio entero",
+  "confirmations.domain_block.confirm": "Bloquear dominio entero",
   "confirmations.domain_block.message": "¿Seguro de que quieres bloquear al dominio {domain} entero? En general unos cuantos bloqueos y silenciados concretos es suficiente y preferible.",
   "confirmations.edit.confirm": "Editar",
   "confirmations.edit.message": "Editar ahora reemplazará el mensaje que está escribiendo. ¿Está seguro que quiere proceder?",
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "Spam",
   "report_notification.categories.violation": "Infracción de regla",
   "report_notification.open": "Abrir informe",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Sin búsquedas recientes",
   "search.placeholder": "Buscar",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Perfiles que coinciden con {x}",
+  "search.quick_action.go_to_account": "Ir al perfil {x}",
+  "search.quick_action.go_to_hashtag": "Ir a la etiqueta {x}",
+  "search.quick_action.open_url": "Abrir enlace en Mastodon",
+  "search.quick_action.status_search": "Publicaciones que coinciden con {x}",
   "search.search_or_paste": "Buscar o pegar URL",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "Acciones rápidas",
+  "search_popout.recent": "Búsquedas recientes",
   "search_results.accounts": "Perfiles",
   "search_results.all": "Todos",
   "search_results.hashtags": "Etiquetas",
diff --git a/app/javascript/mastodon/locales/et.json b/app/javascript/mastodon/locales/et.json
index 7e39386aa..a61a577d6 100644
--- a/app/javascript/mastodon/locales/et.json
+++ b/app/javascript/mastodon/locales/et.json
@@ -224,7 +224,7 @@
   "empty_column.follow_recommendations": "Tundub, et sinu jaoks ei ole võimalik soovitusi luua. Proovi kasutada otsingut, et leida tuttavaid inimesi, või sirvi populaarseid silte.",
   "empty_column.follow_requests": "Pole hetkel ühtegi jälgimistaotlust. Kui saad mõne, näed neid siin.",
   "empty_column.followed_tags": "Sa ei jälgi veel ühtegi märksõna. Kui jälgid, ilmuvad need siia.",
-  "empty_column.hashtag": "Seda sildi all ei ole ühtegi postitust.",
+  "empty_column.hashtag": "Selle sildi all ei ole ühtegi postitust.",
   "empty_column.home": "Su koduajajoon on tühi. Jälgi rohkemaid inimesi, et seda täita {suggestions}",
   "empty_column.home.suggestions": "Vaata mõndasid soovitusi",
   "empty_column.list": "Siin loetelus pole veel midagi. Kui loetelu liikmed teevad uusi postitusi, näed neid siin.",
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "Rämpspost",
   "report_notification.categories.violation": "Reeglite rikkumine",
   "report_notification.open": "Ava teavitus",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Pole viimatisi otsinguid",
   "search.placeholder": "Otsi",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Sobivaid profiile {x}",
+  "search.quick_action.go_to_account": "Mine profiili {x}",
+  "search.quick_action.go_to_hashtag": "Ava silt {x}",
+  "search.quick_action.open_url": "Ava URL Mastodonis",
+  "search.quick_action.status_search": "Sobivad postitused {x}",
   "search.search_or_paste": "Otsi või kleebi URL",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "Kiirtegevused",
+  "search_popout.recent": "Viimatised otsingud",
   "search_results.accounts": "Profiilid",
   "search_results.all": "Kõik",
   "search_results.hashtags": "Sildid",
diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json
index 11ed5be8c..597f4fb50 100644
--- a/app/javascript/mastodon/locales/eu.json
+++ b/app/javascript/mastodon/locales/eu.json
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "Spam",
   "report_notification.categories.violation": "Arau haustea",
   "report_notification.open": "Ireki salaketa",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Duela gutxiko bilaketarik ez",
   "search.placeholder": "Bilatu",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "{x}-(r)ekin bat datozen profilak",
+  "search.quick_action.go_to_account": "Joan {x} profilera",
+  "search.quick_action.go_to_hashtag": "Joan {x} traolara",
+  "search.quick_action.open_url": "Ireki URLa Mastodonen",
+  "search.quick_action.status_search": "{x}-(r)ekin bat datozen argitalpenak",
   "search.search_or_paste": "Bilatu edo itsatsi URLa",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "Ekintza azkarrak",
+  "search_popout.recent": "Duela gutxiko bilaketak",
   "search_results.accounts": "Profilak",
   "search_results.all": "Guztiak",
   "search_results.hashtags": "Traolak",
diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json
index 2fdee7bca..37e213c01 100644
--- a/app/javascript/mastodon/locales/fa.json
+++ b/app/javascript/mastodon/locales/fa.json
@@ -20,7 +20,7 @@
   "account.blocked": "مسدود",
   "account.browse_more_on_origin_server": "مرور بیش‌تر روی نمایهٔ اصلی",
   "account.cancel_follow_request": "رد کردن درخواست پی‌گیری",
-  "account.direct": "Privately mention @{name}",
+  "account.direct": "خصوصی از @{name} نام ببرید",
   "account.disable_notifications": "آگاه کردن من هنگام فرسته‌های ‎@{name} را متوقّف کن",
   "account.domain_blocked": "دامنه مسدود شد",
   "account.edit_profile": "ویرایش نمایه",
@@ -102,7 +102,7 @@
   "column.blocks": "کاربران مسدود شده",
   "column.bookmarks": "نشانک‌ها",
   "column.community": "خط زمانی محلّی",
-  "column.direct": "Private mentions",
+  "column.direct": "خصوصی نام ببرید",
   "column.directory": "مرور نمایه‌ها",
   "column.domain_blocks": "دامنه‌های مسدود شده",
   "column.favourites": "پسندیده‌ها",
@@ -163,7 +163,7 @@
   "confirmations.domain_block.confirm": "مسدود کردن تمام دامنه",
   "confirmations.domain_block.message": "آیا جدی جدی می‌خواهید تمام دامنهٔ {domain} را مسدود کنید؟ در بیشتر موارد مسدود کردن یا خموشاندن چند حساب خاص کافی است و توصیه می‌شود. پس از این کار شما هیچ محتوایی را از این دامنه در خط زمانی عمومی یا آگاهی‌هایتان نخواهید دید. پی‌گیرانتان از این دامنه هم برداشته خواهند شد.",
   "confirmations.edit.confirm": "ویرایش",
-  "confirmations.edit.message": "Editing now will overwrite the message you are currently composing. Are you sure you want to proceed?",
+  "confirmations.edit.message": "در صورت ویرایش، پیامی که در حال نوشتنش بودید از بین خواهد رفت. می‌خواهید ادامه دهید؟",
   "confirmations.logout.confirm": "خروج از حساب",
   "confirmations.logout.message": "مطمئنید می‌خواهید خارج شوید؟",
   "confirmations.mute.confirm": "خموش",
@@ -216,14 +216,14 @@
   "empty_column.blocks": "هنوز کسی را مسدود نکرده‌اید.",
   "empty_column.bookmarked_statuses": "هنوز هیچ فرستهٔ نشانه‌گذاری شده‌ای ندارید. هنگامی که فرسته‌ای را نشانه‌گذاری کنید، این‌جا نشان داده خواهد شد.",
   "empty_column.community": "خط زمانی محلّی خالی است. چیزی بنویسید تا چرخش بچرخد!",
-  "empty_column.direct": "You don't have any private mentions yet. When you send or receive one, it will show up here.",
+  "empty_column.direct": "هنوز هیچ اشاره خصوصی‌ای ندارید. هنگامی که چنین پیامی بگیرید یا بفرستید این‌جا نشان داده خواهد شد.",
   "empty_column.domain_blocks": "هنوز هیچ دامنه‌ای مسدود نشده است.",
   "empty_column.explore_statuses": "الآن چیزی پرطرفدار نیست. بعداً دوباره بررسی کنید!",
   "empty_column.favourited_statuses": "شما هنوز هیچ فرسته‌ای را نپسندیده‌اید. هنگامی که فرسته‌ای را بپسندید، این‌جا نشان داده خواهد شد.",
   "empty_column.favourites": "هنوز هیچ کسی این فرسته را نپسندیده است. هنگامی که کسی آن را بپسندد، این‌جا نشان داده خواهد شد.",
   "empty_column.follow_recommendations": "به نظر نمی‌توان هیچ پیشنهادی برایتان ایجاد کرد. می‌توانید برای یافتن افرادی که ممکن است بشناسید از جست‌وجو یا کاوش برچسب‌های داغ استفاده کنید.",
   "empty_column.follow_requests": "شما هنوز هیچ درخواست پی‌گیری‌ای ندارید. هنگامی که چنین درخواستی بگیرید، این‌جا نشان داده خواهد شد.",
-  "empty_column.followed_tags": "You have not followed any hashtags yet. When you do, they will show up here.",
+  "empty_column.followed_tags": "شما هیچ برچسبی را پی‌نگرفتید. هنگامی که برچسبی را پی‌گیری کنید اینجا نمایان می‌شوند.",
   "empty_column.hashtag": "هنوز هیچ چیزی در این برچسب نیست.",
   "empty_column.home": "خط زمانی خانگیتان خالی است! برای پر کردنش، افراد بیشتری را پی بگیرید. {suggestions}",
   "empty_column.home.suggestions": "چند پیشنهاد را ببینید",
@@ -314,7 +314,7 @@
   "keyboard_shortcuts.column": "برای تمرکز روی یک فرسته در یکی از ستون‌ها",
   "keyboard_shortcuts.compose": "تمرکز روی محیط نوشتن",
   "keyboard_shortcuts.description": "توضیح",
-  "keyboard_shortcuts.direct": "to open direct messages column",
+  "keyboard_shortcuts.direct": "باز کردن ستون اشاره‌های خصوصی",
   "keyboard_shortcuts.down": "پایین بردن در سیاهه",
   "keyboard_shortcuts.enter": "گشودن فرسته",
   "keyboard_shortcuts.favourite": "پسندیدن فرسته",
@@ -376,7 +376,7 @@
   "navigation_bar.bookmarks": "نشانک‌ها",
   "navigation_bar.community_timeline": "خط زمانی محلّی",
   "navigation_bar.compose": "نوشتن فرستهٔ تازه",
-  "navigation_bar.direct": "Private mentions",
+  "navigation_bar.direct": "اشاره‌های خصوصی",
   "navigation_bar.discover": "گشت و گذار",
   "navigation_bar.domain_blocks": "دامنه‌های مسدود شده",
   "navigation_bar.edit_profile": "ویرایش نمایه",
@@ -522,17 +522,17 @@
   "report_notification.categories.spam": "هرزنامه",
   "report_notification.categories.violation": "تخطّی از قانون",
   "report_notification.open": "گشودن گزارش",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "جست‌وجوی اخیری نیست",
   "search.placeholder": "جست‌وجو",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "نمایه‌های جور با {x}",
+  "search.quick_action.go_to_account": "برو به نمایه {x}",
+  "search.quick_action.go_to_hashtag": "برو به برچسب {x}",
+  "search.quick_action.open_url": "باز کردن پیوند در ماستودون",
+  "search.quick_action.status_search": "فرسته‌های جور با {x}",
   "search.search_or_paste": "جست‌وجو یا جایگذاری نشانی",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
-  "search_results.accounts": "Profiles",
+  "search_popout.quick_actions": "کنش‌های سریع",
+  "search_popout.recent": "جست‌وجوهای اخیر",
+  "search_results.accounts": "نمایه‌ها",
   "search_results.all": "همه",
   "search_results.hashtags": "برچسب‌ها",
   "search_results.nothing_found": "چیزی برای این عبارت جست‌وجو یافت نشد",
@@ -548,7 +548,7 @@
   "server_banner.server_stats": "آمار کارساز:",
   "sign_in_banner.create_account": "ایجاد حساب",
   "sign_in_banner.sign_in": "ورود",
-  "sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts. You can also interact from your account on a different server.",
+  "sign_in_banner.text": "برای پی‌گیری نمایه‌ها یا برچسب‌ها، پسندیدن، هم‌رسانی و یا پاسخ به فرسته‌ها وارد شوید. همچنین می‌توانید این کارها را با حسابتان در کارسازی دیگر انجام دهید.",
   "status.admin_account": "گشودن واسط مدیریت برای ‎@{name}",
   "status.admin_domain": "گشودن واسط مدیریت برای ‎{domain}",
   "status.admin_status": "گشودن این فرسته در واسط مدیریت",
@@ -559,8 +559,8 @@
   "status.copy": "رونوشت از پیوند فرسته",
   "status.delete": "حذف",
   "status.detailed_status": "نمایش کامل گفتگو",
-  "status.direct": "Privately mention @{name}",
-  "status.direct_indicator": "Private mention",
+  "status.direct": "خصوصی به @{name} اشاره کنید",
+  "status.direct_indicator": "اشاره خصوصی",
   "status.edit": "ویرایش",
   "status.edited": "ویرایش شده در {date}",
   "status.edited_x_times": "{count, plural, one {{count} مرتبه} other {{count} مرتبه}} ویرایش شد",
diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json
index eaed4906f..a086e0e21 100644
--- a/app/javascript/mastodon/locales/fi.json
+++ b/app/javascript/mastodon/locales/fi.json
@@ -153,14 +153,14 @@
   "confirmations.block.confirm": "Estä",
   "confirmations.block.message": "Haluatko varmasti estää käyttäjän {name}?",
   "confirmations.cancel_follow_request.confirm": "Peruuta pyyntö",
-  "confirmations.cancel_follow_request.message": "Haluatko varmasti peruuttaa pyyntösi seurata käyttäjää {name}?",
+  "confirmations.cancel_follow_request.message": "Haluatko varmasti peruuttaa pyyntösi seurata profiilia {name}?",
   "confirmations.delete.confirm": "Poista",
   "confirmations.delete.message": "Haluatko varmasti poistaa tämän viestin?",
   "confirmations.delete_list.confirm": "Poista",
   "confirmations.delete_list.message": "Haluatko varmasti poistaa tämän listan kokonaan?",
   "confirmations.discard_edit_media.confirm": "Hylkää",
   "confirmations.discard_edit_media.message": "Sinulla on tallentamattomia muutoksia median kuvaukseen tai esikatseluun, hylätäänkö ne silti?",
-  "confirmations.domain_block.confirm": "Estä koko palvelu",
+  "confirmations.domain_block.confirm": "Estä koko verkkotunnus",
   "confirmations.domain_block.message": "Haluatko aivan varmasti estää palvelun {domain} täysin? Useimmiten muutama kohdistettu esto tai mykistys on riittävä ja suositeltava toimenpide. Et näe kyseisen sisältöä kyseiseltä verkkoalueelta missään julkisissa aikajanoissa tai ilmoituksissa. Tälle verkkoalueelle kuuluvat seuraajasi poistetaan.",
   "confirmations.edit.confirm": "Muokkaa",
   "confirmations.edit.message": "Muokkaaminen nyt korvaa viestin, jota paraikaa työstät. Haluatko varmasti jatkaa?",
@@ -168,13 +168,13 @@
   "confirmations.logout.message": "Haluatko varmasti kirjautua ulos?",
   "confirmations.mute.confirm": "Mykistä",
   "confirmations.mute.explanation": "Tämä toiminto piilottaa heidän julkaisunsa sinulta – mukaan lukien ne, joissa heidät mainitaan – sallien heidän yhä nähdä julkaisusi ja seurata sinua.",
-  "confirmations.mute.message": "Haluatko varmasti mykistää käyttäjän {name}?",
+  "confirmations.mute.message": "Haluatko varmasti mykistää profiilin {name}?",
   "confirmations.redraft.confirm": "Poista & palauta muokattavaksi",
   "confirmations.redraft.message": "Oletko varma että haluat poistaa tämän julkaisun ja tehdä siitä uuden luonnoksen? Suosikit ja tehostukset menetään, alkuperäisen julkaisusi vastaukset jäävät orvoiksi.",
   "confirmations.reply.confirm": "Vastaa",
   "confirmations.reply.message": "Jos vastaat nyt, vastaus korvaa tällä hetkellä työstämäsi viestin. Oletko varma, että haluat jatkaa?",
   "confirmations.unfollow.confirm": "Lopeta seuraaminen",
-  "confirmations.unfollow.message": "Haluatko varmasti lakata seuraamasta käyttäjää {name}?",
+  "confirmations.unfollow.message": "Haluatko varmasti lakata seuraamasta profiilia {name}?",
   "conversation.delete": "Poista keskustelu",
   "conversation.mark_as_read": "Merkitse luetuksi",
   "conversation.open": "Näytä keskustelu",
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "Roskaposti",
   "report_notification.categories.violation": "Sääntöjen rikkominen",
   "report_notification.open": "Avaa ilmoitus",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Edellisiä hakuja ei ole",
   "search.placeholder": "Hae",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Profiilit, jotka vastaavat \"{x}\"",
+  "search.quick_action.go_to_account": "Avaa profiili {x}",
+  "search.quick_action.go_to_hashtag": "Avaa aihetunniste {x}",
+  "search.quick_action.open_url": "Avaa URL-osoite Mastodonissa",
+  "search.quick_action.status_search": "Julkaisut, jotka vastaavat \"{x}\"",
   "search.search_or_paste": "Etsi tai kirjoita URL-osoite",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "Pikatoiminnot",
+  "search_popout.recent": "Edelliset haut",
   "search_results.accounts": "Profiilit",
   "search_results.all": "Kaikki",
   "search_results.hashtags": "Aihetunnisteet",
diff --git a/app/javascript/mastodon/locales/fo.json b/app/javascript/mastodon/locales/fo.json
index 714d405f8..29a2f7bc2 100644
--- a/app/javascript/mastodon/locales/fo.json
+++ b/app/javascript/mastodon/locales/fo.json
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "Ruskpostur",
   "report_notification.categories.violation": "Brotin regla",
   "report_notification.open": "Opna melding",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Ongar nýggjar leitingar",
   "search.placeholder": "Leita",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Vangar, ið samsvara {x}",
+  "search.quick_action.go_to_account": "Far til vanga {x}",
+  "search.quick_action.go_to_hashtag": "Far til frámerki {x}",
+  "search.quick_action.open_url": "Lat URL upp í Mastodon",
+  "search.quick_action.status_search": "Postar, ið samsvara {x}",
   "search.search_or_paste": "Leita ella set URL inn",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "Skjótar atgerðir",
+  "search_popout.recent": "Nýggjar leitingar",
   "search_results.accounts": "Vangar",
   "search_results.all": "Alt",
   "search_results.hashtags": "Frámerki",
diff --git a/app/javascript/mastodon/locales/fy.json b/app/javascript/mastodon/locales/fy.json
index f0e5cf982..d4dfe35a2 100644
--- a/app/javascript/mastodon/locales/fy.json
+++ b/app/javascript/mastodon/locales/fy.json
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "Spam",
   "report_notification.categories.violation": "Skeinde regels",
   "report_notification.open": "Rapport iepenje",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Gjin resinte sykopdrachten",
   "search.placeholder": "Sykje",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Accounts dy’t oerienkomme mei {x}",
+  "search.quick_action.go_to_account": "Gean nei account {x}",
+  "search.quick_action.go_to_hashtag": "Gean nei hashtag {x}",
+  "search.quick_action.open_url": "URL yn Mastodon iepenje",
+  "search.quick_action.status_search": "Berjochten dy’t oerienkomme mei {x}",
   "search.search_or_paste": "Sykje of fier URL yn",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "Flugge aksjes",
+  "search_popout.recent": "Resinte sykopdrachten",
   "search_results.accounts": "Profilen",
   "search_results.all": "Alles",
   "search_results.hashtags": "Hashtags",
diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json
index a2e6716c9..20279e71f 100644
--- a/app/javascript/mastodon/locales/gl.json
+++ b/app/javascript/mastodon/locales/gl.json
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "Spam",
   "report_notification.categories.violation": "Faltou ás regras",
   "report_notification.open": "Abrir a denuncia",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Non hai buscas recentes",
   "search.placeholder": "Procurar",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Perfís coincidentes {x}",
+  "search.quick_action.go_to_account": "Ir ao perfil {x}",
+  "search.quick_action.go_to_hashtag": "Ir ao cancelo {x}",
+  "search.quick_action.open_url": "Abrir URL en Mastodon",
+  "search.quick_action.status_search": "Publicacións coincidentes {x}",
   "search.search_or_paste": "Busca ou insire URL",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "Accións rápidas",
+  "search_popout.recent": "Buscas recentes",
   "search_results.accounts": "Perfís",
   "search_results.all": "Todo",
   "search_results.hashtags": "Cancelos",
diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json
index 25fdb28dd..17b97ca74 100644
--- a/app/javascript/mastodon/locales/he.json
+++ b/app/javascript/mastodon/locales/he.json
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "ספאם (דואר זבל)",
   "report_notification.categories.violation": "הפרת כלל",
   "report_notification.open": "פתח דו\"ח",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "לא נמצאו חיפושים אחרונים",
   "search.placeholder": "חיפוש",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "פרופילים המכילים {x}",
+  "search.quick_action.go_to_account": "לצפיה בפרופיל {x}",
+  "search.quick_action.go_to_hashtag": "לצפיה בתגית {x}",
+  "search.quick_action.open_url": "לפתיחת {x} במסטודון",
+  "search.quick_action.status_search": "הודעות המכילות {x}",
   "search.search_or_paste": "חפש או הזן קישור",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "פעולות זריזות",
+  "search_popout.recent": "חיפושים אחרונים",
   "search_results.accounts": "פרופילים",
   "search_results.all": "כל התוצאות",
   "search_results.hashtags": "תגיות",
diff --git a/app/javascript/mastodon/locales/hi.json b/app/javascript/mastodon/locales/hi.json
index 2803c8417..186de8129 100644
--- a/app/javascript/mastodon/locales/hi.json
+++ b/app/javascript/mastodon/locales/hi.json
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "Spam",
   "report_notification.categories.violation": "Rule violation",
   "report_notification.open": "Open report",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "कोई हालिया खोज नहीं",
   "search.placeholder": "खोजें",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "प्रोफ़ाइल मिले {x}",
+  "search.quick_action.go_to_account": "प्रोफ़ाइल पर जाएँ {x}",
+  "search.quick_action.go_to_hashtag": "हैशटैग पर जाएं {x}",
+  "search.quick_action.open_url": "URL मॅस्टोडॉन में खोलें",
+  "search.quick_action.status_search": "पोस्ट मिलें {x}",
   "search.search_or_paste": "Search or paste URL",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "त्वरित क्रियाएं",
+  "search_popout.recent": "हालिया खोजें",
   "search_results.accounts": "प्रोफ़ाइल",
   "search_results.all": "All",
   "search_results.hashtags": "Hashtags",
diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json
index 6b16f47b3..4cd7ebde7 100644
--- a/app/javascript/mastodon/locales/hu.json
+++ b/app/javascript/mastodon/locales/hu.json
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "Kéretlen üzenet",
   "report_notification.categories.violation": "Szabálysértés",
   "report_notification.open": "Bejelentés megnyitása",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Nincsenek keresési előzmények",
   "search.placeholder": "Keresés",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Profilok a következő keresésre: {x}",
+  "search.quick_action.go_to_account": "Ugrás a következő profilhoz: {x}",
+  "search.quick_action.go_to_hashtag": "Ugrás a következő hashtaghez: {x}",
+  "search.quick_action.open_url": "Webcím megnyitása a Mastodonon",
+  "search.quick_action.status_search": "Bejegyzések a következő keresésre: {x}",
   "search.search_or_paste": "Keresés vagy webcím beillesztése",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "Gyors műveletek",
+  "search_popout.recent": "Legutóbbi keresések",
   "search_results.accounts": "Profilok",
   "search_results.all": "Összes",
   "search_results.hashtags": "#Címkék",
diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json
index 5127978b0..b9d650473 100644
--- a/app/javascript/mastodon/locales/is.json
+++ b/app/javascript/mastodon/locales/is.json
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "Ruslpóstur",
   "report_notification.categories.violation": "Brot á reglum",
   "report_notification.open": "Opin kæra",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Engar nýlegar leitir",
   "search.placeholder": "Leita",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Notandasnið sem samsvara {x}",
+  "search.quick_action.go_to_account": "Fara á notandasnið {x}",
+  "search.quick_action.go_to_hashtag": "Fara á myllumerkið {x}",
+  "search.quick_action.open_url": "Opna slóð í Mastodon",
+  "search.quick_action.status_search": "Færslur sem samsvara {x}",
   "search.search_or_paste": "Leita eða líma slóð",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "Flýtiaðgerðir",
+  "search_popout.recent": "Nýlegar leitir",
   "search_results.accounts": "Notendasnið",
   "search_results.all": "Allt",
   "search_results.hashtags": "Myllumerki",
diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json
index 7ac0dfacd..ab1cc02af 100644
--- a/app/javascript/mastodon/locales/it.json
+++ b/app/javascript/mastodon/locales/it.json
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "Spam",
   "report_notification.categories.violation": "Violazione delle regole",
   "report_notification.open": "Apri segnalazione",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Nessuna ricerca recente",
   "search.placeholder": "Cerca",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Profili corrispondenti a {x}",
+  "search.quick_action.go_to_account": "Vai al profilo {x}",
+  "search.quick_action.go_to_hashtag": "Vai all'hashtag {x}",
+  "search.quick_action.open_url": "Apri URL in Mastodon",
+  "search.quick_action.status_search": "Post corrispondenti a {x}",
   "search.search_or_paste": "Cerca o incolla URL",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "Azioni rapide",
+  "search_popout.recent": "Ricerche recenti",
   "search_results.accounts": "Profili",
   "search_results.all": "Tutto",
   "search_results.hashtags": "Hashtag",
diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json
index d1fb586f3..dee4baea9 100644
--- a/app/javascript/mastodon/locales/ja.json
+++ b/app/javascript/mastodon/locales/ja.json
@@ -526,16 +526,16 @@
   "report_notification.categories.spam": "スパム",
   "report_notification.categories.violation": "ルール違反",
   "report_notification.open": "通報を開く",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "検索履歴はありません",
   "search.placeholder": "検索",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "{x} に該当するプロフィール",
+  "search.quick_action.go_to_account": "{x} のプロフィールを見る",
+  "search.quick_action.go_to_hashtag": "{x} に該当するハッシュタグ",
+  "search.quick_action.open_url": "MastodonでURLを開く",
+  "search.quick_action.status_search": "{x} に該当する投稿",
   "search.search_or_paste": "検索またはURLを入力",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "クイック操作",
+  "search_popout.recent": "最近の検索",
   "search_results.accounts": "ユーザー",
   "search_results.all": "すべて",
   "search_results.hashtags": "ハッシュタグ",
diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json
index b08e0b45c..7d7659569 100644
--- a/app/javascript/mastodon/locales/ko.json
+++ b/app/javascript/mastodon/locales/ko.json
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "스팸",
   "report_notification.categories.violation": "규칙 위반",
   "report_notification.open": "신고 열기",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "최근 검색 기록이 없습니다",
   "search.placeholder": "검색",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "{x}에 맞는 프로필",
+  "search.quick_action.go_to_account": "{x} 프로필로 이동",
+  "search.quick_action.go_to_hashtag": "{x} 해시태그로 이동",
+  "search.quick_action.open_url": "마스토돈에서 URL 열기",
+  "search.quick_action.status_search": "{x}에 맞는 게시물",
   "search.search_or_paste": "검색하거나 URL 붙여넣기",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "빠른 작업",
+  "search_popout.recent": "최근 검색",
   "search_results.accounts": "프로필",
   "search_results.all": "전부",
   "search_results.hashtags": "해시태그",
diff --git a/app/javascript/mastodon/locales/lv.json b/app/javascript/mastodon/locales/lv.json
index c3d82bd16..4f1032ae2 100644
--- a/app/javascript/mastodon/locales/lv.json
+++ b/app/javascript/mastodon/locales/lv.json
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "Spams",
   "report_notification.categories.violation": "Noteikumu pārkāpums",
   "report_notification.open": "Atvērt sūdzību",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Nav nesen veiktu meklējumu",
   "search.placeholder": "Meklēšana",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Profili atbilst {x}",
+  "search.quick_action.go_to_account": "Doties uz profilu {x}",
+  "search.quick_action.go_to_hashtag": "Doties uz tēmturi {x}",
+  "search.quick_action.open_url": "Atvērt URL Mastodonā",
+  "search.quick_action.status_search": "Ziņas atbilst {x}",
   "search.search_or_paste": "Meklē vai iekopē URL",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "Ātrās darbības",
+  "search_popout.recent": "Nesen meklētais",
   "search_results.accounts": "Profili",
   "search_results.all": "Visi",
   "search_results.hashtags": "Tēmturi",
diff --git a/app/javascript/mastodon/locales/my.json b/app/javascript/mastodon/locales/my.json
index 838e18da1..197addd1b 100644
--- a/app/javascript/mastodon/locales/my.json
+++ b/app/javascript/mastodon/locales/my.json
@@ -20,7 +20,7 @@
   "account.blocked": "ဘလော့ထားသည်",
   "account.browse_more_on_origin_server": "မူရင်းပရိုဖိုင်တွင် ပိုမိုကြည့်ရှုပါ။",
   "account.cancel_follow_request": "ဖောလိုးပယ်ဖျက်ခြင်း",
-  "account.direct": "Privately mention @{name}",
+  "account.direct": "@{name} သာသိရှိနိုင်အောင်မန်းရှင်းခေါ်မည်",
   "account.disable_notifications": "@{name} ပို့စ်တင်သည့်အခါ ကျွန်ုပ်ကို အသိပေးခြင်းရပ်ပါ။",
   "account.domain_blocked": "ဒိုမိန်း ပိတ်ပင်ထားခဲ့သည်\n",
   "account.edit_profile": "ကိုယ်ရေးမှတ်တမ်းပြင်ဆင်မည်",
@@ -102,7 +102,7 @@
   "column.blocks": "ဘလော့ထားသောအကောင့်များ",
   "column.bookmarks": "မှတ်တမ်းများ",
   "column.community": "ဒေသတွင်း အချိန်ဇယား",
-  "column.direct": "Private mentions",
+  "column.direct": "သီးသန့်ဖော်ပြခြင်း",
   "column.directory": "ပရိုဖိုင်များကို ရှာဖွေမည်\n",
   "column.domain_blocks": "  ဒိုမိန်းကိုပိတ်မည်",
   "column.favourites": "အကြိုက်ဆုံးများ",
@@ -216,7 +216,7 @@
   "empty_column.blocks": "ပိတ်ထားသောအကောင့်များမရှိသေးပါ",
   "empty_column.bookmarked_statuses": "သင့်တွင် မှတ်သားထားသော ပို့စ်များ မရှိသေးပါ။ တစ်ခုကို အမှတ်အသားပြုလိုက်ပါက ၎င်းကို ဤနေရာတွင် ပြထားပါမည်။",
   "empty_column.community": "ဒေသတွင်းစာမျက်နှာမှာ အလွတ်ဖြစ်နေသည်။ အများမြင်နိုင်ရန်အတွက် တစ်ခုခုရေးပါ။",
-  "empty_column.direct": "You don't have any private mentions yet. When you send or receive one, it will show up here.",
+  "empty_column.direct": "သင့်တွင် သီးသန့်ဖော်ပြချက်များ မရှိသေးပါ။ ပေးပို့ခြင်း သို့မဟုတ် လက်ခံသောအခါ၊ ၎င်းသည် ဤနေရာတွင် ပေါ်လာလိမ့်မည်။",
   "empty_column.domain_blocks": "သင်ပိတ်ထားသော ဒိုမိန်းမရှိသေးပါ",
   "empty_column.explore_statuses": "အခုလောလောဆယ်တွင် ရေပန်းစားနေသောပို့စ်များ မရှိသေးပါ။ နောက်မှ ပြန်စစ်ဆေးပါရန်။",
   "empty_column.favourited_statuses": "သင့်တွင် အကြိုက်ဆုံးပို့စ်များ မရှိသေးပါ။ တစ်ခုကို သင်နှစ်သက်ထားပါက ၎င်းကို ဤနေရာတွင် ပြထားပါမည်။",
@@ -314,7 +314,7 @@
   "keyboard_shortcuts.column": "to focus a status in one of the columns",
   "keyboard_shortcuts.compose": "to focus the compose textarea",
   "keyboard_shortcuts.description": "ဖော်ပြချက်",
-  "keyboard_shortcuts.direct": "to open direct messages column",
+  "keyboard_shortcuts.direct": "သီးသန့်ဖော်ပြချက်များကော်လံကိုဖွင့်ရန်",
   "keyboard_shortcuts.down": "to move down in the list",
   "keyboard_shortcuts.enter": "to open status",
   "keyboard_shortcuts.favourite": "to favourite",
@@ -376,7 +376,7 @@
   "navigation_bar.bookmarks": "မှတ်ထားသည်များ",
   "navigation_bar.community_timeline": "ဒေသစံတော်ချိန်",
   "navigation_bar.compose": "ပို့စ်အသစ်ရေးပါ",
-  "navigation_bar.direct": "Private mentions",
+  "navigation_bar.direct": "သီးသန့်ဖော်ပြချက်များ",
   "navigation_bar.discover": "ရှာဖွေပါ",
   "navigation_bar.domain_blocks": "Hidden domains",
   "navigation_bar.edit_profile": "ကိုယ်ရေးမှတ်တမ်းပြင်ဆင်မည်",
@@ -522,17 +522,17 @@
   "report_notification.categories.spam": "Spam",
   "report_notification.categories.violation": "စည်းကမ်းဖောက်ဖျက်ခြင်း",
   "report_notification.open": "အစီရင်ခံစာကိုဖွင့်ပါ",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "လတ်တလောရှာဖွေမှုများမရှိပါ။",
   "search.placeholder": "ရှာဖွေရန်",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "{x} နှင့် ကိုက်ညီသော ပရိုဖိုင်များ",
+  "search.quick_action.go_to_account": "ပရိုဖိုင် {x} သို့သွားမည်",
+  "search.quick_action.go_to_hashtag": "hashtag {x} သို့သွားမည်",
+  "search.quick_action.open_url": "Mastodon တွင် URL ကိုဖွင့်မည်",
+  "search.quick_action.status_search": "{x} နှင့် ကိုက်ညီသော ပို့စ်များ",
   "search.search_or_paste": "URL ရိုက်ထည့်ပါ သို့မဟုတ် ရှာဖွေပါ",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
-  "search_results.accounts": "Profiles",
+  "search_popout.quick_actions": "အမြန်လုပ်ဆောင်မှုများ",
+  "search_popout.recent": "လတ်တလော ရှာဖွေမှုများ",
+  "search_results.accounts": "စာမျက်နှာ",
   "search_results.all": "အားလုံး",
   "search_results.hashtags": "ဟက်ရှ်တက်များ",
   "search_results.nothing_found": "ရှာဖွေလိုသောအရာမရှိပါ",
@@ -559,8 +559,8 @@
   "status.copy": "Copy link to status",
   "status.delete": "ဖျက်ရန်",
   "status.detailed_status": "အသေးစိတ်စကားပြောဆိုမှုမြင်ကွင်း",
-  "status.direct": "Privately mention @{name}",
-  "status.direct_indicator": "Private mention",
+  "status.direct": "@{name} ကို သီးသန့်ဖော်ပြမည်\n",
+  "status.direct_indicator": "သီးသန့်ဖော်ပြခြင်း။",
   "status.edit": "ပြင်ဆင်ရန်",
   "status.edited": "{date} ကို ပြင်ဆင်ပြီးပါပြီ",
   "status.edited_x_times": "{count, plural, one {{count} time} other {{count} times}} ပြင်ဆင်ခဲ့သည်",
@@ -646,7 +646,7 @@
   "upload_modal.description_placeholder": "သီဟိုဠ်မှ ဉာဏ်ကြီးရှင်သည် အာယုဝဍ္ဎနဆေးညွှန်းစာကို ဇလွန်ဈေးဘေး ဗာဒံပင်ထက် အဓိဋ္ဌာန်လျက် ဂဃနဏဖတ်ခဲ့သည်",
   "upload_modal.detect_text": "ပုံမှစာသားကို ရှာဖွေပါ",
   "upload_modal.edit_media": "မီဒီယာကို ပြင်ဆင်ရန်",
-  "upload_modal.hint": "Click or drag the circle on the preview to choose the focal point which will always be in view on all thumbnails.",
+  "upload_modal.hint": "ပုံသေးအားလုံးတွင် အမြဲတမ်းကြည့်ရှုနိုင်သည့် focal point ကို ရွေးချယ်ရန် Preview ပေါ်ရှိ စက်ဝိုင်းကို နှိပ်ပါ သို့မဟုတ် ဖိဆွဲပါ။",
   "upload_modal.preparing_ocr": "OCR ပြင်ဆင်နေသည်…",
   "upload_modal.preview_label": "({ratio}) အစမ်းကြည့်ရှုရန်",
   "upload_progress.label": "တင်နေသည်...",
diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json
index 6e080da9b..bb33a6f0c 100644
--- a/app/javascript/mastodon/locales/nl.json
+++ b/app/javascript/mastodon/locales/nl.json
@@ -55,7 +55,7 @@
   "account.report": "@{name} rapporteren",
   "account.requested": "Wachten op goedkeuring. Klik om het volgverzoek te annuleren",
   "account.requested_follow": "{name} wil je graag volgen",
-  "account.share": "Profiel van @{name} delen",
+  "account.share": "Account van @{name} delen",
   "account.show_reblogs": "Boosts van @{name} tonen",
   "account.statuses_counter": "{count, plural, one {{counter} bericht} other {{counter} berichten}}",
   "account.unblock": "@{name} deblokkeren",
@@ -487,7 +487,7 @@
   "report.categories.violation": "De inhoud overtreedt een of meerdere serverregels",
   "report.category.subtitle": "Kies wat het beste overeenkomt",
   "report.category.title": "Vertel ons wat er met dit {type} aan de hand is",
-  "report.category.title_account": "profiel",
+  "report.category.title_account": "account",
   "report.category.title_status": "bericht",
   "report.close": "Klaar",
   "report.comment.title": "Zijn er nog andere dingen waarvan je denkt dat wij dat moeten weten?",
@@ -522,17 +522,17 @@
   "report_notification.categories.spam": "Spam",
   "report_notification.categories.violation": "Overtreden regel(s)",
   "report_notification.open": "Rapportage openen",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Geen recente zoekopdrachten",
   "search.placeholder": "Zoeken",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Accounts die overeenkomen met {x}",
+  "search.quick_action.go_to_account": "Ga naar account {x}",
+  "search.quick_action.go_to_hashtag": "Ga naar hashtag {x}",
+  "search.quick_action.open_url": "URL in Mastodon openen",
+  "search.quick_action.status_search": "Berichten die overeenkomen met {x}",
   "search.search_or_paste": "Zoek of voer een URL in",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
-  "search_results.accounts": "Profielen",
+  "search_popout.quick_actions": "Snelle acties",
+  "search_popout.recent": "Recente zoekopdrachten",
+  "search_results.accounts": "Accounts",
   "search_results.all": "Alles",
   "search_results.hashtags": "Hashtags",
   "search_results.nothing_found": "Deze zoektermen leveren geen resultaat op",
diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json
index e26c592ed..4df5d8431 100644
--- a/app/javascript/mastodon/locales/pl.json
+++ b/app/javascript/mastodon/locales/pl.json
@@ -527,16 +527,16 @@
   "report_notification.categories.spam": "Spam",
   "report_notification.categories.violation": "Naruszenie zasad",
   "report_notification.open": "Otwórz raport",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Brak ostatnich wyszukiwań",
   "search.placeholder": "Szukaj",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Profile pasujące do {x}",
+  "search.quick_action.go_to_account": "Przejdź do profilu {x}",
+  "search.quick_action.go_to_hashtag": "Przejdź do hasztaga {x}",
+  "search.quick_action.open_url": "Otwórz adres URL w Mastodonie",
+  "search.quick_action.status_search": "Wpisy pasujące do {x}",
   "search.search_or_paste": "Wyszukaj lub wklej adres",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "Szybkie akcje",
+  "search_popout.recent": "Ostatnie wyszukiwania",
   "search_results.accounts": "Profile",
   "search_results.all": "Wszystkie",
   "search_results.hashtags": "Hasztagi",
diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json
index 1c8bf8b04..d10c9a8f7 100644
--- a/app/javascript/mastodon/locales/pt-BR.json
+++ b/app/javascript/mastodon/locales/pt-BR.json
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "Spam",
   "report_notification.categories.violation": "Violação de regra",
   "report_notification.open": "Abrir denúncia",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Nenhuma busca recente",
   "search.placeholder": "Pesquisar",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Perfis correspondentes a {x}",
+  "search.quick_action.go_to_account": "Ir para a página do perfil {x}",
+  "search.quick_action.go_to_hashtag": "Ir para a hashtag {x}",
+  "search.quick_action.open_url": "Abrir link no Mastodon",
+  "search.quick_action.status_search": "Publicações correspondentes a {x}",
   "search.search_or_paste": "Buscar ou colar URL",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "Ações rápidas",
+  "search_popout.recent": "Buscas Recentes",
   "search_results.accounts": "Perfis",
   "search_results.all": "Tudo",
   "search_results.hashtags": "Hashtags",
diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json
index 496551a87..e93ff73cf 100644
--- a/app/javascript/mastodon/locales/pt-PT.json
+++ b/app/javascript/mastodon/locales/pt-PT.json
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "Spam",
   "report_notification.categories.violation": "Violação de regra",
   "report_notification.open": "Abrir denúncia",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Nenhuma pesquisa recente",
   "search.placeholder": "Pesquisar",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Perfis com correspondência a {x}",
+  "search.quick_action.go_to_account": "Ir para o perfil {x}",
+  "search.quick_action.go_to_hashtag": "Ir para a hashtag {x}",
+  "search.quick_action.open_url": "Abrir ligação no Mastodon",
+  "search.quick_action.status_search": "Publicações com correspondência a {x}",
   "search.search_or_paste": "Pesquisar ou introduzir URL",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "Ações rápidas",
+  "search_popout.recent": "Pesquisas recentes",
   "search_results.accounts": "Perfis",
   "search_results.all": "Tudo",
   "search_results.hashtags": "Etiquetas",
diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json
index c0064eb7e..93a00e51e 100644
--- a/app/javascript/mastodon/locales/sq.json
+++ b/app/javascript/mastodon/locales/sq.json
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "I padëshiruar",
   "report_notification.categories.violation": "Cenim rregullash",
   "report_notification.open": "Hape raportimin",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Pa kërkime së fundi",
   "search.placeholder": "Kërkoni",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Profile me përputhje me {x}",
+  "search.quick_action.go_to_account": "Kalo te profili {x}",
+  "search.quick_action.go_to_hashtag": "Kalo te hashtag-u {x}",
+  "search.quick_action.open_url": "Hape URL-në në Mastodon",
+  "search.quick_action.status_search": "Postime me përputhje me {x}",
   "search.search_or_paste": "Kërkoni, ose hidhni një URL",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "Veprime të shpejta",
+  "search_popout.recent": "Kërkime së fundi",
   "search_results.accounts": "Profile",
   "search_results.all": "Krejt",
   "search_results.hashtags": "Hashtag-ë",
diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json
index c460b5e1b..cd4c92351 100644
--- a/app/javascript/mastodon/locales/th.json
+++ b/app/javascript/mastodon/locales/th.json
@@ -522,17 +522,17 @@
   "report_notification.categories.spam": "สแปม",
   "report_notification.categories.violation": "การละเมิดกฎ",
   "report_notification.open": "รายงานที่เปิด",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "ไม่มีการค้นหาล่าสุด",
   "search.placeholder": "ค้นหา",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "โปรไฟล์ที่ตรงกับ {x}",
+  "search.quick_action.go_to_account": "ไปยังโปรไฟล์ {x}",
+  "search.quick_action.go_to_hashtag": "ไปยังแฮชแท็ก {x}",
+  "search.quick_action.open_url": "เปิด URL ใน Mastodon",
+  "search.quick_action.status_search": "โพสต์ที่ตรงกับ {x}",
   "search.search_or_paste": "ค้นหาหรือวาง URL",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
-  "search_results.accounts": "Profiles",
+  "search_popout.quick_actions": "การกระทำด่วน",
+  "search_popout.recent": "การค้นหาล่าสุด",
+  "search_results.accounts": "โปรไฟล์",
   "search_results.all": "ทั้งหมด",
   "search_results.hashtags": "แฮชแท็ก",
   "search_results.nothing_found": "ไม่พบสิ่งใดสำหรับคำค้นหาเหล่านี้",
diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json
index b3cbed024..a7b8cd916 100644
--- a/app/javascript/mastodon/locales/tr.json
+++ b/app/javascript/mastodon/locales/tr.json
@@ -72,8 +72,8 @@
   "admin.dashboard.retention.average": "Ortalama",
   "admin.dashboard.retention.cohort": "Kayıt ayı",
   "admin.dashboard.retention.cohort_size": "Yeni kullanıcılar",
-  "alert.rate_limited.message": "Lütfen {retry_time, time, medium} süresinden sonra tekrar deneyin.",
-  "alert.rate_limited.title": "Oran sınırlıdır",
+  "alert.rate_limited.message": "Lütfen {retry_time, time, medium} saatinden sonra tekrar deneyin.",
+  "alert.rate_limited.title": "Aşırı istek gönderildi",
   "alert.unexpected.message": "Beklenmedik bir hata oluştu.",
   "alert.unexpected.title": "Hay aksi!",
   "announcement.announcement": "Duyuru",
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "İstenmeyen",
   "report_notification.categories.violation": "Kural ihlali",
   "report_notification.open": "Bildirim aç",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Son arama yok",
   "search.placeholder": "Ara",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Eşleşen profiller {x}",
+  "search.quick_action.go_to_account": "Profile git {x}",
+  "search.quick_action.go_to_hashtag": "Etikete git {x}",
+  "search.quick_action.open_url": "URL'yi Mastodon'da Aç",
+  "search.quick_action.status_search": "Eşleşen gönderiler {x}",
   "search.search_or_paste": "Ara veya URL gir",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "Hızlı eylemler",
+  "search_popout.recent": "Son aramalar",
   "search_results.accounts": "Profiller",
   "search_results.all": "Tümü",
   "search_results.hashtags": "Etiketler",
diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json
index 9cbf8ad6b..5278f845f 100644
--- a/app/javascript/mastodon/locales/uk.json
+++ b/app/javascript/mastodon/locales/uk.json
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "Спам",
   "report_notification.categories.violation": "Порушення правил",
   "report_notification.open": "Відкрити скаргу",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Немає останніх пошуків",
   "search.placeholder": "Пошук",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Збіг профілів {x}",
+  "search.quick_action.go_to_account": "Перейти до профілю {x}",
+  "search.quick_action.go_to_hashtag": "Перейти до хештегу {x}",
+  "search.quick_action.open_url": "Відкрити URL-адресу в Mastodon",
+  "search.quick_action.status_search": "Збіг дописів {x}",
   "search.search_or_paste": "Введіть адресу або пошуковий запит",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "Швидкі дії",
+  "search_popout.recent": "Нещодавні запити",
   "search_results.accounts": "Профілі",
   "search_results.all": "Усі",
   "search_results.hashtags": "Хештеґи",
diff --git a/app/javascript/mastodon/locales/vi.json b/app/javascript/mastodon/locales/vi.json
index 7096268ea..7d51c7055 100644
--- a/app/javascript/mastodon/locales/vi.json
+++ b/app/javascript/mastodon/locales/vi.json
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "Spam",
   "report_notification.categories.violation": "Vi phạm nội quy",
   "report_notification.open": "Mở báo cáo",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "Không có tìm kiếm gần đây",
   "search.placeholder": "Tìm kiếm",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "Người trùng khớp {x}",
+  "search.quick_action.go_to_account": "Xem trang {x}",
+  "search.quick_action.go_to_hashtag": "Xem hashtag {x}",
+  "search.quick_action.open_url": "Mở liên kết trong Mastodon",
+  "search.quick_action.status_search": "Tút trùng khớp {x}",
   "search.search_or_paste": "Tìm kiếm hoặc nhập URL",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "Thao tác nhanh",
+  "search_popout.recent": "Tìm kiếm gần đây",
   "search_results.accounts": "Mọi người",
   "search_results.all": "Toàn bộ",
   "search_results.hashtags": "Hashtags",
diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json
index 3b6aa203f..f9e31c450 100644
--- a/app/javascript/mastodon/locales/zh-CN.json
+++ b/app/javascript/mastodon/locales/zh-CN.json
@@ -37,7 +37,7 @@
   "account.following_counter": "正在关注 {counter} 人",
   "account.follows.empty": "此用户目前尚未关注任何人。",
   "account.follows_you": "关注了你",
-  "account.go_to_profile": "转到个人资料界面",
+  "account.go_to_profile": "转到个人资料页",
   "account.hide_reblogs": "隐藏来自 @{name} 的转贴",
   "account.joined_short": "加入于",
   "account.languages": "更改订阅语言",
@@ -53,7 +53,7 @@
   "account.posts": "嘟文",
   "account.posts_with_replies": "嘟文和回复",
   "account.report": "举报 @{name}",
-  "account.requested": "正在等待对方同意。点击以取消发送关注请求",
+  "account.requested": "正在等待对方同意。点击取消发送关注请求",
   "account.requested_follow": "{name} 已经向你发送了关注请求",
   "account.share": "分享 @{name} 的个人资料页",
   "account.show_reblogs": "显示来自 @{name} 的转嘟",
@@ -202,7 +202,7 @@
   "emoji_button.food": "食物和饮料",
   "emoji_button.label": "插入表情符号",
   "emoji_button.nature": "自然",
-  "emoji_button.not_found": "木有这个表情符号!(╯°□°)╯︵ ┻━┻",
+  "emoji_button.not_found": "未找到匹配的表情符号",
   "emoji_button.objects": "物体",
   "emoji_button.people": "人物",
   "emoji_button.recent": "常用",
@@ -246,18 +246,18 @@
   "explore.trending_tags": "话题标签",
   "filter_modal.added.context_mismatch_explanation": "此过滤器分类不适用访问过嘟文的环境中。如果你想要在环境中过滤嘟文,你必须编辑此过滤器。",
   "filter_modal.added.context_mismatch_title": "环境不匹配!",
-  "filter_modal.added.expired_explanation": "此过滤器分类已过期,你需要修改到期日期才能应用。",
+  "filter_modal.added.expired_explanation": "此过滤器类别已过期,你需要修改到期日期才能应用。",
   "filter_modal.added.expired_title": "过滤器已过期!",
   "filter_modal.added.review_and_configure": "要审核并进一步配置此过滤器分类,请前往{settings_link}。",
   "filter_modal.added.review_and_configure_title": "过滤器设置",
   "filter_modal.added.settings_link": "设置页面",
-  "filter_modal.added.short_explanation": "此嘟文已添加到以下过滤器分类:{title}。",
+  "filter_modal.added.short_explanation": "此嘟文已添加到以下过滤器类别:{title}。",
   "filter_modal.added.title": "过滤器已添加 !",
-  "filter_modal.select_filter.context_mismatch": "不适用于此环境",
+  "filter_modal.select_filter.context_mismatch": "不适用于这个情境",
   "filter_modal.select_filter.expired": "已过期",
-  "filter_modal.select_filter.prompt_new": "新分类:{name}",
+  "filter_modal.select_filter.prompt_new": "新类别:{name}",
   "filter_modal.select_filter.search": "搜索或创建",
-  "filter_modal.select_filter.subtitle": "使用一个已存在分类,或创建一个新分类",
+  "filter_modal.select_filter.subtitle": "使用一个已存在分类,或创建一个新类别",
   "filter_modal.select_filter.title": "过滤此嘟文",
   "filter_modal.title.status": "过滤一条嘟文",
   "follow_recommendations.done": "完成",
@@ -269,7 +269,7 @@
   "followed_tags": "关注的话题标签",
   "footer.about": "关于",
   "footer.directory": "用户目录",
-  "footer.get_app": "获取应用程序",
+  "footer.get_app": "获取应用",
   "footer.invite": "邀请",
   "footer.keyboard_shortcuts": "快捷键列表",
   "footer.privacy_policy": "隐私政策",
@@ -363,8 +363,8 @@
   "lists.search": "搜索你关注的人",
   "lists.subheading": "你的列表",
   "load_pending": "{count} 项",
-  "loading_indicator.label": "加载中……",
-  "media_gallery.toggle_visible": "隐藏图片",
+  "loading_indicator.label": "加载中…",
+  "media_gallery.toggle_visible": "{number, plural, other {隐藏图像}}",
   "missing_indicator.label": "找不到内容",
   "missing_indicator.sublabel": "无法找到此资源",
   "moved_to_account_banner.text": "您的账号 {disabledAccount} 已停用,因为您已迁移到 {movedToAccount} 。",
@@ -387,7 +387,7 @@
   "navigation_bar.followed_tags": "关注的话题标签",
   "navigation_bar.follows_and_followers": "关注管理",
   "navigation_bar.lists": "列表",
-  "navigation_bar.logout": "登出",
+  "navigation_bar.logout": "退出登录",
   "navigation_bar.mutes": "已隐藏的用户",
   "navigation_bar.personal": "个人",
   "navigation_bar.pins": "置顶嘟文",
@@ -503,7 +503,7 @@
   "report.reasons.other_description": "该问题不符合其他类别",
   "report.reasons.spam": "它是垃圾信息",
   "report.reasons.spam_description": "恶意链接,虚假互动和重复回复",
-  "report.reasons.violation": "它违反了服务器规则",
+  "report.reasons.violation": "违反服务器规则",
   "report.reasons.violation_description": "你清楚它违反了特定的规则",
   "report.rules.subtitle": "选择所有适用选项",
   "report.rules.title": "哪些规则被违反了?",
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "骚扰",
   "report_notification.categories.violation": "违反规则",
   "report_notification.open": "打开举报",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "无最近搜索",
   "search.placeholder": "搜索",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "匹配 {x} 的个人资料",
+  "search.quick_action.go_to_account": "转到 {x} 个人资料",
+  "search.quick_action.go_to_hashtag": "转到标签 {x}",
+  "search.quick_action.open_url": "在 Mastodon 中打开链接",
+  "search.quick_action.status_search": "匹配 {x} 的帖子",
   "search.search_or_paste": "搜索或输入链接",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "快捷操作",
+  "search_popout.recent": "最近搜索",
   "search_results.accounts": "个人资料",
   "search_results.all": "全部",
   "search_results.hashtags": "话题标签",
diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json
index 5245c59d8..55f709340 100644
--- a/app/javascript/mastodon/locales/zh-TW.json
+++ b/app/javascript/mastodon/locales/zh-TW.json
@@ -522,16 +522,16 @@
   "report_notification.categories.spam": "垃圾訊息",
   "report_notification.categories.violation": "違反規則",
   "report_notification.open": "開啟檢舉報告",
-  "search.no_recent_searches": "No recent searches",
+  "search.no_recent_searches": "尚無最近的搜尋紀錄",
   "search.placeholder": "搜尋",
-  "search.quick_action.account_search": "Profiles matching {x}",
-  "search.quick_action.go_to_account": "Go to profile {x}",
-  "search.quick_action.go_to_hashtag": "Go to hashtag {x}",
-  "search.quick_action.open_url": "Open URL in Mastodon",
-  "search.quick_action.status_search": "Posts matching {x}",
+  "search.quick_action.account_search": "符合的個人檔案 {x}",
+  "search.quick_action.go_to_account": "前往個人檔案 {x}",
+  "search.quick_action.go_to_hashtag": "前往主題標籤 {x}",
+  "search.quick_action.open_url": "於 Mastodon 中開啟連結",
+  "search.quick_action.status_search": "符合的嘟文 {x}",
   "search.search_or_paste": "搜尋或輸入網址",
-  "search_popout.quick_actions": "Quick actions",
-  "search_popout.recent": "Recent searches",
+  "search_popout.quick_actions": "快捷操作",
+  "search_popout.recent": "最近的搜尋紀錄",
   "search_results.accounts": "個人檔案",
   "search_results.all": "全部",
   "search_results.hashtags": "主題標籤",
diff --git a/app/javascript/packs/public.jsx b/app/javascript/packs/public.jsx
index 8017734d5..ad6bf237f 100644
--- a/app/javascript/packs/public.jsx
+++ b/app/javascript/packs/public.jsx
@@ -100,11 +100,12 @@ function main() {
       const datetime = new Date(content.getAttribute('datetime'));
       const now      = new Date();
 
-      content.title = dateTimeFormat.format(datetime);
+      const timeGiven = content.getAttribute('datetime').includes('T');
+      content.title = timeGiven ? dateTimeFormat.format(datetime) : dateFormat.format(datetime);
       content.textContent = timeAgoString({
         formatMessage: ({ id, defaultMessage }, values) => (new IntlMessageFormat(messages[id] || defaultMessage, locale)).format(values),
         formatDate: (date, options) => (new Intl.DateTimeFormat(locale, options)).format(date),
-      }, datetime, now, now.getFullYear(), content.getAttribute('datetime').includes('T'));
+      }, datetime, now, now.getFullYear(), timeGiven);
     });
 
     const reactComponents = document.querySelectorAll('[data-component]');
@@ -188,10 +189,10 @@ function main() {
 
     if (sidebar.classList.contains('visible')) {
       document.body.style.overflow = null;
-      toggleButton.setAttribute('aria-expanded', false);
+      toggleButton.setAttribute('aria-expanded', 'false');
     } else {
       document.body.style.overflow = 'hidden';
-      toggleButton.setAttribute('aria-expanded', true);
+      toggleButton.setAttribute('aria-expanded', 'true');
     }
 
     toggleButton.classList.toggle('active');
diff --git a/app/javascript/styles/mastodon/accounts.scss b/app/javascript/styles/mastodon/accounts.scss
index af0d8b5ed..853d7f70d 100644
--- a/app/javascript/styles/mastodon/accounts.scss
+++ b/app/javascript/styles/mastodon/accounts.scss
@@ -36,10 +36,6 @@
     @media screen and (max-width: 600px) {
       height: 200px;
     }
-
-    @media screen and (max-width: $no-gap-breakpoint) {
-      display: none;
-    }
   }
 
   &__bar {
@@ -138,7 +134,7 @@
   }
 
   .older {
-    float: inline-start;
+    float: left;
     padding-inline-start: 0;
 
     .fa {
@@ -148,7 +144,7 @@
   }
 
   .newer {
-    float: inline-end;
+    float: right;
     padding-inline-end: 0;
 
     .fa {
diff --git a/app/javascript/styles/mastodon/admin.scss b/app/javascript/styles/mastodon/admin.scss
index 1c74de256..acb4baf4f 100644
--- a/app/javascript/styles/mastodon/admin.scss
+++ b/app/javascript/styles/mastodon/admin.scss
@@ -651,7 +651,7 @@ body,
     .button {
       overflow: visible;
       margin: 0 0 5px 5px;
-      float: inline-end;
+      float: right;
     }
   }
 }
@@ -799,7 +799,7 @@ a.name-tag,
 
 .speech-bubble {
   margin-bottom: 20px;
-  border-inset-inline-start: 4px solid $ui-highlight-color;
+  border-inline-start: 4px solid $ui-highlight-color;
 
   &.positive {
     border-left-color: $success-green;
@@ -1678,7 +1678,7 @@ a.sparkline {
 }
 
 .section-skip-link {
-  float: inline-end;
+  float: right;
 
   a {
     color: $ui-highlight-color;
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index fb6cb4a39..862252781 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -826,7 +826,7 @@ body > [data-popper-placement] {
 }
 
 .reply-indicator__cancel {
-  float: inline-end;
+  float: right;
   line-height: 24px;
 }
 
@@ -841,7 +841,7 @@ body > [data-popper-placement] {
 }
 
 .reply-indicator__display-avatar {
-  float: inline-start;
+  float: left;
   margin-inline-end: 5px;
 }
 
@@ -1159,7 +1159,7 @@ body > [data-popper-placement] {
 
 .notification__relative_time {
   color: $dark-text-color;
-  float: inline-end;
+  float: right;
   font-size: 14px;
   padding-bottom: 1px;
 }
@@ -1507,7 +1507,7 @@ body > [data-popper-placement] {
     position: relative;
 
     & > div {
-      float: inline-start;
+      float: left;
       position: relative;
       box-sizing: border-box;
     }
@@ -1622,7 +1622,7 @@ a .account__avatar {
   text-decoration: none;
   overflow: hidden;
   flex: 0 1 100%;
-  border-inset-inline-end: 1px solid lighten($ui-base-color, 8%);
+  border-inline-end: 1px solid lighten($ui-base-color, 8%);
   padding: 10px 0;
   border-bottom: 4px solid transparent;
 
@@ -1662,7 +1662,7 @@ a .account__avatar {
 }
 
 .account-authorize__avatar {
-  float: inline-start;
+  float: left;
   margin-inline-end: 10px;
 }
 
@@ -2642,7 +2642,7 @@ $ui-header-height: 55px;
     .navigation-panel {
       margin: 0;
       background: $ui-base-color;
-      border-inset-inline-start: 1px solid lighten($ui-base-color, 8%);
+      border-inline-start: 1px solid lighten($ui-base-color, 8%);
       height: 100vh;
     }
 
@@ -2941,7 +2941,6 @@ $ui-header-height: 55px;
     width: 85%;
     height: 100%;
     pointer-events: none;
-    user-drag: none;
     user-select: none;
   }
 
@@ -3879,7 +3878,7 @@ a.status-card.compact:hover {
 }
 
 .column-header__setting-arrows {
-  float: inline-end;
+  float: right;
 
   .column-header__setting-btn {
     padding: 5px;
@@ -4340,6 +4339,7 @@ a.status-card.compact:hover {
 .follow_requests-unlocked_explanation {
   background: darken($ui-base-color, 4%);
   contain: initial;
+  flex-grow: 0;
 }
 
 .error-column {
@@ -5753,7 +5753,7 @@ a.status-card.compact:hover {
 
 .report-modal__comment {
   padding: 20px;
-  border-inset-inline-end: 1px solid $ui-secondary-color;
+  border-inline-end: 1px solid $ui-secondary-color;
   max-width: 320px;
 
   p {
@@ -6044,7 +6044,7 @@ a.status-card.compact:hover {
     color: $dark-text-color;
     padding: 8px 18px;
     cursor: default;
-    border-inset-inline-end: 1px solid lighten($ui-base-color, 8%);
+    border-inline-end: 1px solid lighten($ui-base-color, 8%);
     display: flex;
     flex-direction: column;
     align-items: center;
@@ -6109,7 +6109,7 @@ a.status-card.compact:hover {
   border: 0;
   box-sizing: border-box;
   display: block;
-  float: inline-start;
+  float: left;
   position: relative;
   border-radius: 4px;
   overflow: hidden;
@@ -7930,7 +7930,7 @@ noscript {
       inset-inline-start: 0;
       width: 100%;
       height: 100%;
-      border-inset-inline-start: 4px solid $highlight-text-color;
+      border-inline-start: 4px solid $highlight-text-color;
       pointer-events: none;
     }
   }
diff --git a/app/javascript/styles/mastodon/rich_text.scss b/app/javascript/styles/mastodon/rich_text.scss
index aa41e4ad3..c77c23bc4 100644
--- a/app/javascript/styles/mastodon/rich_text.scss
+++ b/app/javascript/styles/mastodon/rich_text.scss
@@ -14,7 +14,7 @@
 
   blockquote {
     padding-inline-start: 10px;
-    border-inset-inline-start: 3px solid $darker-text-color;
+    border-inline-start: 3px solid $darker-text-color;
     color: $darker-text-color;
     white-space: normal;
 
diff --git a/app/javascript/styles/mastodon/rtl.scss b/app/javascript/styles/mastodon/rtl.scss
index 726135c58..8d3d32665 100644
--- a/app/javascript/styles/mastodon/rtl.scss
+++ b/app/javascript/styles/mastodon/rtl.scss
@@ -19,10 +19,22 @@ body.rtl {
     direction: rtl;
   }
 
+  .account__avatar-wrapper {
+    float: right;
+  }
+
+  .column-header__setting-arrows {
+    float: left;
+  }
+
   .admin-wrapper {
     direction: rtl;
   }
 
+  .react-swipeable-view-container > * {
+    direction: rtl;
+  }
+
   .simple_form .label_input__append {
     &::after {
       background-image: linear-gradient(
diff --git a/app/javascript/styles/mastodon/tables.scss b/app/javascript/styles/mastodon/tables.scss
index fb1ff0781..49e5bbf9f 100644
--- a/app/javascript/styles/mastodon/tables.scss
+++ b/app/javascript/styles/mastodon/tables.scss
@@ -91,12 +91,12 @@
 
       &:first-child {
         border-radius: 4px 0 0;
-        border-inset-inline-start: 1px solid darken($ui-base-color, 8%);
+        border-inline-start: 1px solid darken($ui-base-color, 8%);
       }
 
       &:last-child {
         border-radius: 0 4px 0 0;
-        border-inset-inline-end: 1px solid darken($ui-base-color, 8%);
+        border-inline-end: 1px solid darken($ui-base-color, 8%);
       }
     }
   }
diff --git a/app/services/notify_service.rb b/app/services/notify_service.rb
index 994ca588a..069f370cf 100644
--- a/app/services/notify_service.rb
+++ b/app/services/notify_service.rb
@@ -6,6 +6,7 @@ class NotifyService < BaseService
   NON_EMAIL_TYPES = %i(
     admin.report
     admin.sign_up
+    update
   ).freeze
 
   def call(recipient, type, activity)
diff --git a/config/locales/cs.yml b/config/locales/cs.yml
index f54624a80..9e7ecb6ed 100644
--- a/config/locales/cs.yml
+++ b/config/locales/cs.yml
@@ -649,6 +649,8 @@ cs:
       statuses: Nahlášený obsah
       statuses_description_html: Obsah porušující pravidla bude uveden v komunikaci s nahlášeným účtem
       summary:
+        actions:
+          delete_html: Odstranit urážlivé příspěvky
         close_report: Označit nahlášení č.%{id} za vyřešené
       target_origin: Původ nahlášeného účtu
       title: Hlášení
@@ -1475,6 +1477,7 @@ cs:
       electron: Electron
       firefox: Firefox
       generic: Neznámý prohlížeč
+      huawei_browser: Prohlížeč Huawei
       ie: Internet Explorer
       micro_messenger: MicroMessenger
       nokia: Nokia S40 Ovi Browser
diff --git a/config/locales/devise.my.yml b/config/locales/devise.my.yml
index fd000223a..04d744cf2 100644
--- a/config/locales/devise.my.yml
+++ b/config/locales/devise.my.yml
@@ -110,3 +110,5 @@ my:
       expired: သည် သက်တမ်းကျော်လွန်သွားပြီ။ ကျေးဇူးပြု၍အသစ်တစ်ခု တောင်းဆိုပါ
       not_found: ရှာမတွေ့ပါ
       not_locked: လော့ခ် မချထားပါ
+      not_saved:
+        other: "%{count} အမှားသည် ဤ %{resource} အား သိမ်းဆည်းခြင်းမှ တားမြစ်ထားသည်-"
diff --git a/config/locales/devise.zh-CN.yml b/config/locales/devise.zh-CN.yml
index 4a47dddec..d21c0c7f1 100644
--- a/config/locales/devise.zh-CN.yml
+++ b/config/locales/devise.zh-CN.yml
@@ -96,9 +96,9 @@ zh-CN:
       update_needs_confirmation: 账号信息更新成功,但我们需要验证你的新电子邮件地址,请点击邮件中的链接以确认。如果没有收到邮件,请检查你的垃圾邮箱。
       updated: 账户资料更新成功。
     sessions:
-      already_signed_out: 已成功登出。
+      already_signed_out: 已成功退出登录。
       signed_in: 已成功登录。
-      signed_out: 已成功登出。
+      signed_out: 已成功退出登录。
     unlocks:
       send_instructions: 几分钟后,你将收到一封解锁账户的邮件。如果没有,请检查你的垃圾邮箱。
       send_paranoid_instructions: 如果你的账号存在,你将会在几分钟内收到一封指引你如何解锁账号的邮件。如果你没有收到这封邮件,请检查你邮箱的垃圾箱。
diff --git a/config/locales/doorkeeper.my.yml b/config/locales/doorkeeper.my.yml
index 8a92d7e79..241dcb691 100644
--- a/config/locales/doorkeeper.my.yml
+++ b/config/locales/doorkeeper.my.yml
@@ -83,6 +83,7 @@ my:
         access_denied: မူလပိုင်ရှင် သို့မဟုတ် ခွင့်ပြုချက်ရှိသောဆာဗာမှ တောင်းဆိုချက်ကို ငြင်းပယ်ခဲ့သည်။
         credential_flow_not_configured: Doorkeeper.configure.resource_owner_from_credentials ကို သတ်မှတ်မထားသည့်အတွက် မူလပိုင်ရှင် စကားဝှက် အထောက်အထားများထည့်သွင်းခြင်းမှာ မအောင်မြင်တော့ပါ။
         invalid_client: Client အထောက်အထားစိစစ်မှု မအောင်မြင်ခြင်းမှာ အမည်မသိ Client ဖြစ်ခြင်း၊ Client စစ်မှန်ကြောင်းအထောက်အထားမပါဝင်ခြင်း သို့မဟုတ် ပံ့ပိုးမထားသည့် အထောက်အထားဖြစ်နေခြင်းကြောင့် ဖြစ်ပါသည်။
+        invalid_grant: ပံ့ပိုးပေးထားသည့် ခွင့်ပြုချက်ပေးသည် မမှန်ကန်ပါ၊ သက်တမ်းကုန်၊ ရုပ်သိမ်းလိုက်သည်၊ ခွင့်ပြုချက်တောင်းခံမှုတွင် အသုံးပြုထားသော ပြန်ညွှန်း URI နှင့် မကိုက်ညီပါ သို့မဟုတ် အခြားအသုံးပြုသူထံသို့ ထုတ်ပေးထားသည်။
         invalid_redirect_uri: ပြန်ညွှန်းထားခြင်းတွင် ပါဝင်သော URI မှာ မမှန်ကန်ပါ။
         invalid_request:
           missing_param: ပျောက်နေသည့် လိုအပ်သောအရာ - %{value}။
@@ -190,4 +191,5 @@ my:
       write:media: မီဒီယာဖိုင်များကို အင်တာနက်ပေါ်တင်ပါ
       write:mutes: လူများနှင့် စကားဝိုင်းများကို ပိတ်ထားပါ
       write:notifications: သင့်အအသိပေးချက်များကို ရှင်းလင်းပါ
+      write:reports: အခြားလူများကို သတင်းပို့မည်
       write:statuses: ပို့စ်များအား ရအောင်ပို့ခြင်း
diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml
index 3345f4b71..db4f83b93 100644
--- a/config/locales/en-GB.yml
+++ b/config/locales/en-GB.yml
@@ -691,8 +691,37 @@ en-GB:
         manage_invites_description: Allows users to browse and deactivate invite links
         manage_reports: Manage Reports
         manage_reports_description: Allows users to review reports and perform moderation actions against them
+        manage_roles: Manage Roles
+        manage_roles_description: Allows users to manage and assign roles below theirs
+        manage_rules: Manage Rules
+        manage_rules_description: Allows users to change server rules
+        manage_settings: Manage Settings
+        manage_settings_description: Allows users to change site settings
+        manage_taxonomies: Manage Taxonomies
+        manage_taxonomies_description: Allows users to review trending content and update hashtag settings
+        manage_user_access: Manage User Access
+        manage_user_access_description: Allows users to disable other users' two-factor authentication, change their e-mail address, and reset their password
+        manage_users: Manage Users
+        manage_users_description: Allows users to view other users' details and perform moderation actions against them
+        manage_webhooks: Manage Webhooks
+        manage_webhooks_description: Allows users to set up webhooks for administrative events
+        view_audit_log: View Audit Log
+        view_audit_log_description: Allows users to see a history of administrative actions on the server
+        view_dashboard: View Dashboard
+        view_dashboard_description: Allows users to access the dashboard and various metrics
         view_devops: DevOps
+        view_devops_description: Allows users to access Sidekiq and pgHero dashboards
+      title: Roles
+    rules:
+      add_new: Add rule
+      delete: Delete
+      description_html: While most claim to have read and agree to the terms of service, usually people do not read through until after a problem arises. <strong>Make it easier to see your server's rules at a glance by providing them in a flat bullet point list.</strong> Try to keep individual rules short and simple, but try not to split them up into many separate items either.
+      edit: Edit rule
+      empty: No server rules have been defined yet.
+      title: Server rules
     settings:
+      about:
+        manage_rules: Manage server rules
       registrations:
         title: Registrations
       registrations_mode:
@@ -716,7 +745,39 @@ en-GB:
       favourites: Favourites
       history: Version history
       in_reply_to: Replying to
+    trends:
+      tags:
+        listable: Can be suggested
+        no_tag_selected: No tags were changed as none were selected
+        not_listable: Won't be suggested
+        not_trendable: Won't appear under trends
+        not_usable: Cannot be used
+        peaked_on_and_decaying: Peaked on %{date}, now decaying
+        title: Trending hashtags
+        trendable: Can appear under trends
+        trending_rank: 'Trending #%{rank}'
+        usable: Can be used
+        usage_comparison: Used %{today} times today, compared to %{yesterday} yesterday
+        used_by_over_week:
+          one: Used by one person over the last week
+          other: Used by %{count} people over the last week
+      title: Trends
+      trending: Trending
+    warning_presets:
+      add_new: Add new
+      delete: Delete
+      edit_preset: Edit warning preset
+      empty: You haven't defined any warning presets yet.
+      title: Manage warning presets
     webhooks:
+      add_new: Add endpoint
+      delete: Delete
+      description_html: A <strong>webhook</strong> enables Mastodon to push <strong>real-time notifications</strong> about chosen events to your own application, so your application can <strong>automatically trigger reactions</strong>.
+      disable: Disable
+      disabled: Disabled
+      edit: Edit endpoint
+      empty: You don't have any webhook endpoints configured yet.
+      enable: Enable
       enabled: Active
       enabled_events:
         one: 1 enabled event
@@ -758,7 +819,30 @@ en-GB:
         no_approved_tags: There are currently no approved trending hashtags.
         requirements: 'Any of these candidates could surpass the #%{rank} approved trending hashtag, which is currently #%{lowest_tag_name} with a score of %{lowest_tag_score}.'
         title: Trending hashtags
+      subject: New trends up for review on %{instance}
+  aliases:
+    add_new: Create alias
+    created_msg: Successfully created a new alias. You can now initiate the move from the old account.
+    deleted_msg: Successfully removed the alias. Moving from that account to this one will no longer be possible.
+    empty: You have no aliases.
+    hint_html: If you want to move from another account to this one, here you can create an alias, which is required before you can proceed with moving followers from the old account to this one. This action by itself is <strong>harmless and reversible</strong>. <strong>The account migration is initiated from the old account</strong>.
+    remove: Unlink alias
+  appearance:
+    advanced_web_interface: Advanced web interface
+    advanced_web_interface_hint: 'If you want to make use of your entire screen width, the advanced web interface allows you to configure many different columns to see as much information at the same time as you want: Home, notifications, federated timeline, any number of lists and hashtags.'
+    animations_and_accessibility: Animations and accessibility
+    confirmation_dialogs: Confirmation dialogues
+    discovery: Discovery
+    localization:
+      body: Mastodon is translated by volunteers.
+      guide_link: https://crowdin.com/project/mastodon
+      guide_link_text: Everyone can contribute.
+    sensitive_content: Sensitive content
+    toot_layout: Post layout
   application_mailer:
+    notification_preferences: Change e-mail preferences
+    salutation: "%{name},"
+    settings: 'Change e-mail preferences: %{link}'
     view: 'View:'
     view_profile: View profile
     view_status: View post
diff --git a/config/locales/eo.yml b/config/locales/eo.yml
index b45692664..b381805a1 100644
--- a/config/locales/eo.yml
+++ b/config/locales/eo.yml
@@ -1691,6 +1691,7 @@ eo:
     seamless_external_login: Vi estas ensalutinta per ekstera servo, do pasvortaj kaj retadresaj agordoj ne estas disponeblaj.
     signed_in_as: 'Salutinta kiel:'
   verification:
+    explanation_html: 'Vi povas <strong>pruvi, ke vi estas la posedanto de la ligiloj en viaj profilaj metadatumoj</strong>. Por fari tion, la alligita retejo devas enhavi ligilon reen al via Mastodon-profilo. La religilo <strong>devas</strong> havi la atributon <code>rel="me"</code>. Ne gravas la teksta enhavo de la religilo. Jen ekzemplo:'
     verification: Kontrolo
   webauthn_credentials:
     add: Aldoni novan sekurecan ŝlosilon
diff --git a/config/locales/my.yml b/config/locales/my.yml
index b63093c41..816c5c401 100644
--- a/config/locales/my.yml
+++ b/config/locales/my.yml
@@ -11,6 +11,7 @@ my:
     followers:
       other: စောင့်ကြည့်သူ
     following: စောင့်ကြည့်နေသည်
+    instance_actor_flash: ဤအကောင့်သည် ဆာဗာကိုယ်တိုင်ကို ကိုယ်စားပြုပြီး မည်သည့်အသုံးပြုသူမျှမဟုတ်ဘဲ အတုအယောင်သရုပ်ဆောင်တစ်ခုဖြစ်သည်။ ၎င်းကို Federation ရည်ရွယ်ချက်များအတွက် အသုံးပြုပြီး ဆိုင်းငံ့မထားသင့်ပါ။
     last_active: နောက်ဆုံးအသုံးပြုခဲ့သည့်အချိန်
     link_verified_on: ဤလင့်ခ်၏ ပိုင်ဆိုင်မှုကို %{date} တွင် စစ်ဆေးခဲ့သည်
     nothing_here: ဤနေရာတွင် မည်သည့်အရာမျှမရှိပါ။
@@ -136,6 +137,7 @@ my:
       security_measures:
         only_password: စကားဝှက်ဖြင့်သာ
         password_and_2fa: စကားဝှက်နှင့် 2FA
+      sensitive: သတိပြုရန်
       sensitized: သတိထားရသည်ဟု အမှတ်အသားပြုထားပါ
       shared_inbox_url: inbox URL ကို မျှဝေခဲ့သည်
       show:
@@ -154,7 +156,9 @@ my:
       unblock_email: အီးမေးလ်ကိုပြန်ဖွင့်မည်
       unblocked_email_msg: " %{username} အီးမေးလ်ကိုပြန်ဖွင့်လိုက်ပါပြီ"
       unconfirmed_email: အတည်မပြုရသေးသော အီးမေးလ်
+      undo_sensitized: သတိပြုရန်အား ပြန်ဖြုတ်ရန်
       undo_silenced: ကန့်သတ်ချက်မလုပ်တော့ပါ
+      undo_suspension: ပိတ်ခြင်းကိုပြန်ဖွင့်မည်
       unsilenced_msg: "%{username} ၏ အကောင့်၏ ကန့်သတ်ချက်ကို အောင်မြင်စွာ ပယ်ဖျက်ခဲ့သည်။"
       unsubscribe: စာရင်းမှထွက်ရန်
       unsuspended_msg: "%{username} ၏ အကောင့်ကို ရပ်ဆိုင်းလိုက်ပါပြီ"
@@ -447,6 +451,8 @@ my:
       unsuppress: အကြံပြုချက်စောင့်ကြည့်ခြင်းအား ပြန်လည်ရယူပါ
     instances:
       availability:
+        description_html:
+          other: ဒိုမိန်းသို့ ပေးပို့ခြင်း မအောင်မြင်ဘဲ <strong>%{count} ရက်</strong> မအောင်မြင်ပါက၊ ဒိုမိန်းထံပေးပို့ခြင်း <em>မှ</em> မရရှိပါက နောက်ထပ်ပေးပို့ရန် ကြိုးပမ်းမှုများ ပြုလုပ်မည်မဟုတ်ပါ။
         failure_threshold_reached: "%{date} နေ့ တွင် မအောင်မြင်ခဲ့ပါ။"
         failures_recorded:
           other: "%{count} ရက်နေ့တွင် ကြိုးစားမှု မအောင်မြင်ပါ။"
@@ -536,6 +542,7 @@ my:
     relays:
       add_new: relay အသစ်ထည့်ပါ
       delete: ဖျက်ပါ
+      description_html: စာရင်းသွင်းပြီး ထုတ်ဝေသည့် ဆာဗာများအကြား အများသူငှာ ပို့စ်များ အများအပြားကို ဖလှယ်ပေးသည့် ကြားခံဆာဗာတစ်ခုဖြစ်သည်။ <strong>၎င်းသည် အသေးစားနှင့် အလတ်စား ဆာဗာများမှ အကြောင်းအရာများကို ရှာဖွေတွေ့ရှိရန် ကူညီပေးနိုင်သည်</strong>၊ ၎င်းသည် ဒေသဆိုင်ရာအသုံးပြုသူများသည် အဝေးထိန်းဆာဗာများပေါ်တွင် အခြားလူများကို ကိုယ်တိုင်လိုက်လျှောက်ရန် လိုအပ်မည်ဖြစ်သည်။
       disable: ပိတ်ပါ
       disabled: ပိတ်ထားသည်
       enable: ဖွင့်ပါ
@@ -558,6 +565,7 @@ my:
       action_log: မှတ်တမ်းများစစ်ဆေးခြင်း
       action_taken_by: ဆောင်ရွက်ခဲ့ပါသည်
       actions:
+        delete_description_html: အစီရင်ခံထားသော ပို့စ်များကို ဖျက်လိုက်မည်ဖြစ်ပြီး အကောင့်တစ်ခုတည်းမှ နောင်လာမည့် ချိုးဖောက်မှုများအပေါ် အရှိန်မြှင့်ကူညီရန် သတိပေးချက်တစ်ခု မှတ်တမ်းတင်ပါမည်။
         mark_as_sensitive_description_html: တိုင်ကြားထားသည့်ပို့စ်များရှိ မီဒီယာအား သတိထားရသောမီဒီယာအဖြစ် သတ်မှတ်ပြီး အကောင့်တူဖြင့် နောင် ချိုးဖောက်မှုများရှိပါက သတိပေးချက်တစ်ခုဖြင့် သင့်အတွက် မှတ်တမ်းပြုလုပ်ပေးထားပါမည်။
         other_description_html: အကောင့်ထိန်းချုပ်ရန်နှင့် တိုင်ကြားထားသည့်သို့ ဆက်သွယ်မှုကို စိတ်ကြိုက်ပြင်ဆင်ရန်တို့အတွက် နောက်ထပ်ရွေးချယ်စရာများကို ကြည့်ပါ။
         resolve_description_html: တိုင်ကြားထားသည့်အကောင့်ကို အရေးယူမည်မဟုတ်ပါ၊ လုပ်ဆောင်ချက်ကို မှတ်တမ်းတင်ထားခြင်းမရှိသည့်အပြင် တိုင်ကြားထားမှုကိုလည်း ရုပ်သိမ်းပါမည်။
@@ -572,6 +580,7 @@ my:
       by_target_domain: တိုင်ကြားထားသော အကောင့်၏ ဒိုမိန်း
       cancel: ပယ်ဖျက်မည်
       category: အမျိုးအစား
+      category_description_html: ဤအကောင့်နှင့်/သို့မဟုတ် အကြောင်းအရာကို အစီရင်ခံထားသည့် အကြောင်းရင်းကို အစီရင်ခံထားသည့်အကောင့်နှင့် ဆက်သွယ်မှုတွင် ကိုးကားပါမည်။
       comment:
         none: တစ်ခုမျှမရှိ
       comment_description_html: "%{name} က နောက်ထပ်အချက်အလက်များ ပံ့ပိုးပေးနိုင်ရန်အတွက် ရေးသားခဲ့သည် -"
@@ -605,6 +614,7 @@ my:
       skip_to_actions: လုပ်ဆောင်ချက်များသို့ ကျော်သွားရန်
       status: အခြေအနေ
       statuses: တိုင်ကြားထားသောအကြောင်းအရာ
+      statuses_description_html: စိတ်အ​နှောင့်အယှက်ဖြစ်​စေ​သောအကြောင်းအရာများကို အစီရင်ခံထားသောအကောင့်နှင့် ဆက်သွယ်ပြီး အ​ရေးယူ​ဆောင်ရွက်ပါမည်
       summary:
         action_preambles:
           delete_html: သင်သည် <strong>@%{acct}</strong> ၏ ပို့စ်အချို့ကို <strong>ဖယ်ရှား</strong> တော့မည်ဖြစ်သည်။ ၎င်းတို့မှာ -
@@ -711,6 +721,7 @@ my:
         profile_directory: ပရိုဖိုင်လမ်းညွှန်
         public_timelines: အများမြင်စာမျက်နှာ
         publish_discovered_servers: ရှာဖွေတွေ့ရှိထားသော ဆာဗာများကို ထုတ်ပြန်ပါ
+        publish_statistics: စာရင်းဇယားထုတ်ပြန်မည်
         title: ရှာဖွေတွေ့ရှိမှု
         trends: လက်ရှိခေတ်စားမှုများ
       domain_blocks:
@@ -718,6 +729,7 @@ my:
         disabled: မည်သူ့ကိုမျှ
         users: အကောင့်ဝင်ထားသော ပြည်တွင်းအသုံးပြုသူများအတွက်
       registrations:
+        preamble: သင့်ဆာဗာတွင် အကောင့်တစ်ခုမည်သူဖန်တီးနိုင်သည်ကို ထိန်းချုပ်ပါ။
         title: စာရင်းသွင်းထားခြင်းများ
       registrations_mode:
         modes:
@@ -766,13 +778,24 @@ my:
       appeal_pending: အတည်ပြုမှုဆိုင်းငံ့ထားခြင်း
       appeal_rejected: တင်ပြခြင်းကို ပယ်ချခဲ့သည်
     system_checks:
+      database_schema_check:
+        message_html: ဆိုင်းငံ့ထားသော ဒေတာဘေ့စ် ပြောင်းရွှေ့မှုများ ရှိပါသည်။ အပလီကေးရှင်းသည် မျှော်လင့်ထားသည့်အတိုင်း လုပ်ဆောင်ကြောင်း သေချာစေရန် ၎င်းတို့ကို လုပ်ဆောင်ပါ။
+      elasticsearch_running_check:
+        message_html: Elasticsearch သို့ ချိတ်ဆက်၍မရပါ။ ၎င်းသည် အလုပ်လုပ်နေသလား၊ သို့မဟုတ် စာသားအပြည့်အစုံရှာဖွေမှုကို ပိတ်ပါ။
+      elasticsearch_version_check:
+        message_html: သဟဇာတမဖြစ်သော Elasticsearch ဗားရှင်း- %{value}
+        version_comparison: Elasticsearch %{running_version} သည် %{required_version} လိုအပ်နေချိန်တွင် လုပ်ဆောင်နေသည်
       rules_check:
         action: ဆာဗာစည်းမျဉ်းများကို စီမံရန်
         message_html: သင်သည် မည်သည့်ဆာဗာစည်းမျဉ်းများကိုမျှ မသတ်မှတ်ထားပါ။
+      sidekiq_process_check:
+        message_html: "%{value} တန်းစီ(s) အတွက် Sidekiq လုပ်ငန်းစဉ် မရှိပါ။ သင်၏ Sidekiq ဖွဲ့စည်းမှုကို ပြန်လည်သုံးသပ်ပါ။"
       upload_check_privacy_error:
         action: နောက်ထပ်အချက်အလက်များအတွက် ဤနေရာတွင် ကြည့်ပါ
+        message_html: "<strong>သင်၏ဝဘ်ဆာဗာကို မှားယွင်းစွာပြုလုပ်ထားသည်။ သင့်အသုံးပြုသူများ၏ လျှို့ဝှက်ချက်များသည် အန္တရာယ်ရှိသည်။</strong>"
       upload_check_privacy_error_object_storage:
         action: နောက်ထပ်အချက်အလက်များအတွက် ဤနေရာတွင် ကြည့်ပါ
+        message_html: "<strong>သင်၏ Object သိုလှောင်မှုအား မှားယွင်းစွာ စီစဉ်သတ်မှတ်ထားပါသည်။ သင့်အသုံးပြုသူများ၏ လျှို့ဝှက်ချက်များသည် အန္တရာယ်ရှိသည်။</strong>"
     tags:
       review: အခြေအနေသုံးသပ်ရန်
       updated_msg: ဟက်ရှ်တဂျ်သတ်မှတ်ချက်များကို အပ်ဒိတ်လုပ်ပြီးပါပြီ
@@ -784,6 +807,7 @@ my:
       links:
         allow: လင့်ခ်ကို ခွင့်ပြုရန်
         allow_provider: ပို့စ်တင်သူကိုခွင့်ပြုရန်
+        description_html: "၎င်းတို့သည် သင့်ဆာဗာမှ ပို့စ်များကို မြင်သည့် အကောင့်များမှ လောလောဆယ်တွင် အများအပြားမျှဝေနေသည့် လင့်ခ်များဖြစ်သည်။ ၎င်းသည် သင့်အသုံးပြုသူများအား ကမ္ဘာပေါ်တွင် ဖြစ်ပျက်နေသည့်အရာများကို ရှာဖွေရန် ကူညီပေးနိုင်ပါသည်။ ထုတ်ဝေသူအား သင်အတည်မပြုမချင်း လင့်ခ်များကို လူသိရှင်ကြားပြသခြင်းမရှိပါ။ တစ်ဦးချင်း လင့်ခ်များကို သင် ခွင့်ပြုနိုင်သည် သို့မဟုတ် ငြင်းပယ်နိုင်သည်။"
         disallow: လင့်ခ်ကို ခွင့်မပြုရန်
         disallow_provider: ပို့စ်တင်သူကို ခွင့်မပြုရန်
         no_link_selected: မည်သည့်လင့်ခ်ကိုမျှ ရွေးချယ်ထားခြင်းမရှိသောကြောင့် ပြောင်းလဲခြင်းမရှိပါ
@@ -798,24 +822,30 @@ my:
       pending_review: ဆိုင်းငံ့ထားသော သုံးသပ်ချက်
       preview_card_providers:
         allowed: ဤပို့စ်တင်သူထံမှ လင့်ခ်များ ခေတ်စားနိုင်သည်
+        description_html: "၎င်းတို့သည် သင့်ဆာဗာပေါ်တွင် မကြာခဏ လင့်ခ်များကို မျှဝေလေ့ရှိသည့် ဒိုမိန်းများဖြစ်သည်။ လင့်ခ်၏ဒိုမိန်းကို အတည်ပြုမထားပါက လင့်ခ်များသည် လူသိရှင်ကြား လမ်းကြောင်းပေါ်ရှိလိမ့်မည်မဟုတ်ပါ။ သင့်ခွင့်ပြုချက် (သို့မဟုတ် ငြင်းပယ်ခြင်း) သည် ဒိုမိန်းခွဲများသို့ အကျုံးဝင်ပါသည်။"
+        rejected: ဤထုတ်ဝေသူထံမှ လင့်ခ်များ ခေတ်စားလာမည်မဟုတ်ပါ။
         title: ပို့စ်တင်သူများ
       rejected: ဖယ်ရှားပြီးပါပြီ
       statuses:
         allow: ပို့စ်တင်ခွင့်ပြုရန်
         allow_account: ပို့စ်တင်သူကို ခွင့်ပြုပါ
+        description_html: ဤအရာများသည် သင့်ဆာဗာမှ သိရှိထားသည့် ပို့စ်များဖြစ်ပြီး လက်ရှိတွင် မျှဝေလျက်ရှိပြီး ယခုအချိန်တွင် လူကြိုက်များသော ပို့စ်များဖြစ်သည်။ ၎င်းသည် သင်၏အသစ်နှင့် ပြန်လာသောအသုံးပြုသူများကို လိုက်ကြည့်ရန် နောက်ထပ်လူများကို ရှာဖွေရန် ကူညီပေးနိုင်သည်။ စာရေးဆရာကို သင်အတည်ပြုသည့်တိုင်အောင် မည်သည့်ပို့စ်ကိုမျှ လူသိရှင်ကြားမပြသဘဲ၊ စာရေးသူက ၎င်းတို့၏အကောင့်ကို အခြားသူများထံ အကြံပြုခွင့်ပြုသည်။ တစ်ဦးချင်း ပို့စ်များကို ခွင့်ပြုနိုင်သည် သို့မဟုတ် ငြင်းပယ်နိုင်သည်။
         disallow: ပို့စ်ကို တင်ခွင့်မပြုရန်
         disallow_account: ပို့စ်တင်သူကို ခွင့်မပြုပါနဲ့
         no_status_selected: မည်သည့်ခေတ်စားနေသောပို့စ်ကိုမျှ ရွေးချယ်ထားခြင်းမရှိသောကြောင့် ပြောင်းလဲခြင်းမရှိပါ
+        not_discoverable: စာရေးသူသည် ရှာဖွေတွေ့ရှိနိုင်မှုကို ရွေးချယ်မထားပါ။
         shared_by:
           other: မျှဝေမှုနှင့် နှစ်သက်မှု %{friendly_count} ကြိမ်
         title: လက်ရှိခေတ်စားနေသော ပို့စ်များ
       tags:
         current_score: "%{score} လက်ရှိရမှတ်"
         dashboard:
+          tag_accounts_measure: အများဆုံးအသုံပြုမှုများ
           tag_languages_dimension: အသုံးများသည့်ဘာသာစကားများ
           tag_servers_dimension: အသုံးများသည့်ဆာဗာများ
           tag_servers_measure: မတူညီသောဆာဗာများ
           tag_uses_measure: စုစုပေါင်းအသုံးပြုမှု
+        description_html: "၎င်းတို့သည် သင့်ဆာဗာမြင်နေရသည့် ပို့စ်အများအပြားတွင် လက်ရှိမြင်နေရသည့် hashtag များဖြစ်သည်။ ၎င်းသည် သင့်အသုံးပြုသူများအား ယခုအချိန်တွင် လူအများပြောနေသည့်အရာများကို သိရှိနိုင်ရန် ကူညီပေးနိုင်ပါသည်။ ၎င်းတို့ကို သင်အတည်မပြုမချင်း hashtags များကို လူသိရှင်ကြား ပြသမည်မဟုတ်ပါ။"
         listable: အကြံပြုနိုင်ပါသည်
         no_tag_selected: မည်သည့်တဂျ်ကိုမျှ ရွေးချယ်ထားခြင်းမရှိသောကြောင့် ပြောင်းလဲခြင်းမရှိပါ
         not_listable: အကြံပြုမည်မဟုတ်ပါ
@@ -839,6 +869,7 @@ my:
     webhooks:
       add_new: ဆုံးမှတ် ထည့်ပါ
       delete: ဖျက်ပါ
+      description_html: "<strong>webhook</strong> သည် Mastodon အား ရွေးချယ်ထားသော အစီအစဉ်များအကြောင်း သင့်ကိုယ်ပိုင်အက်ပ်လီကေးရှင်းသို့ <strong>အချိန်နှင့်တစ်ပြေးညီ အသိပေးချက်များကို တွန်းပို့နိုင်သည်၊ ထို့ကြောင့် သင့်အပလီကေးရှင်းသည် <strong>တုံ့ပြန်မှုများကို အလိုအလျောက်စတင်နိုင်သည်</strong>။"
       disable: ပိတ်ပါ
       disabled: ပိတ်ထားသည်
       edit: ဆုံးမှတ် ပြင်ဆင်ပါ
@@ -890,6 +921,7 @@ my:
     remove: နာမည်တူများကို လင့်ခ်ဖြုတ်ပါ
   appearance:
     advanced_web_interface: အဆင့်မြင့်ဝဘ်ပုံစံ
+    animations_and_accessibility: လှုပ်ရှားမှုဆိုင်ရာများ
     confirmation_dialogs: အတည်ပြုချက် ဒိုင်ယာလော့ခ်များ
     discovery: ရှာဖွေတွေ့ရှိမှု
     localization:
@@ -1099,6 +1131,8 @@ my:
       keywords: အဓိကစကားလုံးများ
       statuses: တစ်ဦးချင်းတင်ထားသောပို့စ်များ
       title: စစ်ထုတ်ခြင်းကို ပြင်ဆင်ရန်
+    errors:
+      invalid_context: ပံ့ပိုးထား​သော အ​​ကြောင်းအရာ မရှိခြင်း သို့မဟုတ် မမှန်ကန်ခြင်း
     index:
       contexts: "%{contexts} ရှိ စစ်ထုတ်ထားမှုများ"
       delete: ဖျက်ပါ
@@ -1545,6 +1579,7 @@ my:
     backup_ready:
       explanation: သင့် Mastodon အကောင့် အရန်ကူးယူရန် တောင်းဆိုပြီးဖြစ်သည်။ ယခု ဒေါင်းလုဒ်လုပ်နိုင်ပါပြီ။
       subject: သင့်မှတ်တမ်း ဒေါင်းလုဒ်ဆွဲရန် အသင့်ဖြစ်ပါပြီ
+      title: မှတ်တမ်းသိမ်းရန်
     suspicious_sign_in:
       change_password: သင်၏ စကားဝှက်ပြောင်းလဲပါ
       details: ဤသည်မှာ အကောင့်ဝင်ရောက်ခြင်းအတွက် အသေးစိတ်အချက်များဖြစ်သည် -
diff --git a/config/locales/simple_form.el.yml b/config/locales/simple_form.el.yml
index dbb76208e..2788fd9b5 100644
--- a/config/locales/simple_form.el.yml
+++ b/config/locales/simple_form.el.yml
@@ -53,7 +53,7 @@ el:
         setting_default_sensitive: Τα ευαίσθητα πολυμέσα είναι κρυμμένα και εμφανίζονται με ένα κλικ
         setting_display_media_default: Απόκρυψη ευαίσθητων πολυμέσων
         setting_display_media_hide_all: Μόνιμη απόκρυψη όλων των πολυμέσων
-        setting_display_media_show_all: Μόνιμη εμφάνιση ευαίσθητων πολυμέσων
+        setting_display_media_show_all: Πάντα εμφάνιση πολυμέσων
         setting_hide_network: Δε θα εμφανίζεται στο προφίλ σου ποιους ακολουθείς και ποιοι σε ακολουθούν
         setting_noindex: Επηρεάζει το δημόσιο προφίλ και τις δημοσιεύσεις σου
         setting_show_application: Η εφαρμογή που χρησιμοποιείς για να στέλνεις τα τουτ σου θα εμφανίζεται στις αναλυτικές λεπτομέρειες τους
@@ -82,6 +82,22 @@ el:
         custom_css: Μπορείς να εφαρμόσεις προσαρμοσμένα στυλ στην έκδοση ιστοσελίδας του Mastodon.
         mascot: Παρακάμπτει την εικονογραφία στην προηγμένη διεπαφή ιστού.
         media_cache_retention_period: Τα ληφθέντα αρχεία πολυμέσων θα διαγραφούν μετά τον καθορισμένο αριθμό ημερών, όταν οριστεί σε θετική τιμή, και να γίνει εκ νέου λήψη κατά απαίτηση.
+        peers_api_enabled: Μια λίστα με ονόματα τομέα που συνάντησε αυτός ο διακομιστής στο fediverse. Δεν περιλαμβάνονται δεδομένα εδώ για το αν συναλλάσσετε με ένα συγκεκριμένο διακομιστή, μόνο ότι ο διακομιστής σας το ξέρει. Χρησιμοποιείται από υπηρεσίες που συλλέγουν στατιστικά στοιχεία για την συναλλαγή με γενική έννοια.
+        profile_directory: Ο κατάλογος προφίλ παραθέτει όλους τους χρήστες που έχουν επιλέξει να είναι ανακαλύψιμοι.
+        require_invite_text: 'Όταν η εγγραφή απαιτεί χειροκίνητη έγκριση, κάνε το πεδίο κειμένου: «Γιατί θέλετε να συμμετάσχετε;» υποχρεωτικό αντί για προαιρετικό'
+        site_contact_email: Πώς μπορούν να σε προσεγγίσουν για νομικές ή υποστηρικτικές έρευνες.
+        site_contact_username: Πώς μπορούν να σε προσεγγίσουν στο Mastodon.
+        site_extended_description: Οποιεσδήποτε πρόσθετες πληροφορίες μπορεί να είναι χρήσιμες για τους επισκέπτες και τους χρήστες σας. Μπορεί να δομηθεί με σύνταξη Markdown.
+        site_short_description: Μια σύντομη περιγραφή για να ξεχωρίζει ο διακομιστής σου. Ποιος τον έχει, για ποιον είναι;
+        site_terms: Χρησιμοποίησε τη δική σου πολιτική απορρήτου ή άσε το κενό για να χρησιμοποιήσεις την προεπιλεγμένη. Μπορεί να δομηθεί με σύνταξη Markdown.
+        site_title: Πώς μπορεί κάποιος να αναφέρεται στο διακομιστή σου εκτός από το όνομα τομέα του.
+        status_page_url: Το URL μιας σελίδας όπου κάποιος μπορεί να δει την κατάσταση αυτού του διακομιστή κατά τη διάρκεια μιας διακοπής λειτουργίας
+        theme: Θέμα που βλέπουν αποσυνδεδεμένοι επισκέπτες ή νέοι χρήστες.
+        thumbnail: Μια εικόνα περίπου 2:1 που εμφανίζεται παράλληλα με τις πληροφορίες του διακομιστή σου.
+        timeline_preview: Αποσυνδεδεμένοι επισκέπτες θα μπορούν να περιηγηθούν στις πιο πρόσφατες δημόσιες δημοσιεύσεις που είναι διαθέσιμες στο διακομιστή.
+        trendable_by_default: Παράλειψη χειροκίνητης αξιολόγησης του περιεχομένου σε τάση. Μεμονωμένα στοιχεία μπορούν ακόμα να αφαιρεθούν από τις τάσεις μετέπειτα.
+        trends: Τάσεις δείχνουν ποιες δημοσιεύσεις, ετικέτες και ειδήσεις προκαλούν έλξη στο διακομιστή σας.
+        trends_as_landing_page: Εμφάνιση περιεχομένου σε τάση σε αποσυνδεδεμένους χρήστες και επισκέπτες αντί για μια περιγραφή αυτού του διακομιστή. Απαιτεί οι τάσεις να έχουν ενεργοποιηθεί.
       form_challenge:
         current_password: Μπαίνεις σε ασφαλή περιοχή
       imports:
@@ -106,6 +122,16 @@ el:
         name: Μπορείς να αλλάξεις μόνο το πλαίσιο των χαρακτήρων, για παράδειγμα για να γίνει περισσότερο ευανάγνωστο
       user:
         chosen_languages: Όταν ενεργοποιηθεί, στη δημόσια ροή θα εμφανίζονται τουτ μόνο από τις επιλεγμένες γλώσσες
+        role: Ο ρόλος ελέγχει ποια δικαιώματα έχει ο χρήστης
+      user_role:
+        color: Το χρώμα που θα χρησιμοποιηθεί για το ρόλο σε ολόκληρη τη διεπαφή, ως RGB σε δεκαεξαδική μορφή
+        highlighted: Αυτό καθιστά το ρόλο δημόσια ορατό
+        name: Δημόσιο όνομα του ρόλου, εάν ο ρόλος έχει οριστεί να εμφανίζεται ως σήμα
+        permissions_as_keys: Οι χρήστες με αυτόν τον ρόλο θα έχουν πρόσβαση σε...
+        position: Ανώτεροι ρόλοι αποφασίζει την επίλυση συγκρούσεων σε ορισμένες περιπτώσεις. Ορισμένες ενέργειες μπορούν να εκτελεστούν μόνο σε ρόλους με χαμηλότερη προτεραιότητα
+      webhook:
+        events: Επιλέξτε συμβάντα για αποστολή
+        url: Πού θα σταλούν τα γεγονότα
     labels:
       account:
         fields:
@@ -136,6 +162,8 @@ el:
         scheduled_at: Προγραμματισμένη δημοσίευση
         starts_at: Έναρξη γεγονότος
         text: Ανακοίνωση
+      appeal:
+        text: Εξηγήστε γιατί αυτή η απόφαση πρέπει να αντιστραφεί
       defaults:
         autofollow: Προσκάλεσε για να ακολουθήσουν το λογαριασμό σου
         avatar: Αβατάρ
@@ -205,11 +233,32 @@ el:
           hide: Πλήρης απόκρυψη
           warn: Απόκρυψη με προειδοποίηση
       form_admin_settings:
+        activity_api_enabled: Δημοσίευση συγκεντρωτικών στατιστικών σχετικά με τη δραστηριότητα του χρήστη στο API
+        backups_retention_period: Περίοδος αρχειοθέτησης του χρήστη
+        bootstrap_timeline_accounts: Πρότεινε πάντα αυτούς τους λογαριασμούς σε νέους χρήστες
+        closed_registrations_message: Προσαρμοσμένο μήνυμα όταν οι εγγραφές δεν είναι διαθέσιμες
+        content_cache_retention_period: Περίοδος διατήρησης προσωρινής μνήμης περιεχομένου
         custom_css: Προσαρμοσμένο CSS
+        mascot: Προσαρμοσμένη μασκότ (απαρχαιωμένο)
+        media_cache_retention_period: Περίοδος διατήρησης προσωρινής μνήμης πολυμέσων
+        peers_api_enabled: Δημοσίευση λίστας των εντοπισμένων διακομιστών στο API
+        profile_directory: Ενεργοποίηση καταλόγου προφίλ
         registrations_mode: Ποιος μπορεί να εγγραφεί
+        require_invite_text: Απαίτησε έναν λόγο για να γίνει κάποιος μέλος
+        show_domain_blocks: Εμφάνιση αποκλεισμένων τομέων
+        show_domain_blocks_rationale: Εμφάνιση γιατί αποκλείστηκαν οι τομείς
         site_contact_email: E-mail επικοινωνίας
         site_contact_username: Όνομα χρήστη επικοινωνίας
+        site_extended_description: Εκτεταμένη περιγραφή
+        site_short_description: Περιγραφή διακομιστή
+        site_terms: Πολιτική Απορρήτου
+        site_title: Όνομα διακομιστή
         status_page_url: URL σελίδας κατάστασης
+        theme: Προεπιλεγμένο θέμα
+        thumbnail: Μικρογραφία διακομιστή
+        timeline_preview: Να επιτρέπεται μη πιστοποιημένη πρόσβαση σε δημόσια χρονολόγια
+        trendable_by_default: Επίτρεψε τις τάσεις χωρίς προηγούμενη αξιολόγηση
+        trends: Ενεργοποίηση τάσεων
         trends_as_landing_page: Χρήση των τάσεων ως σελίδα προορισμού
       interactions:
         must_be_follower: Μπλόκαρε τις ειδοποιήσεις από όσους δεν σε ακολουθούν
@@ -228,6 +277,7 @@ el:
           sign_up_requires_approval: Περιορισμός εγγραφών
         severity: Κανόνας
       notification_emails:
+        appeal: Κάποιος κάνει έφεση σε απόφαση συντονιστή
         digest: Αποστολή συνοπτικών email
         favourite: Αποστολή email όταν κάποιος σημειώνει ως αγαπημένη τη δημοσίευσή σου
         follow: Αποστολή email όταν κάποιος σε ακολουθεί
@@ -235,6 +285,8 @@ el:
         mention: Αποστολή email όταν κάποιος σε αναφέρει
         pending_account: Αποστολή email όταν υπάρχει νέος λογαριασμός για επιθεώρηση
         reblog: Αποστολή email όταν κάποιος προωθεί τη δημοσίευση σου
+        report: Υποβλήθηκε νέα αναφορά
+        trending_tag: Νέο περιεχόμενο προς τάση απαιτεί αξιολόγηση
       rule:
         text: Κανόνας
       tag:
@@ -244,7 +296,17 @@ el:
         usable: Χρήση της ετικέτας σε τουτ
       user:
         role: Ρόλος
+      user_role:
+        color: Χρώμα εμβλήματος
+        highlighted: Εμφάνιση ρόλου ως σήμα στα προφίλ χρηστών
+        name: Όνομα
+        permissions_as_keys: Δικαιώματα
+        position: Προτεραιότητα
+      webhook:
+        events: Ενεργοποιημένα συμβάντα
+        url: Endpoint URL
     'no': Όχι
+    not_recommended: Δεν προτείνεται
     recommended: Προτείνεται
     required:
       mark: "*"
diff --git a/config/locales/simple_form.my.yml b/config/locales/simple_form.my.yml
index 93319b13e..5f1624819 100644
--- a/config/locales/simple_form.my.yml
+++ b/config/locales/simple_form.my.yml
@@ -76,6 +76,7 @@ my:
         mascot: အဆင့်မြင့် ဝဘ်ပုံစံတွင်တွင် ရုပ်ပုံဖြင့်ဖော်ပြထားသည်။
         media_cache_retention_period: သတ်မှတ်ထားသောရက်များပြီးနောက် ဒေါင်းလုဒ်လုပ်ထားသော မီဒီယာဖိုင်များကို ဖျက်လိုက်ပါမည်။ တောင်းဆိုပါက ပြန်လည်ဒေါင်းလုဒ် လုပ်ခွင့်ရှိသည်။
         profile_directory: ပရိုဖိုင်လမ်းညွှန်တွင် ရှာဖွေ‌နိုင်သည့်အသုံးပြုသူအားလုံးကို စာရင်းပြုစုထားသည်။
+        require_invite_text: အကောင့်ဖွင့်ရာတွင် လူကိုယ်တိုင်ခွင့်ပြုချက်လိုအပ်သောအခါ “ဘာကြောင့်ပါဝင်ချင်သလဲ” ဟုလုပ်ပါ။ စိတ်ကြိုက်ရွေးချယ်မည့်အစား စာသားထည့်သွင်းရန်မဖြစ်မနေထည့်သွင်းပါ။
         site_contact_email: ဥပဒေရေးရာ သို့မဟုတ် အကူအညီ စုံစမ်းမေးမြန်းရန် လူများက သင့်ထံ မည်သို့ဆက်သွယ်နိုင်မည်နည်း။
         site_contact_username: Mastodon တွင် အခြားသူများက သင့်ကို မည်သို့သိရှိနိုင်မည်နည်း။
         site_extended_description: ဝင်ရောက်ကြည့်ရှုသူများနှင့် အသုံးပြုသူများအတွက် အသုံးဝင်မည့် နောက်ထပ်အချက်အလက်များကို Markdown စာကြောင်းများဖြင့် ရေးသားနိုင်သည်။
@@ -173,6 +174,7 @@ my:
         header: မျက်နှာဖုံးပုံ
         honeypot: "%{label} (မဖြည့်ပါနှင့်)"
         inbox_url: ထပ်ဆင့်ဝင်စာ၏ URL
+        irreversible: ဖျောက်မယ့်အစား လွှတ်လိုက်ပါ။
         locale: ဘာသာစကား
         locked: စောင့်ကြည့်တောင်းဆိုမှုများ လိုအပ်သည်
         max_uses: အများဆုံးအသုံးပြုမှုအရေအတွက်
diff --git a/config/locales/simple_form.zh-CN.yml b/config/locales/simple_form.zh-CN.yml
index 18ba22921..09e051cb5 100644
--- a/config/locales/simple_form.zh-CN.yml
+++ b/config/locales/simple_form.zh-CN.yml
@@ -33,7 +33,7 @@ zh-CN:
         autofollow: 通过邀请链接注册的用户将会自动关注你
         avatar: 文件大小限制 %{size},只支持 PNG、GIF 或 JPG 格式。图片分辨率将会压缩至 %{dimensions}px
         bot: 来自这个账户的绝大多数操作都是自动进行的,并且可能无人监控
-        context: 过滤器的应用环境
+        context: 过滤器的应用场景
         current_password: 为了安全起见,请输入当前账号的密码
         current_username: 请输入当前账号的用户名以确认
         digest: 仅在你长时间未登录,且收到了私信时发送
@@ -171,7 +171,7 @@ zh-CN:
         chosen_languages: 语言过滤
         confirm_new_password: 确认新密码
         confirm_password: 确认密码
-        context: 过滤器环境
+        context: 过滤场景
         current_password: 当前密码
         data: 数据文件
         discoverable: 在本站用户目录中收录此账号
diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml
index 5934a8607..f85c6c73a 100644
--- a/config/locales/zh-CN.yml
+++ b/config/locales/zh-CN.yml
@@ -307,12 +307,12 @@ zh-CN:
       unpublished_msg: 公告已取消发布!
       updated_msg: 公告已成功更新!
     custom_emojis:
-      assign_category: 指定分类
+      assign_category: 指定类别
       by_domain: 域名
       copied_msg: 已成功将表情复制到本站
       copy: 复制
       copy_failed_msg: 无法将表情复制到本站
-      create_new_category: 新建分类
+      create_new_category: 新建类别
       created_msg: 表情添加成功!
       delete: 删除
       destroyed_msg: 表情删除成功!
@@ -954,7 +954,7 @@ zh-CN:
   applications:
     created: 应用创建成功
     destroyed: 应用删除成功
-    logout: 登出
+    logout: 退出登录
     regenerate_token: 重置访问令牌
     token_regenerated: 访问令牌重置成功
     warning: 一定小心,千万不要把它分享给任何人!
@@ -978,7 +978,7 @@ zh-CN:
     link_to_webauth: 使用你的安全密钥设备
     log_in_with: 通过外部服务登录
     login: 登录
-    logout: 登出
+    logout: 退出登录
     migrate_account: 迁移到另一个账户
     migrate_account_html: 如果你希望引导他人关注另一个账号,请<a href="%{path}">点击这里进行设置</a>。
     or_log_in_with: 或通过外部服务登录
diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml
index 11a67ec47..ef027e8f2 100644
--- a/config/locales/zh-TW.yml
+++ b/config/locales/zh-TW.yml
@@ -970,7 +970,7 @@ zh-TW:
     delete_account_html: 如果您欲刪除您的帳號,請<a href="%{path}">點擊這裡繼續</a>。您需要再三確認您的操作。
     description:
       prefix_invited_by_user: "@%{name} 邀請您加入這個 Mastodon 伺服器!"
-      prefix_sign_up: 現在就註冊 Mastodon 帳號吧!
+      prefix_sign_up: 馬上註冊 Mastodon 帳號吧!
       suffix: 有了帳號,就可以從任何 Mastodon 伺服器跟隨任何人、發發廢嘟,並且與任何 Mastodon 伺服器的使用者交流,以及更多!
     didnt_get_confirmation: 沒有收到驗證信?
     dont_have_your_security_key: 找不到您的安全金鑰?
diff --git a/db/migrate/20230215074423_move_user_settings.rb b/db/migrate/20230215074423_move_user_settings.rb
index 351a8b61d..8dbca9ecd 100644
--- a/db/migrate/20230215074423_move_user_settings.rb
+++ b/db/migrate/20230215074423_move_user_settings.rb
@@ -52,7 +52,7 @@ class MoveUserSettings < ActiveRecord::Migration[6.1]
     end
 
     def value
-      YAML.safe_load(self[:value], permitted_classes: [ActiveSupport::HashWithIndifferentAccess]) if self[:value].present?
+      YAML.safe_load(self[:value], permitted_classes: [ActiveSupport::HashWithIndifferentAccess, Symbol]) if self[:value].present?
     end
   end
 
diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb
index b98095fa3..408f60185 100644
--- a/lib/mastodon/version.rb
+++ b/lib/mastodon/version.rb
@@ -13,7 +13,7 @@ module Mastodon
     end
 
     def patch
-      1
+      2
     end
 
     def flags
diff --git a/package.json b/package.json
index ef45f2143..1c09ae413 100644
--- a/package.json
+++ b/package.json
@@ -38,7 +38,6 @@
     "@github/webauthn-json": "^2.1.1",
     "@rails/ujs": "^6.1.7",
     "abortcontroller-polyfill": "^1.7.5",
-    "array-includes": "^3.1.6",
     "atrament": "0.2.4",
     "arrow-key-navigation": "^1.2.0",
     "autoprefixer": "^10.4.14",
@@ -203,7 +202,7 @@
     "react-test-renderer": "^16.14.0",
     "stylelint": "^15.3.0",
     "stylelint-config-standard-scss": "^7.0.1",
-    "typescript": "^4.9.5",
+    "typescript": "^5.0.3",
     "webpack-dev-server": "^3.11.3",
     "yargs": "^17.7.1"
   },
diff --git a/spec/lib/admin/system_check/base_check_spec.rb b/spec/lib/admin/system_check/base_check_spec.rb
new file mode 100644
index 000000000..fdd9f6b6c
--- /dev/null
+++ b/spec/lib/admin/system_check/base_check_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Admin::SystemCheck::BaseCheck do
+  subject(:check) { described_class.new(user) }
+
+  let(:user) { Fabricate(:user) }
+
+  describe 'skip?' do
+    it 'returns false' do
+      expect(check.skip?).to be false
+    end
+  end
+
+  describe 'pass?' do
+    it 'raises not implemented error' do
+      expect { check.pass? }.to raise_error(NotImplementedError)
+    end
+  end
+
+  describe 'message' do
+    it 'raises not implemented error' do
+      expect { check.message }.to raise_error(NotImplementedError)
+    end
+  end
+end
diff --git a/spec/lib/admin/system_check/database_schema_check_spec.rb b/spec/lib/admin/system_check/database_schema_check_spec.rb
new file mode 100644
index 000000000..db1dcb52f
--- /dev/null
+++ b/spec/lib/admin/system_check/database_schema_check_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Admin::SystemCheck::DatabaseSchemaCheck do
+  subject(:check) { described_class.new(user) }
+
+  let(:user) { Fabricate(:user) }
+
+  it_behaves_like 'a check available to devops users'
+
+  describe 'pass?' do
+    context 'when database needs migration' do
+      before do
+        context = instance_double(ActiveRecord::MigrationContext, needs_migration?: true)
+        allow(ActiveRecord::Base.connection).to receive(:migration_context).and_return(context)
+      end
+
+      it 'returns false' do
+        expect(check.pass?).to be false
+      end
+    end
+
+    context 'when database does not need migration' do
+      before do
+        context = instance_double(ActiveRecord::MigrationContext, needs_migration?: false)
+        allow(ActiveRecord::Base.connection).to receive(:migration_context).and_return(context)
+      end
+
+      it 'returns true' do
+        expect(check.pass?).to be true
+      end
+    end
+  end
+
+  describe 'message' do
+    it 'sends class name symbol to message instance' do
+      allow(Admin::SystemCheck::Message).to receive(:new).with(:database_schema_check)
+
+      check.message
+
+      expect(Admin::SystemCheck::Message).to have_received(:new).with(:database_schema_check)
+    end
+  end
+end
diff --git a/spec/lib/admin/system_check/elasticsearch_check_spec.rb b/spec/lib/admin/system_check/elasticsearch_check_spec.rb
new file mode 100644
index 000000000..1ffac89ee
--- /dev/null
+++ b/spec/lib/admin/system_check/elasticsearch_check_spec.rb
@@ -0,0 +1,100 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Admin::SystemCheck::ElasticsearchCheck do
+  subject(:check) { described_class.new(user) }
+
+  let(:user) { Fabricate(:user) }
+
+  it_behaves_like 'a check available to devops users'
+
+  describe 'pass?' do
+    context 'when chewy is enabled' do
+      before { allow(Chewy).to receive(:enabled?).and_return(true) }
+
+      context 'when running version is present and high enough' do
+        before do
+          allow(Chewy.client).to receive(:info)
+            .and_return({ 'version' => { 'number' => '999.99.9' } })
+        end
+
+        it 'returns true' do
+          expect(check.pass?).to be true
+        end
+      end
+
+      context 'when running version is present and too low' do
+        context 'when compatible version is too low' do
+          before do
+            allow(Chewy.client).to receive(:info)
+              .and_return({ 'version' => { 'number' => '1.2.3', 'minimum_wire_compatibility_version' => '1.0' } })
+          end
+
+          it 'returns false' do
+            expect(check.pass?).to be false
+          end
+        end
+
+        context 'when compatible version is high enough' do
+          before do
+            allow(Chewy.client).to receive(:info)
+              .and_return({ 'version' => { 'number' => '1.2.3', 'minimum_wire_compatibility_version' => '99.9' } })
+          end
+
+          it 'returns true' do
+            expect(check.pass?).to be true
+          end
+        end
+      end
+
+      context 'when running version is missing' do
+        before do
+          client = instance_double(Elasticsearch::Transport::Client)
+          allow(client).to receive(:info).and_raise(Elasticsearch::Transport::Transport::Error)
+          allow(Chewy).to receive(:client).and_return(client)
+        end
+
+        it 'returns false' do
+          expect(check.pass?).to be false
+        end
+      end
+    end
+
+    context 'when chewy is not enabled' do
+      before { allow(Chewy).to receive(:enabled?).and_return(false) }
+
+      it 'returns true' do
+        expect(check.pass?).to be true
+      end
+    end
+  end
+
+  describe 'message' do
+    context 'when running version is present' do
+      before { allow(Chewy.client).to receive(:info).and_return({ 'version' => { 'number' => '999.99.9' } }) }
+
+      it 'sends class name symbol to message instance' do
+        allow(Admin::SystemCheck::Message).to receive(:new)
+          .with(:elasticsearch_version_check, anything)
+
+        check.message
+
+        expect(Admin::SystemCheck::Message).to have_received(:new)
+          .with(:elasticsearch_version_check, 'Elasticsearch 999.99.9 is running while 7.x is required')
+      end
+    end
+
+    context 'when running version is missing' do
+      it 'sends class name symbol to message instance' do
+        allow(Admin::SystemCheck::Message).to receive(:new)
+          .with(:elasticsearch_running_check)
+
+        check.message
+
+        expect(Admin::SystemCheck::Message).to have_received(:new)
+          .with(:elasticsearch_running_check)
+      end
+    end
+  end
+end
diff --git a/spec/lib/admin/system_check/media_privacy_check_spec.rb b/spec/lib/admin/system_check/media_privacy_check_spec.rb
new file mode 100644
index 000000000..316bf1215
--- /dev/null
+++ b/spec/lib/admin/system_check/media_privacy_check_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Admin::SystemCheck::MediaPrivacyCheck do
+  subject(:check) { described_class.new(user) }
+
+  let(:user) { Fabricate(:user) }
+
+  it_behaves_like 'a check available to devops users'
+
+  describe 'pass?' do
+    context 'when the media cannot be listed' do
+      before do
+        stub_request(:get, /ngrok.io/).to_return(status: 200, body: 'a list of no files')
+      end
+
+      it 'returns true' do
+        expect(check.pass?).to be true
+      end
+    end
+  end
+
+  describe 'message' do
+    it 'sends values to message instance' do
+      allow(Admin::SystemCheck::Message).to receive(:new).with(nil, nil, nil, true)
+
+      check.message
+
+      expect(Admin::SystemCheck::Message).to have_received(:new).with(nil, nil, nil, true)
+    end
+  end
+end
diff --git a/spec/lib/admin/system_check/message_spec.rb b/spec/lib/admin/system_check/message_spec.rb
new file mode 100644
index 000000000..c0671f345
--- /dev/null
+++ b/spec/lib/admin/system_check/message_spec.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Admin::SystemCheck::Message do
+  subject(:check) { described_class.new(:key_value, :value_value, :action_value, :critical_value) }
+
+  it 'providers readers when initialized' do
+    expect(check.key).to eq :key_value
+    expect(check.value).to eq :value_value
+    expect(check.action).to eq :action_value
+    expect(check.critical).to eq :critical_value
+  end
+end
diff --git a/spec/lib/admin/system_check/rules_check_spec.rb b/spec/lib/admin/system_check/rules_check_spec.rb
new file mode 100644
index 000000000..fb3293fb2
--- /dev/null
+++ b/spec/lib/admin/system_check/rules_check_spec.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Admin::SystemCheck::RulesCheck do
+  subject(:check) { described_class.new(user) }
+
+  let(:user) { Fabricate(:user) }
+
+  describe 'skip?' do
+    context 'when user can manage rules' do
+      before { allow(user).to receive(:can?).with(:manage_rules).and_return(true) }
+
+      it 'returns false' do
+        expect(check.skip?).to be false
+      end
+    end
+
+    context 'when user cannot manage rules' do
+      before { allow(user).to receive(:can?).with(:manage_rules).and_return(false) }
+
+      it 'returns true' do
+        expect(check.skip?).to be true
+      end
+    end
+  end
+
+  describe 'pass?' do
+    context 'when there is not a kept rule' do
+      it 'returns false' do
+        expect(check.pass?).to be false
+      end
+    end
+
+    context 'when there is a kept rule' do
+      before { Fabricate(:rule) }
+
+      it 'returns true' do
+        expect(check.pass?).to be true
+      end
+    end
+  end
+
+  describe 'message' do
+    it 'sends class name symbol to message instance' do
+      allow(Admin::SystemCheck::Message).to receive(:new).with(:rules_check, nil, '/admin/rules')
+
+      check.message
+
+      expect(Admin::SystemCheck::Message).to have_received(:new).with(:rules_check, nil, '/admin/rules')
+    end
+  end
+end
diff --git a/spec/lib/admin/system_check/sidekiq_process_check_spec.rb b/spec/lib/admin/system_check/sidekiq_process_check_spec.rb
new file mode 100644
index 000000000..9bd9daddf
--- /dev/null
+++ b/spec/lib/admin/system_check/sidekiq_process_check_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Admin::SystemCheck::SidekiqProcessCheck do
+  subject(:check) { described_class.new(user) }
+
+  let(:user) { Fabricate(:user) }
+
+  it_behaves_like 'a check available to devops users'
+
+  describe 'pass?' do
+    context 'when missing queues is empty' do
+      before do
+        process_set = instance_double(Sidekiq::ProcessSet, reduce: [])
+        allow(Sidekiq::ProcessSet).to receive(:new).and_return(process_set)
+      end
+
+      it 'returns true' do
+        expect(check.pass?).to be true
+      end
+    end
+
+    context 'when missing queues is not empty' do
+      before do
+        process_set = instance_double(Sidekiq::ProcessSet, reduce: [:something])
+        allow(Sidekiq::ProcessSet).to receive(:new).and_return(process_set)
+      end
+
+      it 'returns false' do
+        expect(check.pass?).to be false
+      end
+    end
+  end
+
+  describe 'message' do
+    it 'sends values to message instance' do
+      allow(Admin::SystemCheck::Message).to receive(:new).with(:sidekiq_process_check, 'default, push, mailers, pull, scheduler, ingress')
+
+      check.message
+
+      expect(Admin::SystemCheck::Message).to have_received(:new).with(:sidekiq_process_check, 'default, push, mailers, pull, scheduler, ingress')
+    end
+  end
+end
diff --git a/spec/lib/admin/system_check_spec.rb b/spec/lib/admin/system_check_spec.rb
new file mode 100644
index 000000000..30048fd3a
--- /dev/null
+++ b/spec/lib/admin/system_check_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Admin::SystemCheck do
+  let(:user) { Fabricate(:user) }
+
+  describe 'perform' do
+    let(:result) { described_class.perform(user) }
+
+    it 'runs all the checks' do
+      expect(result).to be_an(Array)
+    end
+  end
+end
diff --git a/spec/support/examples/lib/admin/checks.rb b/spec/support/examples/lib/admin/checks.rb
new file mode 100644
index 000000000..b50faa77b
--- /dev/null
+++ b/spec/support/examples/lib/admin/checks.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+shared_examples 'a check available to devops users' do
+  describe 'skip?' do
+    context 'when user can view devops' do
+      before { allow(user).to receive(:can?).with(:view_devops).and_return(true) }
+
+      it 'returns false' do
+        expect(check.skip?).to be false
+      end
+    end
+
+    context 'when user cannot view devops' do
+      before { allow(user).to receive(:can?).with(:view_devops).and_return(false) }
+
+      it 'returns true' do
+        expect(check.skip?).to be true
+      end
+    end
+  end
+end
diff --git a/stylelint.config.js b/stylelint.config.js
index b56e6f9cb..1a153adb9 100644
--- a/stylelint.config.js
+++ b/stylelint.config.js
@@ -15,7 +15,6 @@ module.exports = {
     'no-descending-specificity': null,
     'no-duplicate-selectors': null,
     'number-max-precision': 8,
-    'property-no-unknown': null,
     'property-no-vendor-prefix': null,
     'selector-class-pattern': null,
     'selector-id-pattern': null,
@@ -25,4 +24,18 @@ module.exports = {
     'scss/dollar-variable-empty-line-before': null,
     'scss/no-global-function-names': null,
   },
+  overrides: [
+    {
+      'files': ['app/javascript/styles/mailer.scss'],
+      rules: {
+        'property-no-unknown': [
+          true,
+          {
+            ignoreProperties: [
+              '/^mso-/',
+            ] },
+        ],
+      },
+    },
+  ],
 };
diff --git a/yarn.lock b/yarn.lock
index 2c8437091..45ed66d8b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -11405,10 +11405,10 @@ type@^2.0.0:
   resolved "https://registry.yarnpkg.com/type/-/type-2.0.0.tgz#5f16ff6ef2eb44f260494dae271033b29c09a9c3"
   integrity sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==
 
-typescript@^4.9.5:
-  version "4.9.5"
-  resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
-  integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
+typescript@^5.0.3:
+  version "5.0.3"
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.3.tgz#fe976f0c826a88d0a382007681cbb2da44afdedf"
+  integrity sha512-xv8mOEDnigb/tN9PSMTwSEqAnUvkoXMQlicOb0IUVDBSQCgBSaAAROUZYy2IcUy5qU6XajK5jjjO7TMWqBTKZA==
 
 unbox-primitive@^1.0.2:
   version "1.0.2"