about summary refs log tree commit diff
path: root/app
diff options
context:
space:
mode:
authorReverite <github@reverite.sh>2019-04-12 01:38:18 -0700
committerReverite <github@reverite.sh>2019-04-12 01:38:18 -0700
commite10a9794f4ed7c90e3190f285359f55dd00da435 (patch)
tree579ebf95d6bbf091d05e66907a9c8168c926e0af /app
parentff736905fa534f7189e57c1d0c14fbac45f239a1 (diff)
parentbb50ec2e6687238ad8b2ec545a73270fee7a7b09 (diff)
Merge branch 'glitch' into production
Diffstat (limited to 'app')
-rw-r--r--app/controllers/about_controller.rb5
-rw-r--r--app/controllers/activitypub/collections_controller.rb16
-rw-r--r--app/controllers/activitypub/outboxes_controller.rb6
-rw-r--r--app/controllers/admin/pending_accounts_controller.rb52
-rw-r--r--app/controllers/api/v1/accounts/follower_accounts_controller.rb8
-rw-r--r--app/controllers/api/v1/accounts/following_accounts_controller.rb8
-rw-r--r--app/controllers/api/v1/accounts/statuses_controller.rb10
-rw-r--r--app/controllers/api/v1/accounts_controller.rb5
-rw-r--r--app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb1
-rw-r--r--app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb2
-rw-r--r--app/controllers/auth/registrations_controller.rb14
-rw-r--r--app/controllers/follower_accounts_controller.rb7
-rw-r--r--app/controllers/following_accounts_controller.rb8
-rw-r--r--app/controllers/home_controller.rb2
-rw-r--r--app/controllers/settings/identity_proofs_controller.rb2
-rw-r--r--app/controllers/settings/preferences_controller.rb2
-rw-r--r--app/controllers/shares_controller.rb2
-rw-r--r--app/helpers/application_helper.rb5
-rw-r--r--app/helpers/stream_entries_helper.rb2
-rw-r--r--app/javascript/core/settings.js8
-rw-r--r--app/javascript/flavours/glitch/actions/alerts.js5
-rw-r--r--app/javascript/flavours/glitch/components/poll.js33
-rw-r--r--app/javascript/flavours/glitch/components/relative_timestamp.js34
-rw-r--r--app/javascript/flavours/glitch/components/status_content.js4
-rw-r--r--app/javascript/flavours/glitch/features/account/components/header.js2
-rw-r--r--app/javascript/flavours/glitch/features/account_gallery/index.js13
-rw-r--r--app/javascript/flavours/glitch/features/account_timeline/components/header.js3
-rw-r--r--app/javascript/flavours/glitch/features/account_timeline/index.js13
-rw-r--r--app/javascript/flavours/glitch/features/favourites/index.js28
-rw-r--r--app/javascript/flavours/glitch/features/followers/index.js13
-rw-r--r--app/javascript/flavours/glitch/features/following/index.js13
-rw-r--r--app/javascript/flavours/glitch/features/reblogs/index.js28
-rw-r--r--app/javascript/flavours/glitch/features/status/components/detailed_status.js1
-rw-r--r--app/javascript/flavours/glitch/styles/accounts.scss26
-rw-r--r--app/javascript/flavours/glitch/styles/stream_entries.scss17
-rw-r--r--app/javascript/flavours/glitch/styles/widgets.scss9
-rw-r--r--app/javascript/mastodon/actions/alerts.js5
-rw-r--r--app/javascript/mastodon/components/poll.js33
-rw-r--r--app/javascript/mastodon/components/relative_timestamp.js30
-rw-r--r--app/javascript/mastodon/components/status.js2
-rw-r--r--app/javascript/mastodon/features/account/components/header.js4
-rw-r--r--app/javascript/mastodon/features/account_gallery/index.js13
-rw-r--r--app/javascript/mastodon/features/account_timeline/components/header.js3
-rw-r--r--app/javascript/mastodon/features/account_timeline/index.js33
-rw-r--r--app/javascript/mastodon/features/followers/index.js19
-rw-r--r--app/javascript/mastodon/features/following/index.js19
-rw-r--r--app/javascript/mastodon/features/status/index.js2
-rw-r--r--app/javascript/mastodon/locales/ar.json27
-rw-r--r--app/javascript/mastodon/locales/ast.json1
-rw-r--r--app/javascript/mastodon/locales/bg.json1
-rw-r--r--app/javascript/mastodon/locales/bn.json1
-rw-r--r--app/javascript/mastodon/locales/ca.json35
-rw-r--r--app/javascript/mastodon/locales/co.json1
-rw-r--r--app/javascript/mastodon/locales/cs.json7
-rw-r--r--app/javascript/mastodon/locales/cy.json1
-rw-r--r--app/javascript/mastodon/locales/da.json1
-rw-r--r--app/javascript/mastodon/locales/de.json1
-rw-r--r--app/javascript/mastodon/locales/defaultMessages.json52
-rw-r--r--app/javascript/mastodon/locales/el.json19
-rw-r--r--app/javascript/mastodon/locales/en.json2
-rw-r--r--app/javascript/mastodon/locales/eo.json43
-rw-r--r--app/javascript/mastodon/locales/es.json1
-rw-r--r--app/javascript/mastodon/locales/eu.json1
-rw-r--r--app/javascript/mastodon/locales/fa.json1
-rw-r--r--app/javascript/mastodon/locales/fi.json1
-rw-r--r--app/javascript/mastodon/locales/fr.json25
-rw-r--r--app/javascript/mastodon/locales/gl.json1
-rw-r--r--app/javascript/mastodon/locales/he.json1
-rw-r--r--app/javascript/mastodon/locales/hr.json1
-rw-r--r--app/javascript/mastodon/locales/hu.json1
-rw-r--r--app/javascript/mastodon/locales/hy.json1
-rw-r--r--app/javascript/mastodon/locales/id.json1
-rw-r--r--app/javascript/mastodon/locales/io.json1
-rw-r--r--app/javascript/mastodon/locales/it.json1
-rw-r--r--app/javascript/mastodon/locales/ja.json6
-rw-r--r--app/javascript/mastodon/locales/ka.json1
-rw-r--r--app/javascript/mastodon/locales/kk.json9
-rw-r--r--app/javascript/mastodon/locales/ko.json1
-rw-r--r--app/javascript/mastodon/locales/lv.json1
-rw-r--r--app/javascript/mastodon/locales/ms.json1
-rw-r--r--app/javascript/mastodon/locales/nl.json29
-rw-r--r--app/javascript/mastodon/locales/no.json1
-rw-r--r--app/javascript/mastodon/locales/oc.json5
-rw-r--r--app/javascript/mastodon/locales/pl.json5
-rw-r--r--app/javascript/mastodon/locales/pt-BR.json55
-rw-r--r--app/javascript/mastodon/locales/pt.json1
-rw-r--r--app/javascript/mastodon/locales/ro.json1
-rw-r--r--app/javascript/mastodon/locales/ru.json158
-rw-r--r--app/javascript/mastodon/locales/sk.json177
-rw-r--r--app/javascript/mastodon/locales/sl.json1
-rw-r--r--app/javascript/mastodon/locales/sq.json1
-rw-r--r--app/javascript/mastodon/locales/sr-Latn.json1
-rw-r--r--app/javascript/mastodon/locales/sr.json1
-rw-r--r--app/javascript/mastodon/locales/sv.json1
-rw-r--r--app/javascript/mastodon/locales/ta.json1
-rw-r--r--app/javascript/mastodon/locales/te.json1
-rw-r--r--app/javascript/mastodon/locales/th.json15
-rw-r--r--app/javascript/mastodon/locales/tr.json325
-rw-r--r--app/javascript/mastodon/locales/uk.json1
-rw-r--r--app/javascript/mastodon/locales/zh-CN.json1
-rw-r--r--app/javascript/mastodon/locales/zh-HK.json1
-rw-r--r--app/javascript/mastodon/locales/zh-TW.json1
-rw-r--r--app/javascript/styles/mastodon/accounts.scss26
-rw-r--r--app/javascript/styles/mastodon/components.scss3
-rw-r--r--app/javascript/styles/mastodon/stream_entries.scss17
-rw-r--r--app/javascript/styles/mastodon/widgets.scss9
-rw-r--r--app/lib/proof_provider/keybase.rb16
-rw-r--r--app/lib/proof_provider/keybase/badge.rb9
-rw-r--r--app/lib/proof_provider/keybase/config_serializer.rb2
-rw-r--r--app/lib/proof_provider/keybase/verifier.rb5
-rw-r--r--app/lib/proof_provider/keybase/worker.rb5
-rw-r--r--app/models/account.rb1
-rw-r--r--app/models/account_identity_proof.rb6
-rw-r--r--app/models/concerns/account_finder_concern.rb2
-rw-r--r--app/models/export.rb12
-rw-r--r--app/models/form/account_batch.rb19
-rw-r--r--app/models/form/admin_settings.rb3
-rw-r--r--app/models/user.rb9
-rw-r--r--app/models/user_invite_request.rb17
-rw-r--r--app/presenters/account_relationships_presenter.rb6
-rw-r--r--app/presenters/instance_presenter.rb2
-rw-r--r--app/serializers/rest/relationship_serializer.rb6
-rw-r--r--app/services/account_search_service.rb10
-rw-r--r--app/services/import_service.rb29
-rw-r--r--app/services/search_service.rb2
-rw-r--r--app/validators/existing_username_validator.rb10
-rw-r--r--app/validators/html_validator.rb12
-rw-r--r--app/validators/poll_validator.rb2
-rw-r--r--app/views/about/_registration.html.haml5
-rw-r--r--app/views/accounts/show.html.haml4
-rw-r--r--app/views/admin/accounts/index.html.haml2
-rw-r--r--app/views/admin/pending_accounts/_account.html.haml14
-rw-r--r--app/views/admin/pending_accounts/index.html.haml30
-rw-r--r--app/views/admin_mailer/new_pending_account.text.erb10
-rw-r--r--app/views/auth/registrations/new.html.haml9
-rw-r--r--app/views/follower_accounts/index.html.haml2
-rw-r--r--app/views/following_accounts/index.html.haml2
-rw-r--r--app/views/settings/notifications/show.html.haml1
-rw-r--r--app/views/settings/preferences/show.html.haml1
-rw-r--r--app/workers/import/relationship_worker.rb7
140 files changed, 1224 insertions, 704 deletions
diff --git a/app/controllers/about_controller.rb b/app/controllers/about_controller.rb
index f459bab19..5850bd56d 100644
--- a/app/controllers/about_controller.rb
+++ b/app/controllers/about_controller.rb
@@ -17,7 +17,10 @@ class AboutController < ApplicationController
   private
 
   def new_user
-    User.new.tap(&:build_account)
+    User.new.tap do |user|
+      user.build_account
+      user.build_invite_request
+    end
   end
 
   helper_method :new_user
diff --git a/app/controllers/activitypub/collections_controller.rb b/app/controllers/activitypub/collections_controller.rb
index 995da9c55..853f4f907 100644
--- a/app/controllers/activitypub/collections_controller.rb
+++ b/app/controllers/activitypub/collections_controller.rb
@@ -6,13 +6,19 @@ class ActivityPub::CollectionsController < Api::BaseController
   before_action :set_account
   before_action :set_size
   before_action :set_statuses
+  before_action :set_cache_headers
 
   def show
-    render json: collection_presenter,
-           serializer: ActivityPub::CollectionSerializer,
-           adapter: ActivityPub::Adapter,
-           content_type: 'application/activity+json',
-           skip_activities: true
+    skip_session!
+
+    render_cached_json(['activitypub', 'collection', @account, params[:id]], content_type: 'application/activity+json') do
+      ActiveModelSerializers::SerializableResource.new(
+        collection_presenter,
+        serializer: ActivityPub::CollectionSerializer,
+        adapter: ActivityPub::Adapter,
+        skip_activities: true
+      )
+    end
   end
 
   private
diff --git a/app/controllers/activitypub/outboxes_controller.rb b/app/controllers/activitypub/outboxes_controller.rb
index be4289b21..438fa226e 100644
--- a/app/controllers/activitypub/outboxes_controller.rb
+++ b/app/controllers/activitypub/outboxes_controller.rb
@@ -7,8 +7,14 @@ class ActivityPub::OutboxesController < Api::BaseController
 
   before_action :set_account
   before_action :set_statuses
+  before_action :set_cache_headers
 
   def show
+    unless page_requested?
+      skip_session!
+      expires_in 1.minute, public: true
+    end
+
     render json: outbox_presenter, serializer: ActivityPub::OutboxSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'
   end
 
diff --git a/app/controllers/admin/pending_accounts_controller.rb b/app/controllers/admin/pending_accounts_controller.rb
new file mode 100644
index 000000000..b62a9bc84
--- /dev/null
+++ b/app/controllers/admin/pending_accounts_controller.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+module Admin
+  class PendingAccountsController < BaseController
+    before_action :set_accounts, only: :index
+
+    def index
+      @form = Form::AccountBatch.new
+    end
+
+    def batch
+      @form = Form::AccountBatch.new(form_account_batch_params.merge(current_account: current_account, action: action_from_button))
+      @form.save
+    rescue ActionController::ParameterMissing
+      flash[:alert] = I18n.t('admin.accounts.no_account_selected')
+    ensure
+      redirect_to admin_pending_accounts_path(current_params)
+    end
+
+    def approve_all
+      Form::AccountBatch.new(current_account: current_account, account_ids: User.pending.pluck(:account_id), action: 'approve').save
+      redirect_to admin_pending_accounts_path(current_params)
+    end
+
+    def reject_all
+      Form::AccountBatch.new(current_account: current_account, account_ids: User.pending.pluck(:account_id), action: 'reject').save
+      redirect_to admin_pending_accounts_path(current_params)
+    end
+
+    private
+
+    def set_accounts
+      @accounts = Account.joins(:user).merge(User.pending.recent).includes(user: :invite_request).page(params[:page])
+    end
+
+    def form_account_batch_params
+      params.require(:form_account_batch).permit(:action, account_ids: [])
+    end
+
+    def action_from_button
+      if params[:approve]
+        'approve'
+      elsif params[:reject]
+        'reject'
+      end
+    end
+
+    def current_params
+      params.slice(:page).permit(:page)
+    end
+  end
+end
diff --git a/app/controllers/api/v1/accounts/follower_accounts_controller.rb b/app/controllers/api/v1/accounts/follower_accounts_controller.rb
index 7a45e6dd2..2dabb8398 100644
--- a/app/controllers/api/v1/accounts/follower_accounts_controller.rb
+++ b/app/controllers/api/v1/accounts/follower_accounts_controller.rb
@@ -19,13 +19,17 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController
   end
 
   def load_accounts
-    return [] if @account.user_hides_network? && current_account.id != @account.id
+    return [] if hide_results?
 
     default_accounts.merge(paginated_follows).to_a
   end
 
+  def hide_results?
+    (@account.user_hides_network? && current_account.id != @account.id) || (current_account && @account.blocking?(current_account))
+  end
+
   def default_accounts
-    Account.without_blocking(current_account).includes(:active_relationships, :account_stat).references(:active_relationships)
+    Account.includes(:active_relationships, :account_stat).references(:active_relationships)
   end
 
   def paginated_follows
diff --git a/app/controllers/api/v1/accounts/following_accounts_controller.rb b/app/controllers/api/v1/accounts/following_accounts_controller.rb
index 0369cb25e..44e89804b 100644
--- a/app/controllers/api/v1/accounts/following_accounts_controller.rb
+++ b/app/controllers/api/v1/accounts/following_accounts_controller.rb
@@ -19,13 +19,17 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController
   end
 
   def load_accounts
-    return [] if @account.user_hides_network? && current_account.id != @account.id
+    return [] if hide_results?
 
     default_accounts.merge(paginated_follows).to_a
   end
 
+  def hide_results?
+    (@account.user_hides_network? && current_account.id != @account.id) || (current_account && @account.blocking?(current_account))
+  end
+
   def default_accounts
-    Account.without_blocking(current_account).includes(:passive_relationships, :account_stat).references(:passive_relationships)
+    Account.includes(:passive_relationships, :account_stat).references(:passive_relationships)
   end
 
   def paginated_follows
diff --git a/app/controllers/api/v1/accounts/statuses_controller.rb b/app/controllers/api/v1/accounts/statuses_controller.rb
index 7aba2d0bd..8cd8f8e79 100644
--- a/app/controllers/api/v1/accounts/statuses_controller.rb
+++ b/app/controllers/api/v1/accounts/statuses_controller.rb
@@ -3,8 +3,6 @@
 class Api::V1::Accounts::StatusesController < Api::BaseController
   before_action -> { authorize_if_got_token! :read, :'read:statuses' }
   before_action :set_account
-  before_action :check_account_suspension
-  before_action :check_account_block
   after_action :insert_pagination_headers
 
   respond_to :json
@@ -20,14 +18,6 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
     @account = Account.find(params[:account_id])
   end
 
-  def check_account_suspension
-    gone if @account.suspended?
-  end
-
-  def check_account_block
-    gone if current_account.present? && @account.blocking?(current_account)
-  end
-
   def load_statuses
     cached_account_statuses
   end
diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb
index 685e044c3..b0c62778e 100644
--- a/app/controllers/api/v1/accounts_controller.rb
+++ b/app/controllers/api/v1/accounts_controller.rb
@@ -10,7 +10,6 @@ class Api::V1::AccountsController < Api::BaseController
   before_action :require_user!, except: [:show, :create]
   before_action :set_account, except: [:create]
   before_action :check_account_suspension, only: [:show]
-  before_action :check_account_block, only: [:show]
   before_action :check_enabled_registrations, only: [:create]
 
   respond_to :json
@@ -76,10 +75,6 @@ class Api::V1::AccountsController < Api::BaseController
     gone if @account.suspended?
   end
 
-  def check_account_block
-    gone if current_account.present? && @account.blocking?(current_account)
-  end
-
   def account_params
     params.permit(:username, :email, :password, :agreement, :locale)
   end
diff --git a/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb b/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb
index e00c4d708..657e57831 100644
--- a/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb
+++ b/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb
@@ -22,7 +22,6 @@ class Api::V1::Statuses::FavouritedByAccountsController < Api::BaseController
 
   def default_accounts
     Account
-      .without_blocking(current_account)
       .includes(:favourites, :account_stat)
       .references(:favourites)
       .where(favourites: { status_id: @status.id })
diff --git a/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb b/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb
index 9b2d0e59e..6851099f6 100644
--- a/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb
+++ b/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb
@@ -21,7 +21,7 @@ class Api::V1::Statuses::RebloggedByAccountsController < Api::BaseController
   end
 
   def default_accounts
-    Account.without_blocking(current_account).includes(:statuses, :account_stat).references(:statuses)
+    Account.includes(:statuses, :account_stat).references(:statuses)
   end
 
   def paginated_statuses
diff --git a/app/controllers/auth/registrations_controller.rb b/app/controllers/auth/registrations_controller.rb
index 74dd7ff34..84099bd96 100644
--- a/app/controllers/auth/registrations_controller.rb
+++ b/app/controllers/auth/registrations_controller.rb
@@ -11,6 +11,10 @@ class Auth::RegistrationsController < Devise::RegistrationsController
   before_action :set_instance_presenter, only: [:new, :create, :update]
   before_action :set_body_classes, only: [:new, :create, :edit, :update]
 
+  def new
+    super(&:build_invite_request)
+  end
+
   def destroy
     not_found
   end
@@ -25,17 +29,17 @@ class Auth::RegistrationsController < Devise::RegistrationsController
   def build_resource(hash = nil)
     super(hash)
 
-    resource.locale      = I18n.locale
-    resource.invite_code = params[:invite_code] if resource.invite_code.blank?
-    resource.agreement   = true
+    resource.locale             = I18n.locale
+    resource.invite_code        = params[:invite_code] if resource.invite_code.blank?
+    resource.agreement          = true
+    resource.current_sign_in_ip = request.remote_ip
 
-    resource.current_sign_in_ip = request.remote_ip if resource.current_sign_in_ip.nil?
     resource.build_account if resource.account.nil?
   end
 
   def configure_sign_up_params
     devise_parameter_sanitizer.permit(:sign_up) do |u|
-      u.permit({ account_attributes: [:username] }, :email, :password, :password_confirmation, :invite_code)
+      u.permit({ account_attributes: [:username], invite_request_attributes: [:text] }, :email, :password, :password_confirmation, :invite_code)
     end
   end
 
diff --git a/app/controllers/follower_accounts_controller.rb b/app/controllers/follower_accounts_controller.rb
index 213c209ab..1462b94fc 100644
--- a/app/controllers/follower_accounts_controller.rb
+++ b/app/controllers/follower_accounts_controller.rb
@@ -3,6 +3,8 @@
 class FollowerAccountsController < ApplicationController
   include AccountControllerConcern
 
+  before_action :set_cache_headers
+
   def index
     respond_to do |format|
       format.html do
@@ -18,6 +20,11 @@ class FollowerAccountsController < ApplicationController
       format.json do
         raise Mastodon::NotPermittedError if params[:page].present? && @account.user_hides_network?
 
+        if params[:page].blank?
+          skip_session!
+          expires_in 3.minutes, public: true
+        end
+
         render json: collection_presenter,
                serializer: ActivityPub::CollectionSerializer,
                adapter: ActivityPub::Adapter,
diff --git a/app/controllers/following_accounts_controller.rb b/app/controllers/following_accounts_controller.rb
index 098b2a20c..181f85221 100644
--- a/app/controllers/following_accounts_controller.rb
+++ b/app/controllers/following_accounts_controller.rb
@@ -3,10 +3,13 @@
 class FollowingAccountsController < ApplicationController
   include AccountControllerConcern
 
+  before_action :set_cache_headers
+
   def index
     respond_to do |format|
       format.html do
         use_pack 'public'
+        mark_cacheable! unless user_signed_in?
 
         next if @account.user_hides_network?
 
@@ -17,6 +20,11 @@ class FollowingAccountsController < ApplicationController
       format.json do
         raise Mastodon::NotPermittedError if params[:page].present? && @account.user_hides_network?
 
+        if params[:page].blank?
+          skip_session!
+          expires_in 3.minutes, public: true
+        end
+
         render json: collection_presenter,
                serializer: ActivityPub::CollectionSerializer,
                adapter: ActivityPub::Adapter,
diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb
index 82e5265f5..06ca03e34 100644
--- a/app/controllers/home_controller.rb
+++ b/app/controllers/home_controller.rb
@@ -56,7 +56,7 @@ class HomeController < ApplicationController
       push_subscription: current_account.user.web_push_subscription(current_session),
       current_account: current_account,
       token: current_session.token,
-      admin: Account.find_local(Setting.site_contact_username),
+      admin: Account.find_local(Setting.site_contact_username.strip.gsub(/\A@/, '')),
     }
   end
 
diff --git a/app/controllers/settings/identity_proofs_controller.rb b/app/controllers/settings/identity_proofs_controller.rb
index 8f857fdcc..e22b4d9be 100644
--- a/app/controllers/settings/identity_proofs_controller.rb
+++ b/app/controllers/settings/identity_proofs_controller.rb
@@ -18,7 +18,7 @@ class Settings::IdentityProofsController < Settings::BaseController
       provider_username: params[:provider_username]
     )
 
-    if current_account.username == params[:username]
+    if current_account.username.casecmp(params[:username]).zero?
       render layout: 'auth'
     else
       flash[:alert] = I18n.t('identity_proofs.errors.wrong_user', proving: params[:username], current: current_account.username)
diff --git a/app/controllers/settings/preferences_controller.rb b/app/controllers/settings/preferences_controller.rb
index 241053261..eb7a0eb4a 100644
--- a/app/controllers/settings/preferences_controller.rb
+++ b/app/controllers/settings/preferences_controller.rb
@@ -46,7 +46,7 @@ class Settings::PreferencesController < Settings::BaseController
       :setting_hide_followers_count,
       :setting_aggregate_reblogs,
       :setting_show_application,
-      notification_emails: %i(follow follow_request reblog favourite mention digest report),
+      notification_emails: %i(follow follow_request reblog favourite mention digest report pending_account),
       interactions: %i(must_be_follower must_be_following)
     )
   end
diff --git a/app/controllers/shares_controller.rb b/app/controllers/shares_controller.rb
index 4624c29a6..ada4eec54 100644
--- a/app/controllers/shares_controller.rb
+++ b/app/controllers/shares_controller.rb
@@ -22,7 +22,7 @@ class SharesController < ApplicationController
       push_subscription: current_account.user.web_push_subscription(current_session),
       current_account: current_account,
       token: current_session.token,
-      admin: Account.find_local(Setting.site_contact_username),
+      admin: Account.find_local(Setting.site_contact_username.strip.gsub(/\A@/, '')),
       text: text,
     }
   end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index f70c37522..7ae1e5d0b 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -118,4 +118,9 @@ module ApplicationHelper
   def storage_host?
     ENV['S3_ALIAS_HOST'].present? || ENV['S3_CLOUDFRONT_HOST'].present?
   end
+
+  def quote_wrap(text, line_width: 80, break_sequence: "\n")
+    text = word_wrap(text, line_width: line_width - 2, break_sequence: break_sequence)
+    text.split("\n").map { |line| '> ' + line }.join("\n")
+  end
 end
diff --git a/app/helpers/stream_entries_helper.rb b/app/helpers/stream_entries_helper.rb
index 5ad2c438e..6e646ab84 100644
--- a/app/helpers/stream_entries_helper.rb
+++ b/app/helpers/stream_entries_helper.rb
@@ -23,7 +23,7 @@ module StreamEntriesHelper
           safe_join([render(file: Rails.root.join('app', 'javascript', 'images', 'logo.svg')), t('accounts.unfollow')])
         end
       elsif !(account.memorial? || account.moved?)
-        link_to account_follow_path(account), class: 'button logo-button', data: { method: :post } do
+        link_to account_follow_path(account), class: "button logo-button#{account.blocking?(current_account) ? ' disabled' : ''}", data: { method: :post } do
           safe_join([render(file: Rails.root.join('app', 'javascript', 'images', 'logo.svg')), t('accounts.follow')])
         end
       end
diff --git a/app/javascript/core/settings.js b/app/javascript/core/settings.js
index af97fb25f..e0cb944e0 100644
--- a/app/javascript/core/settings.js
+++ b/app/javascript/core/settings.js
@@ -42,14 +42,20 @@ delegate(document, '#account_locked', 'change', ({ target }) => {
 });
 
 delegate(document, '.input-copy input', 'click', ({ target }) => {
+  target.focus();
   target.select();
+  target.setSelectionRange(0, target.value.length);
 });
 
 delegate(document, '.input-copy button', 'click', ({ target }) => {
   const input = target.parentNode.querySelector('.input-copy__wrapper input');
 
+  const oldReadOnly = input.readonly;
+
+  input.readonly = false;
   input.focus();
   input.select();
+  input.setSelectionRange(0, input.value.length);
 
   try {
     if (document.execCommand('copy')) {
@@ -63,4 +69,6 @@ delegate(document, '.input-copy button', 'click', ({ target }) => {
   } catch (err) {
     console.error(err);
   }
+
+  input.readonly = oldReadOnly;
 });
diff --git a/app/javascript/flavours/glitch/actions/alerts.js b/app/javascript/flavours/glitch/actions/alerts.js
index 50cd48a9e..b2c7ab76a 100644
--- a/app/javascript/flavours/glitch/actions/alerts.js
+++ b/app/javascript/flavours/glitch/actions/alerts.js
@@ -34,6 +34,11 @@ export function showAlertForError(error) {
   if (error.response) {
     const { data, status, statusText } = error.response;
 
+    if (status === 404 || status === 410) {
+      // Skip these errors as they are reflected in the UI
+      return {};
+    }
+
     let message = statusText;
     let title   = `${status}`;
 
diff --git a/app/javascript/flavours/glitch/components/poll.js b/app/javascript/flavours/glitch/components/poll.js
index 56331cb29..690f9ae5a 100644
--- a/app/javascript/flavours/glitch/components/poll.js
+++ b/app/javascript/flavours/glitch/components/poll.js
@@ -9,41 +9,12 @@ import Motion from 'mastodon/features/ui/util/optional_motion';
 import spring from 'react-motion/lib/spring';
 import escapeTextContentForBrowser from 'escape-html';
 import emojify from 'mastodon/features/emoji/emoji';
+import RelativeTimestamp from './relative_timestamp';
 
 const messages = defineMessages({
-  moments: { id: 'time_remaining.moments', defaultMessage: 'Moments remaining' },
-  seconds: { id: 'time_remaining.seconds', defaultMessage: '{number, plural, one {# second} other {# seconds}} left' },
-  minutes: { id: 'time_remaining.minutes', defaultMessage: '{number, plural, one {# minute} other {# minutes}} left' },
-  hours: { id: 'time_remaining.hours', defaultMessage: '{number, plural, one {# hour} other {# hours}} left' },
-  days: { id: 'time_remaining.days', defaultMessage: '{number, plural, one {# day} other {# days}} left' },
   closed: { id: 'poll.closed', defaultMessage: 'Closed' },
 });
 
-const SECOND = 1000;
-const MINUTE = 1000 * 60;
-const HOUR   = 1000 * 60 * 60;
-const DAY    = 1000 * 60 * 60 * 24;
-
-const timeRemainingString = (intl, date, now) => {
-  const delta = date.getTime() - now;
-
-  let relativeTime;
-
-  if (delta < 10 * SECOND) {
-    relativeTime = intl.formatMessage(messages.moments);
-  } else if (delta < MINUTE) {
-    relativeTime = intl.formatMessage(messages.seconds, { number: Math.floor(delta / SECOND) });
-  } else if (delta < HOUR) {
-    relativeTime = intl.formatMessage(messages.minutes, { number: Math.floor(delta / MINUTE) });
-  } else if (delta < DAY) {
-    relativeTime = intl.formatMessage(messages.hours, { number: Math.floor(delta / HOUR) });
-  } else {
-    relativeTime = intl.formatMessage(messages.days, { number: Math.floor(delta / DAY) });
-  }
-
-  return relativeTime;
-};
-
 const makeEmojiMap = record => record.get('emojis').reduce((obj, emoji) => {
   obj[`:${emoji.get('shortcode')}:`] = emoji.toJS();
   return obj;
@@ -146,7 +117,7 @@ class Poll extends ImmutablePureComponent {
       return null;
     }
 
-    const timeRemaining = poll.get('expired') ? intl.formatMessage(messages.closed) : timeRemainingString(intl, new Date(poll.get('expires_at')), intl.now());
+    const timeRemaining = poll.get('expired') ? intl.formatMessage(messages.closed) : <RelativeTimestamp timestamp={poll.get('expires_at')} futureDate />;
     const showResults   = poll.get('voted') || poll.get('expired');
     const disabled      = this.props.disabled || Object.entries(this.state.selected).every(item => !item);
 
diff --git a/app/javascript/flavours/glitch/components/relative_timestamp.js b/app/javascript/flavours/glitch/components/relative_timestamp.js
index 9609714a1..aa4b73cfe 100644
--- a/app/javascript/flavours/glitch/components/relative_timestamp.js
+++ b/app/javascript/flavours/glitch/components/relative_timestamp.js
@@ -8,6 +8,11 @@ const messages = defineMessages({
   minutes: { id: 'relative_time.minutes', defaultMessage: '{number}m' },
   hours: { id: 'relative_time.hours', defaultMessage: '{number}h' },
   days: { id: 'relative_time.days', defaultMessage: '{number}d' },
+  moments_remaining: { id: 'time_remaining.moments', defaultMessage: 'Moments remaining' },
+  seconds_remaining: { id: 'time_remaining.seconds', defaultMessage: '{number, plural, one {# second} other {# seconds}} left' },
+  minutes_remaining: { id: 'time_remaining.minutes', defaultMessage: '{number, plural, one {# minute} other {# minutes}} left' },
+  hours_remaining: { id: 'time_remaining.hours', defaultMessage: '{number, plural, one {# hour} other {# hours}} left' },
+  days_remaining: { id: 'time_remaining.days', defaultMessage: '{number, plural, one {# day} other {# days}} left' },
 });
 
 const dateFormatOptions = {
@@ -86,13 +91,34 @@ export const timeAgoString = (intl, date, now, year) => {
   return relativeTime;
 };
 
-@injectIntl
-export default class RelativeTimestamp extends React.Component {
+const timeRemainingString = (intl, date, now) => {
+  const delta = date.getTime() - now;
+
+  let relativeTime;
+
+  if (delta < 10 * SECOND) {
+    relativeTime = intl.formatMessage(messages.moments_remaining);
+  } else if (delta < MINUTE) {
+    relativeTime = intl.formatMessage(messages.seconds_remaining, { number: Math.floor(delta / SECOND) });
+  } else if (delta < HOUR) {
+    relativeTime = intl.formatMessage(messages.minutes_remaining, { number: Math.floor(delta / MINUTE) });
+  } else if (delta < DAY) {
+    relativeTime = intl.formatMessage(messages.hours_remaining, { number: Math.floor(delta / HOUR) });
+  } else {
+    relativeTime = intl.formatMessage(messages.days_remaining, { number: Math.floor(delta / DAY) });
+  }
+
+  return relativeTime;
+};
+
+export default @injectIntl
+class RelativeTimestamp extends React.Component {
 
   static propTypes = {
     intl: PropTypes.object.isRequired,
     timestamp: PropTypes.string.isRequired,
     year: PropTypes.number.isRequired,
+    futureDate: PropTypes.bool,
   };
 
   state = {
@@ -145,10 +171,10 @@ export default class RelativeTimestamp extends React.Component {
   }
 
   render () {
-    const { timestamp, intl, year } = this.props;
+    const { timestamp, intl, year, futureDate } = this.props;
 
     const date         = new Date(timestamp);
-    const relativeTime = timeAgoString(intl, date, this.state.now, year);
+    const relativeTime = futureDate ? timeRemainingString(intl, date, this.state.now) : timeAgoString(intl, date, this.state.now, year);
 
     return (
       <time dateTime={timestamp} title={intl.formatDate(date, dateFormatOptions)}>
diff --git a/app/javascript/flavours/glitch/components/status_content.js b/app/javascript/flavours/glitch/components/status_content.js
index a62844185..ae14c949a 100644
--- a/app/javascript/flavours/glitch/components/status_content.js
+++ b/app/javascript/flavours/glitch/components/status_content.js
@@ -91,9 +91,9 @@ export default class StatusContent extends React.PureComponent {
   }
 
   handleMouseUp = (e) => {
-    const { parseClick } = this.props;
+    const { parseClick, disabled } = this.props;
 
-    if (!this.startXY) {
+    if (disabled || !this.startXY) {
       return;
     }
 
diff --git a/app/javascript/flavours/glitch/features/account/components/header.js b/app/javascript/flavours/glitch/features/account/components/header.js
index 13f7741c8..43c4f0d32 100644
--- a/app/javascript/flavours/glitch/features/account/components/header.js
+++ b/app/javascript/flavours/glitch/features/account/components/header.js
@@ -22,8 +22,6 @@ const messages = defineMessages({
   account_locked: { id: 'account.locked_info', defaultMessage: 'This account privacy status is set to locked. The owner manually reviews who can follow them.' },
   mention: { id: 'account.mention', defaultMessage: 'Mention @{name}' },
   direct: { id: 'account.direct', defaultMessage: 'Direct message @{name}' },
-  edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' },
-  unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' },
   unmute: { id: 'account.unmute', defaultMessage: 'Unmute @{name}' },
   block: { id: 'account.block', defaultMessage: 'Block @{name}' },
   mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' },
diff --git a/app/javascript/flavours/glitch/features/account_gallery/index.js b/app/javascript/flavours/glitch/features/account_gallery/index.js
index 63c1b2d86..3b1af108f 100644
--- a/app/javascript/flavours/glitch/features/account_gallery/index.js
+++ b/app/javascript/flavours/glitch/features/account_gallery/index.js
@@ -13,8 +13,10 @@ import MediaItem from './components/media_item';
 import HeaderContainer from 'flavours/glitch/features/account_timeline/containers/header_container';
 import { ScrollContainer } from 'react-router-scroll-4';
 import LoadMore from 'flavours/glitch/components/load_more';
+import MissingIndicator from 'flavours/glitch/components/missing_indicator';
 
 const mapStateToProps = (state, props) => ({
+  isAccount: !!state.getIn(['accounts', props.params.accountId]),
   medias: getAccountGallery(state, props.params.accountId),
   isLoading: state.getIn(['timelines', `account:${props.params.accountId}:media`, 'isLoading']),
   hasMore:   state.getIn(['timelines', `account:${props.params.accountId}:media`, 'hasMore']),
@@ -51,6 +53,7 @@ export default class AccountGallery extends ImmutablePureComponent {
     medias: ImmutablePropTypes.list.isRequired,
     isLoading: PropTypes.bool,
     hasMore: PropTypes.bool,
+    isAccount: PropTypes.bool,
   };
 
   componentDidMount () {
@@ -103,7 +106,15 @@ export default class AccountGallery extends ImmutablePureComponent {
   }
 
   render () {
-    const { medias, isLoading, hasMore } = this.props;
+    const { medias, isLoading, hasMore, isAccount } = this.props;
+
+    if (!isAccount) {
+      return (
+        <Column>
+          <MissingIndicator />
+        </Column>
+      );
+    }
 
     let loadOlder = null;
 
diff --git a/app/javascript/flavours/glitch/features/account_timeline/components/header.js b/app/javascript/flavours/glitch/features/account_timeline/components/header.js
index 96cabe847..0faa8a424 100644
--- a/app/javascript/flavours/glitch/features/account_timeline/components/header.js
+++ b/app/javascript/flavours/glitch/features/account_timeline/components/header.js
@@ -3,7 +3,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import InnerHeader from 'flavours/glitch/features/account/components/header';
 import ActionBar from 'flavours/glitch/features/account/components/action_bar';
-import MissingIndicator from 'flavours/glitch/components/missing_indicator';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import { FormattedMessage } from 'react-intl';
 import { NavLink } from 'react-router-dom';
@@ -89,7 +88,7 @@ export default class Header extends ImmutablePureComponent {
     const { account, hideTabs, identity_proofs } = this.props;
 
     if (account === null) {
-      return <MissingIndicator />;
+      return null;
     }
 
     return (
diff --git a/app/javascript/flavours/glitch/features/account_timeline/index.js b/app/javascript/flavours/glitch/features/account_timeline/index.js
index 9971c0f4a..93d8fc9ec 100644
--- a/app/javascript/flavours/glitch/features/account_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/account_timeline/index.js
@@ -13,11 +13,13 @@ import { List as ImmutableList } from 'immutable';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import { FormattedMessage } from 'react-intl';
 import { fetchAccountIdentityProofs } from '../../actions/identity_proofs';
+import MissingIndicator from 'flavours/glitch/components/missing_indicator';
 
 const mapStateToProps = (state, { params: { accountId }, withReplies = false }) => {
   const path = withReplies ? `${accountId}:with_replies` : accountId;
 
   return {
+    isAccount: !!state.getIn(['accounts', accountId]),
     statusIds: state.getIn(['timelines', `account:${path}`, 'items'], ImmutableList()),
     featuredStatusIds: withReplies ? ImmutableList() : state.getIn(['timelines', `account:${accountId}:pinned`, 'items'], ImmutableList()),
     isLoading: state.getIn(['timelines', `account:${path}`, 'isLoading']),
@@ -36,6 +38,7 @@ export default class AccountTimeline extends ImmutablePureComponent {
     isLoading: PropTypes.bool,
     hasMore: PropTypes.bool,
     withReplies: PropTypes.bool,
+    isAccount: PropTypes.bool,
   };
 
   componentWillMount () {
@@ -73,7 +76,15 @@ export default class AccountTimeline extends ImmutablePureComponent {
   }
 
   render () {
-    const { statusIds, featuredStatusIds, isLoading, hasMore } = this.props;
+    const { statusIds, featuredStatusIds, isLoading, hasMore, isAccount } = this.props;
+
+    if (!isAccount) {
+      return (
+        <Column>
+          <MissingIndicator />
+        </Column>
+      );
+    }
 
     if (!statusIds && isLoading) {
       return (
diff --git a/app/javascript/flavours/glitch/features/favourites/index.js b/app/javascript/flavours/glitch/features/favourites/index.js
index 65cd4a19b..eb86636c3 100644
--- a/app/javascript/flavours/glitch/features/favourites/index.js
+++ b/app/javascript/flavours/glitch/features/favourites/index.js
@@ -7,20 +7,27 @@ import { fetchFavourites } from 'flavours/glitch/actions/interactions';
 import { ScrollContainer } from 'react-router-scroll-4';
 import AccountContainer from 'flavours/glitch/containers/account_container';
 import Column from 'flavours/glitch/features/ui/components/column';
-import ColumnBackButton from 'flavours/glitch/components/column_back_button';
+import ColumnHeader from 'flavours/glitch/components/column_header';
+import { defineMessages, injectIntl } from 'react-intl';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 
+const messages = defineMessages({
+  heading: { id: 'column.favourited_by', defaultMessage: 'Favourited by' },
+});
+
 const mapStateToProps = (state, props) => ({
   accountIds: state.getIn(['user_lists', 'favourited_by', props.params.statusId]),
 });
 
 @connect(mapStateToProps)
+@injectIntl
 export default class Favourites extends ImmutablePureComponent {
 
   static propTypes = {
     params: PropTypes.object.isRequired,
     dispatch: PropTypes.func.isRequired,
     accountIds: ImmutablePropTypes.list,
+    intl: PropTypes.object.isRequired,
   };
 
   componentWillMount () {
@@ -38,8 +45,16 @@ export default class Favourites extends ImmutablePureComponent {
     return !(location.state && location.state.mastodonModalOpen);
   }
 
+  handleHeaderClick = () => {
+    this.column.scrollTop();
+  }
+
+  setRef = c => {
+    this.column = c;
+  }
+
   render () {
-    const { accountIds } = this.props;
+    const { intl, accountIds } = this.props;
 
     if (!accountIds) {
       return (
@@ -50,8 +65,13 @@ export default class Favourites extends ImmutablePureComponent {
     }
 
     return (
-      <Column>
-        <ColumnBackButton />
+      <Column ref={this.setRef}>
+        <ColumnHeader
+          icon='star'
+          title={intl.formatMessage(messages.heading)}
+          onClick={this.handleHeaderClick}
+          showBackButton
+        />
 
         <ScrollContainer scrollKey='favourites' shouldUpdateScroll={this.shouldUpdateScroll}>
           <div className='scrollable'>
diff --git a/app/javascript/flavours/glitch/features/followers/index.js b/app/javascript/flavours/glitch/features/followers/index.js
index 6bb9f60fd..2e47ab9b9 100644
--- a/app/javascript/flavours/glitch/features/followers/index.js
+++ b/app/javascript/flavours/glitch/features/followers/index.js
@@ -15,8 +15,10 @@ import ProfileColumnHeader from 'flavours/glitch/features/account/components/pro
 import HeaderContainer from 'flavours/glitch/features/account_timeline/containers/header_container';
 import LoadMore from 'flavours/glitch/components/load_more';
 import ImmutablePureComponent from 'react-immutable-pure-component';
+import MissingIndicator from 'flavours/glitch/components/missing_indicator';
 
 const mapStateToProps = (state, props) => ({
+  isAccount: !!state.getIn(['accounts', props.params.accountId]),
   accountIds: state.getIn(['user_lists', 'followers', props.params.accountId, 'items']),
   hasMore: !!state.getIn(['user_lists', 'followers', props.params.accountId, 'next']),
 });
@@ -29,6 +31,7 @@ export default class Followers extends ImmutablePureComponent {
     dispatch: PropTypes.func.isRequired,
     accountIds: ImmutablePropTypes.list,
     hasMore: PropTypes.bool,
+    isAccount: PropTypes.bool,
   };
 
   componentWillMount () {
@@ -70,7 +73,15 @@ export default class Followers extends ImmutablePureComponent {
   }
 
   render () {
-    const { accountIds, hasMore } = this.props;
+    const { accountIds, hasMore, isAccount } = this.props;
+
+    if (!isAccount) {
+      return (
+        <Column>
+          <MissingIndicator />
+        </Column>
+      );
+    }
 
     let loadMore = null;
 
diff --git a/app/javascript/flavours/glitch/features/following/index.js b/app/javascript/flavours/glitch/features/following/index.js
index 3f2f091a1..ad1445f3a 100644
--- a/app/javascript/flavours/glitch/features/following/index.js
+++ b/app/javascript/flavours/glitch/features/following/index.js
@@ -15,8 +15,10 @@ import ProfileColumnHeader from 'flavours/glitch/features/account/components/pro
 import HeaderContainer from 'flavours/glitch/features/account_timeline/containers/header_container';
 import LoadMore from 'flavours/glitch/components/load_more';
 import ImmutablePureComponent from 'react-immutable-pure-component';
+import MissingIndicator from 'flavours/glitch/components/missing_indicator';
 
 const mapStateToProps = (state, props) => ({
+  isAccount: !!state.getIn(['accounts', props.params.accountId]),
   accountIds: state.getIn(['user_lists', 'following', props.params.accountId, 'items']),
   hasMore: !!state.getIn(['user_lists', 'following', props.params.accountId, 'next']),
 });
@@ -29,6 +31,7 @@ export default class Following extends ImmutablePureComponent {
     dispatch: PropTypes.func.isRequired,
     accountIds: ImmutablePropTypes.list,
     hasMore: PropTypes.bool,
+    isAccount: PropTypes.bool,
   };
 
   componentWillMount () {
@@ -70,7 +73,15 @@ export default class Following extends ImmutablePureComponent {
   }
 
   render () {
-    const { accountIds, hasMore } = this.props;
+    const { accountIds, hasMore, isAccount } = this.props;
+
+    if (!isAccount) {
+      return (
+        <Column>
+          <MissingIndicator />
+        </Column>
+      );
+    }
 
     let loadMore = null;
 
diff --git a/app/javascript/flavours/glitch/features/reblogs/index.js b/app/javascript/flavours/glitch/features/reblogs/index.js
index 75f8390a1..e007506b7 100644
--- a/app/javascript/flavours/glitch/features/reblogs/index.js
+++ b/app/javascript/flavours/glitch/features/reblogs/index.js
@@ -7,20 +7,27 @@ import { fetchReblogs } from 'flavours/glitch/actions/interactions';
 import { ScrollContainer } from 'react-router-scroll-4';
 import AccountContainer from 'flavours/glitch/containers/account_container';
 import Column from 'flavours/glitch/features/ui/components/column';
-import ColumnBackButton from 'flavours/glitch/components/column_back_button';
+import ColumnHeader from 'flavours/glitch/components/column_header';
+import { defineMessages, injectIntl } from 'react-intl';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 
+const messages = defineMessages({
+  heading: { id: 'column.reblogged_by', defaultMessage: 'Boosted by' },
+});
+
 const mapStateToProps = (state, props) => ({
   accountIds: state.getIn(['user_lists', 'reblogged_by', props.params.statusId]),
 });
 
 @connect(mapStateToProps)
+@injectIntl
 export default class Reblogs extends ImmutablePureComponent {
 
   static propTypes = {
     params: PropTypes.object.isRequired,
     dispatch: PropTypes.func.isRequired,
     accountIds: ImmutablePropTypes.list,
+    intl: PropTypes.object.isRequired,
   };
 
   componentWillMount () {
@@ -38,8 +45,16 @@ export default class Reblogs extends ImmutablePureComponent {
     return !(location.state && location.state.mastodonModalOpen);
   }
 
+  handleHeaderClick = () => {
+    this.column.scrollTop();
+  }
+
+  setRef = c => {
+    this.column = c;
+  }
+
   render () {
-    const { accountIds } = this.props;
+    const { intl, accountIds } = this.props;
 
     if (!accountIds) {
       return (
@@ -50,8 +65,13 @@ export default class Reblogs extends ImmutablePureComponent {
     }
 
     return (
-      <Column>
-        <ColumnBackButton />
+      <Column ref={this.setRef}>
+        <ColumnHeader
+          icon='retweet'
+          title={intl.formatMessage(messages.heading)}
+          onClick={this.handleHeaderClick}
+          showBackButton
+        />
 
         <ScrollContainer scrollKey='reblogs' shouldUpdateScroll={this.shouldUpdateScroll}>
           <div className='scrollable reblogs'>
diff --git a/app/javascript/flavours/glitch/features/status/components/detailed_status.js b/app/javascript/flavours/glitch/features/status/components/detailed_status.js
index e78f16c54..e9130b1b0 100644
--- a/app/javascript/flavours/glitch/features/status/components/detailed_status.js
+++ b/app/javascript/flavours/glitch/features/status/components/detailed_status.js
@@ -228,6 +228,7 @@ export default class DetailedStatus extends ImmutablePureComponent {
             onExpandedToggle={onToggleHidden}
             parseClick={this.parseClick}
             onUpdate={this.handleChildUpdate}
+            disabled
           />
 
           <div className='detailed-status__meta'>
diff --git a/app/javascript/flavours/glitch/styles/accounts.scss b/app/javascript/flavours/glitch/styles/accounts.scss
index d2ae83b2e..57451c3a1 100644
--- a/app/javascript/flavours/glitch/styles/accounts.scss
+++ b/app/javascript/flavours/glitch/styles/accounts.scss
@@ -294,3 +294,29 @@
 .directory__tag .trends__item__current {
   width: auto;
 }
+
+.pending-account {
+  &__header {
+    color: $darker-text-color;
+
+    a {
+      color: $ui-secondary-color;
+      text-decoration: none;
+
+      &:hover,
+      &:active,
+      &:focus {
+        text-decoration: underline;
+      }
+    }
+
+    strong {
+      color: $primary-text-color;
+      font-weight: 700;
+    }
+  }
+
+  &__body {
+    margin-top: 10px;
+  }
+}
diff --git a/app/javascript/flavours/glitch/styles/stream_entries.scss b/app/javascript/flavours/glitch/styles/stream_entries.scss
index 6735049b9..e18696fb7 100644
--- a/app/javascript/flavours/glitch/styles/stream_entries.scss
+++ b/app/javascript/flavours/glitch/styles/stream_entries.scss
@@ -109,6 +109,23 @@
     }
   }
 
+  &:disabled,
+  &.disabled {
+    svg path:last-child {
+      fill: $ui-primary-color;
+    }
+
+    &:active,
+    &:focus,
+    &:hover {
+      background: $ui-primary-color;
+
+      svg path:last-child {
+        fill: $ui-primary-color;
+      }
+    }
+  }
+
   &.button--destructive {
     &:active,
     &:focus,
diff --git a/app/javascript/flavours/glitch/styles/widgets.scss b/app/javascript/flavours/glitch/styles/widgets.scss
index 307e509d5..e736d7a7e 100644
--- a/app/javascript/flavours/glitch/styles/widgets.scss
+++ b/app/javascript/flavours/glitch/styles/widgets.scss
@@ -377,6 +377,10 @@
     border: 0;
   }
 
+  strong {
+    font-weight: 700;
+  }
+
   thead th {
     text-align: center;
     text-transform: uppercase;
@@ -414,6 +418,11 @@
     }
   }
 
+  &__comment {
+    width: 50%;
+    vertical-align: initial !important;
+  }
+
   @media screen and (max-width: $no-gap-breakpoint) {
     tbody td.optional {
       display: none;
diff --git a/app/javascript/mastodon/actions/alerts.js b/app/javascript/mastodon/actions/alerts.js
index 50cd48a9e..b2c7ab76a 100644
--- a/app/javascript/mastodon/actions/alerts.js
+++ b/app/javascript/mastodon/actions/alerts.js
@@ -34,6 +34,11 @@ export function showAlertForError(error) {
   if (error.response) {
     const { data, status, statusText } = error.response;
 
+    if (status === 404 || status === 410) {
+      // Skip these errors as they are reflected in the UI
+      return {};
+    }
+
     let message = statusText;
     let title   = `${status}`;
 
diff --git a/app/javascript/mastodon/components/poll.js b/app/javascript/mastodon/components/poll.js
index 56331cb29..690f9ae5a 100644
--- a/app/javascript/mastodon/components/poll.js
+++ b/app/javascript/mastodon/components/poll.js
@@ -9,41 +9,12 @@ import Motion from 'mastodon/features/ui/util/optional_motion';
 import spring from 'react-motion/lib/spring';
 import escapeTextContentForBrowser from 'escape-html';
 import emojify from 'mastodon/features/emoji/emoji';
+import RelativeTimestamp from './relative_timestamp';
 
 const messages = defineMessages({
-  moments: { id: 'time_remaining.moments', defaultMessage: 'Moments remaining' },
-  seconds: { id: 'time_remaining.seconds', defaultMessage: '{number, plural, one {# second} other {# seconds}} left' },
-  minutes: { id: 'time_remaining.minutes', defaultMessage: '{number, plural, one {# minute} other {# minutes}} left' },
-  hours: { id: 'time_remaining.hours', defaultMessage: '{number, plural, one {# hour} other {# hours}} left' },
-  days: { id: 'time_remaining.days', defaultMessage: '{number, plural, one {# day} other {# days}} left' },
   closed: { id: 'poll.closed', defaultMessage: 'Closed' },
 });
 
-const SECOND = 1000;
-const MINUTE = 1000 * 60;
-const HOUR   = 1000 * 60 * 60;
-const DAY    = 1000 * 60 * 60 * 24;
-
-const timeRemainingString = (intl, date, now) => {
-  const delta = date.getTime() - now;
-
-  let relativeTime;
-
-  if (delta < 10 * SECOND) {
-    relativeTime = intl.formatMessage(messages.moments);
-  } else if (delta < MINUTE) {
-    relativeTime = intl.formatMessage(messages.seconds, { number: Math.floor(delta / SECOND) });
-  } else if (delta < HOUR) {
-    relativeTime = intl.formatMessage(messages.minutes, { number: Math.floor(delta / MINUTE) });
-  } else if (delta < DAY) {
-    relativeTime = intl.formatMessage(messages.hours, { number: Math.floor(delta / HOUR) });
-  } else {
-    relativeTime = intl.formatMessage(messages.days, { number: Math.floor(delta / DAY) });
-  }
-
-  return relativeTime;
-};
-
 const makeEmojiMap = record => record.get('emojis').reduce((obj, emoji) => {
   obj[`:${emoji.get('shortcode')}:`] = emoji.toJS();
   return obj;
@@ -146,7 +117,7 @@ class Poll extends ImmutablePureComponent {
       return null;
     }
 
-    const timeRemaining = poll.get('expired') ? intl.formatMessage(messages.closed) : timeRemainingString(intl, new Date(poll.get('expires_at')), intl.now());
+    const timeRemaining = poll.get('expired') ? intl.formatMessage(messages.closed) : <RelativeTimestamp timestamp={poll.get('expires_at')} futureDate />;
     const showResults   = poll.get('voted') || poll.get('expired');
     const disabled      = this.props.disabled || Object.entries(this.state.selected).every(item => !item);
 
diff --git a/app/javascript/mastodon/components/relative_timestamp.js b/app/javascript/mastodon/components/relative_timestamp.js
index 57d99dd19..aa4b73cfe 100644
--- a/app/javascript/mastodon/components/relative_timestamp.js
+++ b/app/javascript/mastodon/components/relative_timestamp.js
@@ -8,6 +8,11 @@ const messages = defineMessages({
   minutes: { id: 'relative_time.minutes', defaultMessage: '{number}m' },
   hours: { id: 'relative_time.hours', defaultMessage: '{number}h' },
   days: { id: 'relative_time.days', defaultMessage: '{number}d' },
+  moments_remaining: { id: 'time_remaining.moments', defaultMessage: 'Moments remaining' },
+  seconds_remaining: { id: 'time_remaining.seconds', defaultMessage: '{number, plural, one {# second} other {# seconds}} left' },
+  minutes_remaining: { id: 'time_remaining.minutes', defaultMessage: '{number, plural, one {# minute} other {# minutes}} left' },
+  hours_remaining: { id: 'time_remaining.hours', defaultMessage: '{number, plural, one {# hour} other {# hours}} left' },
+  days_remaining: { id: 'time_remaining.days', defaultMessage: '{number, plural, one {# day} other {# days}} left' },
 });
 
 const dateFormatOptions = {
@@ -86,6 +91,26 @@ export const timeAgoString = (intl, date, now, year) => {
   return relativeTime;
 };
 
+const timeRemainingString = (intl, date, now) => {
+  const delta = date.getTime() - now;
+
+  let relativeTime;
+
+  if (delta < 10 * SECOND) {
+    relativeTime = intl.formatMessage(messages.moments_remaining);
+  } else if (delta < MINUTE) {
+    relativeTime = intl.formatMessage(messages.seconds_remaining, { number: Math.floor(delta / SECOND) });
+  } else if (delta < HOUR) {
+    relativeTime = intl.formatMessage(messages.minutes_remaining, { number: Math.floor(delta / MINUTE) });
+  } else if (delta < DAY) {
+    relativeTime = intl.formatMessage(messages.hours_remaining, { number: Math.floor(delta / HOUR) });
+  } else {
+    relativeTime = intl.formatMessage(messages.days_remaining, { number: Math.floor(delta / DAY) });
+  }
+
+  return relativeTime;
+};
+
 export default @injectIntl
 class RelativeTimestamp extends React.Component {
 
@@ -93,6 +118,7 @@ class RelativeTimestamp extends React.Component {
     intl: PropTypes.object.isRequired,
     timestamp: PropTypes.string.isRequired,
     year: PropTypes.number.isRequired,
+    futureDate: PropTypes.bool,
   };
 
   state = {
@@ -145,10 +171,10 @@ class RelativeTimestamp extends React.Component {
   }
 
   render () {
-    const { timestamp, intl, year } = this.props;
+    const { timestamp, intl, year, futureDate } = this.props;
 
     const date         = new Date(timestamp);
-    const relativeTime = timeAgoString(intl, date, this.state.now, year);
+    const relativeTime = futureDate ? timeRemainingString(intl, date, this.state.now) : timeAgoString(intl, date, this.state.now, year);
 
     return (
       <time dateTime={timestamp} title={intl.formatDate(date, dateFormatOptions)}>
diff --git a/app/javascript/mastodon/components/status.js b/app/javascript/mastodon/components/status.js
index e10faedf8..cea9a0c2e 100644
--- a/app/javascript/mastodon/components/status.js
+++ b/app/javascript/mastodon/components/status.js
@@ -351,7 +351,7 @@ class Status extends ImmutablePureComponent {
 
     return (
       <HotKeys handlers={handlers}>
-        <div className={classNames('status__wrapper', `status__wrapper-${status.get('visibility')}`, { 'status__wrapper-reply': !!status.get('in_reply_to_id'), read: unread === false, focusable: !this.props.muted })} tabIndex={this.props.muted ? null : 0} data-featured={featured ? 'true' : null} aria-label={textForScreenReader(intl, status, rebloggedByText, !status.get('hidden'))} ref={this.handleRef}>
+        <div className={classNames('status__wrapper', `status__wrapper-${status.get('visibility')}`, { 'status__wrapper-reply': !!status.get('in_reply_to_id'), read: unread === false, focusable: !this.props.muted })} tabIndex={this.props.muted ? null : 0} data-featured={featured ? 'true' : null} aria-label={textForScreenReader(intl, status, rebloggedByText)} ref={this.handleRef}>
           {prepend}
 
           <div className={classNames('status', `status-${status.get('visibility')}`, { 'status-reply': !!status.get('in_reply_to_id'), muted: this.props.muted, read: unread === false })} data-id={status.get('id')}>
diff --git a/app/javascript/mastodon/features/account/components/header.js b/app/javascript/mastodon/features/account/components/header.js
index 9d15bc28f..e5b60e33e 100644
--- a/app/javascript/mastodon/features/account/components/header.js
+++ b/app/javascript/mastodon/features/account/components/header.js
@@ -22,8 +22,6 @@ const messages = defineMessages({
   account_locked: { id: 'account.locked_info', defaultMessage: 'This account privacy status is set to locked. The owner manually reviews who can follow them.' },
   mention: { id: 'account.mention', defaultMessage: 'Mention @{name}' },
   direct: { id: 'account.direct', defaultMessage: 'Direct message @{name}' },
-  edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' },
-  unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' },
   unmute: { id: 'account.unmute', defaultMessage: 'Unmute @{name}' },
   block: { id: 'account.block', defaultMessage: 'Block @{name}' },
   mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' },
@@ -111,7 +109,7 @@ class Header extends ImmutablePureComponent {
       } else if (account.getIn(['relationship', 'requested'])) {
         actionBtn = <Button className='logo-button' text={intl.formatMessage(messages.requested)} onClick={this.props.onFollow} />;
       } else if (!account.getIn(['relationship', 'blocking'])) {
-        actionBtn = <Button className={classNames('logo-button', { 'button--destructive': account.getIn(['relationship', 'following']) })} text={intl.formatMessage(account.getIn(['relationship', 'following']) ? messages.unfollow : messages.follow)} onClick={this.props.onFollow} />;
+        actionBtn = <Button disabled={account.getIn(['relationship', 'blocked_by'])} className={classNames('logo-button', { 'button--destructive': account.getIn(['relationship', 'following']) })} text={intl.formatMessage(account.getIn(['relationship', 'following']) ? messages.unfollow : messages.follow)} onClick={this.props.onFollow} />;
       } else if (account.getIn(['relationship', 'blocking'])) {
         actionBtn = <Button className='logo-button' text={intl.formatMessage(messages.unblock, { name: account.get('username') })} onClick={this.props.onBlock} />;
       }
diff --git a/app/javascript/mastodon/features/account_gallery/index.js b/app/javascript/mastodon/features/account_gallery/index.js
index 96051818b..73be58d6a 100644
--- a/app/javascript/mastodon/features/account_gallery/index.js
+++ b/app/javascript/mastodon/features/account_gallery/index.js
@@ -13,8 +13,10 @@ import MediaItem from './components/media_item';
 import HeaderContainer from '../account_timeline/containers/header_container';
 import { ScrollContainer } from 'react-router-scroll-4';
 import LoadMore from '../../components/load_more';
+import MissingIndicator from 'mastodon/components/missing_indicator';
 
 const mapStateToProps = (state, props) => ({
+  isAccount: !!state.getIn(['accounts', props.params.accountId]),
   medias: getAccountGallery(state, props.params.accountId),
   isLoading: state.getIn(['timelines', `account:${props.params.accountId}:media`, 'isLoading']),
   hasMore:   state.getIn(['timelines', `account:${props.params.accountId}:media`, 'hasMore']),
@@ -52,6 +54,7 @@ class AccountGallery extends ImmutablePureComponent {
     medias: ImmutablePropTypes.list.isRequired,
     isLoading: PropTypes.bool,
     hasMore: PropTypes.bool,
+    isAccount: PropTypes.bool,
   };
 
   componentDidMount () {
@@ -91,7 +94,15 @@ class AccountGallery extends ImmutablePureComponent {
   }
 
   render () {
-    const { medias, shouldUpdateScroll, isLoading, hasMore } = this.props;
+    const { medias, shouldUpdateScroll, isLoading, hasMore, isAccount } = this.props;
+
+    if (!isAccount) {
+      return (
+        <Column>
+          <MissingIndicator />
+        </Column>
+      );
+    }
 
     let loadOlder = null;
 
diff --git a/app/javascript/mastodon/features/account_timeline/components/header.js b/app/javascript/mastodon/features/account_timeline/components/header.js
index 27dfcc516..844b8a236 100644
--- a/app/javascript/mastodon/features/account_timeline/components/header.js
+++ b/app/javascript/mastodon/features/account_timeline/components/header.js
@@ -2,7 +2,6 @@ import React from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import InnerHeader from '../../account/components/header';
-import MissingIndicator from '../../../components/missing_indicator';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import MovedNote from './moved_note';
 import { FormattedMessage } from 'react-intl';
@@ -88,7 +87,7 @@ export default class Header extends ImmutablePureComponent {
     const { account, hideTabs, identity_proofs } = this.props;
 
     if (account === null) {
-      return <MissingIndicator />;
+      return null;
     }
 
     return (
diff --git a/app/javascript/mastodon/features/account_timeline/index.js b/app/javascript/mastodon/features/account_timeline/index.js
index 883f40d77..27581bfdc 100644
--- a/app/javascript/mastodon/features/account_timeline/index.js
+++ b/app/javascript/mastodon/features/account_timeline/index.js
@@ -13,15 +13,20 @@ import { List as ImmutableList } from 'immutable';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import { FormattedMessage } from 'react-intl';
 import { fetchAccountIdentityProofs } from '../../actions/identity_proofs';
+import MissingIndicator from 'mastodon/components/missing_indicator';
+
+const emptyList = ImmutableList();
 
 const mapStateToProps = (state, { params: { accountId }, withReplies = false }) => {
   const path = withReplies ? `${accountId}:with_replies` : accountId;
 
   return {
-    statusIds: state.getIn(['timelines', `account:${path}`, 'items'], ImmutableList()),
-    featuredStatusIds: withReplies ? ImmutableList() : state.getIn(['timelines', `account:${accountId}:pinned`, 'items'], ImmutableList()),
+    isAccount: !!state.getIn(['accounts', accountId]),
+    statusIds: state.getIn(['timelines', `account:${path}`, 'items'], emptyList),
+    featuredStatusIds: withReplies ? ImmutableList() : state.getIn(['timelines', `account:${accountId}:pinned`, 'items'], emptyList),
     isLoading: state.getIn(['timelines', `account:${path}`, 'isLoading']),
-    hasMore:   state.getIn(['timelines', `account:${path}`, 'hasMore']),
+    hasMore: state.getIn(['timelines', `account:${path}`, 'hasMore']),
+    blockedBy: state.getIn(['relationships', accountId, 'blocked_by'], false),
   };
 };
 
@@ -37,6 +42,8 @@ class AccountTimeline extends ImmutablePureComponent {
     isLoading: PropTypes.bool,
     hasMore: PropTypes.bool,
     withReplies: PropTypes.bool,
+    blockedBy: PropTypes.bool,
+    isAccount: PropTypes.bool,
   };
 
   componentWillMount () {
@@ -44,9 +51,11 @@ class AccountTimeline extends ImmutablePureComponent {
 
     this.props.dispatch(fetchAccount(accountId));
     this.props.dispatch(fetchAccountIdentityProofs(accountId));
+
     if (!withReplies) {
       this.props.dispatch(expandAccountFeaturedTimeline(accountId));
     }
+
     this.props.dispatch(expandAccountTimeline(accountId, { withReplies }));
   }
 
@@ -54,9 +63,11 @@ class AccountTimeline extends ImmutablePureComponent {
     if ((nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) || nextProps.withReplies !== this.props.withReplies) {
       this.props.dispatch(fetchAccount(nextProps.params.accountId));
       this.props.dispatch(fetchAccountIdentityProofs(nextProps.params.accountId));
+
       if (!nextProps.withReplies) {
         this.props.dispatch(expandAccountFeaturedTimeline(nextProps.params.accountId));
       }
+
       this.props.dispatch(expandAccountTimeline(nextProps.params.accountId, { withReplies: nextProps.params.withReplies }));
     }
   }
@@ -66,7 +77,15 @@ class AccountTimeline extends ImmutablePureComponent {
   }
 
   render () {
-    const { shouldUpdateScroll, statusIds, featuredStatusIds, isLoading, hasMore } = this.props;
+    const { shouldUpdateScroll, statusIds, featuredStatusIds, isLoading, hasMore, blockedBy, isAccount } = this.props;
+
+    if (!isAccount) {
+      return (
+        <Column>
+          <MissingIndicator />
+        </Column>
+      );
+    }
 
     if (!statusIds && isLoading) {
       return (
@@ -76,6 +95,8 @@ class AccountTimeline extends ImmutablePureComponent {
       );
     }
 
+    const emptyMessage = blockedBy ? <FormattedMessage id='empty_column.account_unavailable' defaultMessage='Profile unavailable' /> : <FormattedMessage id='empty_column.account_timeline' defaultMessage='No toots here!' />;
+
     return (
       <Column>
         <ColumnBackButton />
@@ -84,13 +105,13 @@ class AccountTimeline extends ImmutablePureComponent {
           prepend={<HeaderContainer accountId={this.props.params.accountId} />}
           alwaysPrepend
           scrollKey='account_timeline'
-          statusIds={statusIds}
+          statusIds={blockedBy ? emptyList : statusIds}
           featuredStatusIds={featuredStatusIds}
           isLoading={isLoading}
           hasMore={hasMore}
           onLoadMore={this.handleLoadMore}
           shouldUpdateScroll={shouldUpdateScroll}
-          emptyMessage={<FormattedMessage id='empty_column.account_timeline' defaultMessage='No toots here!' />}
+          emptyMessage={emptyMessage}
         />
       </Column>
     );
diff --git a/app/javascript/mastodon/features/followers/index.js b/app/javascript/mastodon/features/followers/index.js
index ce56f270c..e3387e1be 100644
--- a/app/javascript/mastodon/features/followers/index.js
+++ b/app/javascript/mastodon/features/followers/index.js
@@ -16,10 +16,13 @@ import Column from '../ui/components/column';
 import HeaderContainer from '../account_timeline/containers/header_container';
 import ColumnBackButton from '../../components/column_back_button';
 import ScrollableList from '../../components/scrollable_list';
+import MissingIndicator from 'mastodon/components/missing_indicator';
 
 const mapStateToProps = (state, props) => ({
+  isAccount: !!state.getIn(['accounts', props.params.accountId]),
   accountIds: state.getIn(['user_lists', 'followers', props.params.accountId, 'items']),
   hasMore: !!state.getIn(['user_lists', 'followers', props.params.accountId, 'next']),
+  blockedBy: state.getIn(['relationships', props.params.accountId, 'blocked_by'], false),
 });
 
 export default @connect(mapStateToProps)
@@ -31,6 +34,8 @@ class Followers extends ImmutablePureComponent {
     shouldUpdateScroll: PropTypes.func,
     accountIds: ImmutablePropTypes.list,
     hasMore: PropTypes.bool,
+    blockedBy: PropTypes.bool,
+    isAccount: PropTypes.bool,
   };
 
   componentWillMount () {
@@ -50,7 +55,15 @@ class Followers extends ImmutablePureComponent {
   }, 300, { leading: true });
 
   render () {
-    const { shouldUpdateScroll, accountIds, hasMore } = this.props;
+    const { shouldUpdateScroll, accountIds, hasMore, blockedBy, isAccount } = this.props;
+
+    if (!isAccount) {
+      return (
+        <Column>
+          <MissingIndicator />
+        </Column>
+      );
+    }
 
     if (!accountIds) {
       return (
@@ -60,7 +73,7 @@ class Followers extends ImmutablePureComponent {
       );
     }
 
-    const emptyMessage = <FormattedMessage id='account.followers.empty' defaultMessage='No one follows this user yet.' />;
+    const emptyMessage = blockedBy ? <FormattedMessage id='empty_column.account_unavailable' defaultMessage='Profile unavailable' /> : <FormattedMessage id='account.followers.empty' defaultMessage='No one follows this user yet.' />;
 
     return (
       <Column>
@@ -75,7 +88,7 @@ class Followers extends ImmutablePureComponent {
           alwaysPrepend
           emptyMessage={emptyMessage}
         >
-          {accountIds.map(id =>
+          {blockedBy ? [] : accountIds.map(id =>
             <AccountContainer key={id} id={id} withNote={false} />
           )}
         </ScrollableList>
diff --git a/app/javascript/mastodon/features/following/index.js b/app/javascript/mastodon/features/following/index.js
index bda0438a0..3bf89fb2b 100644
--- a/app/javascript/mastodon/features/following/index.js
+++ b/app/javascript/mastodon/features/following/index.js
@@ -16,10 +16,13 @@ import Column from '../ui/components/column';
 import HeaderContainer from '../account_timeline/containers/header_container';
 import ColumnBackButton from '../../components/column_back_button';
 import ScrollableList from '../../components/scrollable_list';
+import MissingIndicator from 'mastodon/components/missing_indicator';
 
 const mapStateToProps = (state, props) => ({
+  isAccount: !!state.getIn(['accounts', props.params.accountId]),
   accountIds: state.getIn(['user_lists', 'following', props.params.accountId, 'items']),
   hasMore: !!state.getIn(['user_lists', 'following', props.params.accountId, 'next']),
+  blockedBy: state.getIn(['relationships', props.params.accountId, 'blocked_by'], false),
 });
 
 export default @connect(mapStateToProps)
@@ -31,6 +34,8 @@ class Following extends ImmutablePureComponent {
     shouldUpdateScroll: PropTypes.func,
     accountIds: ImmutablePropTypes.list,
     hasMore: PropTypes.bool,
+    blockedBy: PropTypes.bool,
+    isAccount: PropTypes.bool,
   };
 
   componentWillMount () {
@@ -50,7 +55,15 @@ class Following extends ImmutablePureComponent {
   }, 300, { leading: true });
 
   render () {
-    const { shouldUpdateScroll, accountIds, hasMore } = this.props;
+    const { shouldUpdateScroll, accountIds, hasMore, blockedBy, isAccount } = this.props;
+
+    if (!isAccount) {
+      return (
+        <Column>
+          <MissingIndicator />
+        </Column>
+      );
+    }
 
     if (!accountIds) {
       return (
@@ -60,7 +73,7 @@ class Following extends ImmutablePureComponent {
       );
     }
 
-    const emptyMessage = <FormattedMessage id='account.follows.empty' defaultMessage="This user doesn't follow anyone yet." />;
+    const emptyMessage = blockedBy ? <FormattedMessage id='empty_column.account_unavailable' defaultMessage='Profile unavailable' /> : <FormattedMessage id='account.follows.empty' defaultMessage="This user doesn't follow anyone yet." />;
 
     return (
       <Column>
@@ -75,7 +88,7 @@ class Following extends ImmutablePureComponent {
           alwaysPrepend
           emptyMessage={emptyMessage}
         >
-          {accountIds.map(id =>
+          {blockedBy ? [] : accountIds.map(id =>
             <AccountContainer key={id} id={id} withNote={false} />
           )}
         </ScrollableList>
diff --git a/app/javascript/mastodon/features/status/index.js b/app/javascript/mastodon/features/status/index.js
index c0ea460e8..567af6be9 100644
--- a/app/javascript/mastodon/features/status/index.js
+++ b/app/javascript/mastodon/features/status/index.js
@@ -442,7 +442,7 @@ class Status extends ImmutablePureComponent {
             {ancestors}
 
             <HotKeys handlers={handlers}>
-              <div className={classNames('focusable', 'detailed-status__wrapper')} tabIndex='0' aria-label={textForScreenReader(intl, status, false, !status.get('hidden'))}>
+              <div className={classNames('focusable', 'detailed-status__wrapper')} tabIndex='0' aria-label={textForScreenReader(intl, status, false)}>
                 <DetailedStatus
                   status={status}
                   onOpenVideo={this.handleOpenVideo}
diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json
index 6ed799941..e815d54d5 100644
--- a/app/javascript/mastodon/locales/ar.json
+++ b/app/javascript/mastodon/locales/ar.json
@@ -71,10 +71,10 @@
   "compose_form.lock_disclaimer": "حسابك ليس {locked}. يمكن لأي شخص متابعتك و عرض المنشورات.",
   "compose_form.lock_disclaimer.lock": "مقفل",
   "compose_form.placeholder": "فيمَ تفكّر؟",
-  "compose_form.poll.add_option": "Add a choice",
-  "compose_form.poll.duration": "Poll duration",
-  "compose_form.poll.option_placeholder": "Choice {number}",
-  "compose_form.poll.remove_option": "Remove this choice",
+  "compose_form.poll.add_option": "إضافة خيار",
+  "compose_form.poll.duration": "مدة استطلاع الرأي",
+  "compose_form.poll.option_placeholder": "الخيار {number}",
+  "compose_form.poll.remove_option": "إزالة هذا الخيار",
   "compose_form.publish": "بوّق",
   "compose_form.publish_loud": "{publish}!",
   "compose_form.sensitive.marked": "لقد تم تحديد هذه الصورة كحساسة",
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "رموز",
   "emoji_button.travel": "أماكن و أسفار",
   "empty_column.account_timeline": "ليس هناك تبويقات!",
+  "empty_column.account_unavailable": "الملف الشخصي غير متوفر",
   "empty_column.blocks": "لم تقم بحظر أي مستخدِم بعد.",
   "empty_column.community": "الخط الزمني المحلي فارغ. أكتب شيئا ما للعامة كبداية !",
   "empty_column.direct": "لم تتلق أية رسالة خاصة مباشِرة بعد. سوف يتم عرض الرسائل المباشرة هنا إن قمت بإرسال واحدة أو تلقيت البعض منها.",
@@ -150,7 +151,7 @@
   "hashtag.column_settings.tag_mode.all": "كلها",
   "hashtag.column_settings.tag_mode.any": "أي كان مِن هذه",
   "hashtag.column_settings.tag_mode.none": "لا شيء مِن هذه",
-  "hashtag.column_settings.tag_toggle": "Include additional tags in this column",
+  "hashtag.column_settings.tag_toggle": "إدراج الوسوم الإضافية لهذا العمود",
   "home.column_settings.basic": "أساسية",
   "home.column_settings.show_reblogs": "عرض الترقيات",
   "home.column_settings.show_replies": "عرض الردود",
@@ -257,7 +258,7 @@
   "notifications.column_settings.filter_bar.show": "عرض",
   "notifications.column_settings.follow": "متابعُون جُدُد :",
   "notifications.column_settings.mention": "الإشارات :",
-  "notifications.column_settings.poll": "Poll results:",
+  "notifications.column_settings.poll": "نتائج استطلاع الرأي:",
   "notifications.column_settings.push": "الإخطارات المدفوعة",
   "notifications.column_settings.reblog": "الترقيّات:",
   "notifications.column_settings.show": "إعرِضها في عمود",
@@ -267,14 +268,14 @@
   "notifications.filter.favourites": "المفضلة",
   "notifications.filter.follows": "يتابِع",
   "notifications.filter.mentions": "الإشارات",
-  "notifications.filter.polls": "Poll results",
+  "notifications.filter.polls": "نتائج استطلاع الرأي",
   "notifications.group": "{count} إشعارات",
-  "poll.closed": "Closed",
-  "poll.refresh": "Refresh",
+  "poll.closed": "انتهى",
+  "poll.refresh": "تحديث",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
-  "poll.vote": "Vote",
-  "poll_button.add_poll": "Add a poll",
-  "poll_button.remove_poll": "Remove poll",
+  "poll.vote": "صَوّت",
+  "poll_button.add_poll": "إضافة استطلاع للرأي",
+  "poll_button.remove_poll": "إزالة استطلاع الرأي",
   "privacy.change": "إضبط خصوصية المنشور",
   "privacy.direct.long": "أنشر إلى المستخدمين المشار إليهم فقط",
   "privacy.direct.short": "مباشر",
@@ -366,7 +367,7 @@
   "upload_area.title": "إسحب ثم أفلت للرفع",
   "upload_button.label": "إضافة وسائط (JPEG، PNG، GIF، WebM، MP4، MOV)",
   "upload_error.limit": "لقد تم بلوغ الحد الأقصى المسموح به لإرسال الملفات.",
-  "upload_error.poll": "File upload not allowed with polls.",
+  "upload_error.poll": "لا يمكن إدراج ملفات في استطلاعات الرأي.",
   "upload_form.description": "وصف للمعاقين بصريا",
   "upload_form.focus": "قص",
   "upload_form.undo": "حذف",
diff --git a/app/javascript/mastodon/locales/ast.json b/app/javascript/mastodon/locales/ast.json
index a341567a7..a983f63a4 100644
--- a/app/javascript/mastodon/locales/ast.json
+++ b/app/javascript/mastodon/locales/ast.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Símbolos",
   "emoji_button.travel": "Viaxes y llugares",
   "empty_column.account_timeline": "No toots here!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "Entá nun bloquiesti a dengún usuariu.",
   "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
   "empty_column.direct": "Entá nun tienes dengún mensaxe direutu. Cuando unvies o recibas dalgún, va apaecer equí.",
diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json
index 49e043582..36a08b264 100644
--- a/app/javascript/mastodon/locales/bg.json
+++ b/app/javascript/mastodon/locales/bg.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Symbols",
   "emoji_button.travel": "Travel & Places",
   "empty_column.account_timeline": "No toots here!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "You haven't blocked any users yet.",
   "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
   "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
diff --git a/app/javascript/mastodon/locales/bn.json b/app/javascript/mastodon/locales/bn.json
index 0d095bdeb..338e49f81 100644
--- a/app/javascript/mastodon/locales/bn.json
+++ b/app/javascript/mastodon/locales/bn.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Symbols",
   "emoji_button.travel": "Travel & Places",
   "empty_column.account_timeline": "No toots here!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "You haven't blocked any users yet.",
   "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
   "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json
index 6c98c6ae7..18dd56d0d 100644
--- a/app/javascript/mastodon/locales/ca.json
+++ b/app/javascript/mastodon/locales/ca.json
@@ -71,10 +71,10 @@
   "compose_form.lock_disclaimer": "El teu compte no està bloquejat {locked}. Tothom pot seguir-te i veure els teus missatges a seguidors.",
   "compose_form.lock_disclaimer.lock": "blocat",
   "compose_form.placeholder": "En què estàs pensant?",
-  "compose_form.poll.add_option": "Add a choice",
-  "compose_form.poll.duration": "Poll duration",
-  "compose_form.poll.option_placeholder": "Choice {number}",
-  "compose_form.poll.remove_option": "Remove this choice",
+  "compose_form.poll.add_option": "Afegeix una opció",
+  "compose_form.poll.duration": "Durada de l'enquesta",
+  "compose_form.poll.option_placeholder": "Opció {number}",
+  "compose_form.poll.remove_option": "Elimina aquesta opció",
   "compose_form.publish": "Toot",
   "compose_form.publish_loud": "{publish}!",
   "compose_form.sensitive.marked": "Mèdia marcat com a sensible",
@@ -108,7 +108,7 @@
   "emoji_button.food": "Menjar i beure",
   "emoji_button.label": "Insereix un emoji",
   "emoji_button.nature": "Natura",
-  "emoji_button.not_found": "Emojos no!! (╯°□°)╯︵ ┻━┻",
+  "emoji_button.not_found": "Emojis no!! (╯°□°)╯︵ ┻━┻",
   "emoji_button.objects": "Objectes",
   "emoji_button.people": "Gent",
   "emoji_button.recent": "Usats freqüentment",
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Símbols",
   "emoji_button.travel": "Viatges i Llocs",
   "empty_column.account_timeline": "No hi ha toots aquí!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "Encara no has bloquejat cap usuari.",
   "empty_column.community": "La línia de temps local és buida. Escriu alguna cosa públicament per fer rodar la pilota!",
   "empty_column.direct": "Encara no tens missatges directes. Quan enviïs o rebis un, es mostrarà aquí.",
@@ -154,8 +155,8 @@
   "home.column_settings.basic": "Bàsic",
   "home.column_settings.show_reblogs": "Mostrar impulsos",
   "home.column_settings.show_replies": "Mostrar respostes",
-  "intervals.full.days": "{number, plural, one {# day} other {# days}}",
-  "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
+  "intervals.full.days": "{number, plural, one {# dia} other {# dies}}",
+  "intervals.full.hours": "{number, plural, one {# hora} other {# hores}}",
   "intervals.full.minutes": "{number, plural, one {# minut} other {# minuts}}",
   "introduction.federation.action": "Següent",
   "introduction.federation.federated.headline": "Federada",
@@ -179,14 +180,14 @@
   "keyboard_shortcuts.boost": "impulsar",
   "keyboard_shortcuts.column": "per centrar un estat en una de les columnes",
   "keyboard_shortcuts.compose": "per centrar l'area de composició de text",
-  "keyboard_shortcuts.description": "Description",
+  "keyboard_shortcuts.description": "Descripció",
   "keyboard_shortcuts.direct": "per obrir la columna de missatges directes",
   "keyboard_shortcuts.down": "per baixar en la llista",
   "keyboard_shortcuts.enter": "ampliar estat",
   "keyboard_shortcuts.favourite": "afavorir",
   "keyboard_shortcuts.favourites": "per obrir la llista de favorits",
   "keyboard_shortcuts.federated": "per obrir la línia de temps federada",
-  "keyboard_shortcuts.heading": "Keyboard Shortcuts",
+  "keyboard_shortcuts.heading": "Dreçeres de teclat",
   "keyboard_shortcuts.home": "per obrir la línia de temps Inici",
   "keyboard_shortcuts.hotkey": "Tecla d'accés directe",
   "keyboard_shortcuts.legend": "per a mostrar aquesta llegenda",
@@ -247,7 +248,7 @@
   "notification.follow": "{name} et segueix",
   "notification.mention": "{name} t'ha esmentat",
   "notification.poll": "Ha finalitzat una enquesta en la que has votat",
-  "notification.reblog": "{name} ha retootejat el teu estat",
+  "notification.reblog": "{name} ha impulsat el teu estat",
   "notifications.clear": "Netejar notificacions",
   "notifications.clear_confirmation": "Estàs segur que vols esborrar permanenment totes les teves notificacions?",
   "notifications.column_settings.alert": "Notificacions d'escriptori",
@@ -258,7 +259,7 @@
   "notifications.column_settings.follow": "Nous seguidors:",
   "notifications.column_settings.mention": "Mencions:",
   "notifications.column_settings.poll": "Resultats de l’enquesta:",
-  "notifications.column_settings.push": "Push notificacions",
+  "notifications.column_settings.push": "Notificacions push",
   "notifications.column_settings.reblog": "Impulsos:",
   "notifications.column_settings.show": "Mostrar en la columna",
   "notifications.column_settings.sound": "Reproduïr so",
@@ -273,8 +274,8 @@
   "poll.refresh": "Actualitza",
   "poll.total_votes": "{count, plural, one {# vot} other {# vots}}",
   "poll.vote": "Vota",
-  "poll_button.add_poll": "Add a poll",
-  "poll_button.remove_poll": "Remove poll",
+  "poll_button.add_poll": "Afegeix una enquesta",
+  "poll_button.remove_poll": "Elimina l'enquesta",
   "privacy.change": "Ajusta l'estat de privacitat",
   "privacy.direct.long": "Publicar només per als usuaris esmentats",
   "privacy.direct.short": "Directe",
@@ -311,9 +312,9 @@
   "search_results.total": "{count, number} {count, plural, un {result} altres {results}}",
   "status.admin_account": "Obre l'interfície de moderació per a @{name}",
   "status.admin_status": "Obre aquest estat a la interfície de moderació",
-  "status.block": "Block @{name}",
+  "status.block": "Bloqueja @{name}",
   "status.cancel_reblog_private": "Desfer l'impuls",
-  "status.cannot_reblog": "Aquesta publicació no pot ser retootejada",
+  "status.cannot_reblog": "Aquesta publicació no pot ser impulsada",
   "status.copy": "Copia l'enllaç a l'estat",
   "status.delete": "Esborrar",
   "status.detailed_status": "Visualització detallada de la conversa",
@@ -333,7 +334,7 @@
   "status.read_more": "Llegir més",
   "status.reblog": "Impuls",
   "status.reblog_private": "Impulsar a l'audiència original",
-  "status.reblogged_by": "{name} ha retootejat",
+  "status.reblogged_by": "{name} ha impulsat",
   "status.reblogs.empty": "Encara ningú no ha impulsat aquest toot. Quan algú ho faci, apareixeran aquí.",
   "status.redraft": "Esborrar i reescriure",
   "status.reply": "Respondre",
@@ -366,7 +367,7 @@
   "upload_area.title": "Arrossega i deixa anar per carregar",
   "upload_button.label": "Afegir multimèdia (JPEG, PNG, GIF, WebM, MP4, MOV)",
   "upload_error.limit": "S'ha superat el límit de càrrega d'arxius.",
-  "upload_error.poll": "File upload not allowed with polls.",
+  "upload_error.poll": "No es permet l'enviament de fitxers amb les enquestes.",
   "upload_form.description": "Descriure els problemes visuals",
   "upload_form.focus": "Modificar la previsualització",
   "upload_form.undo": "Esborra",
diff --git a/app/javascript/mastodon/locales/co.json b/app/javascript/mastodon/locales/co.json
index 154feab98..016be39b3 100644
--- a/app/javascript/mastodon/locales/co.json
+++ b/app/javascript/mastodon/locales/co.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Simbuli",
   "emoji_button.travel": "Lochi è Viaghju",
   "empty_column.account_timeline": "Nisun statutu quì!",
+  "empty_column.account_unavailable": "Prufile micca dispunibule",
   "empty_column.blocks": "Per avà ùn avete bluccatu manc'un utilizatore.",
   "empty_column.community": "Ùn c'hè nunda indè a linea lucale. Scrivete puru qualcosa!",
   "empty_column.direct": "Ùn avete ancu nisun missaghju direttu. S'è voi mandate o ricevete unu, u vidarete quì.",
diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json
index e711961e7..f98ea7f26 100644
--- a/app/javascript/mastodon/locales/cs.json
+++ b/app/javascript/mastodon/locales/cs.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Symboly",
   "emoji_button.travel": "Cestování a místa",
   "empty_column.account_timeline": "Tady nejsou žádné tooty!",
+  "empty_column.account_unavailable": "Profil nedostupný",
   "empty_column.blocks": "Ještě jste nezablokoval/a žádného uživatele.",
   "empty_column.community": "Místní časová osa je prázdná. Napište něco veřejně a rozhýbejte to tu!",
   "empty_column.direct": "Ještě nemáte žádné přímé zprávy. Pokud nějakou pošlete nebo dostanete, zobrazí se zde.",
@@ -318,7 +319,7 @@
   "status.delete": "Smazat",
   "status.detailed_status": "Detailní zobrazení konverzace",
   "status.direct": "Poslat přímou zprávu uživateli @{name}",
-  "status.embed": "Vložit",
+  "status.embed": "Vložit na web",
   "status.favourite": "Oblíbit",
   "status.filtered": "Filtrováno",
   "status.load_more": "Zobrazit více",
@@ -327,7 +328,7 @@
   "status.more": "Více",
   "status.mute": "Skrýt uživatele @{name}",
   "status.mute_conversation": "Skrýt konverzaci",
-  "status.open": "Rozbalit tento toot",
+  "status.open": "Otevřít tento toot",
   "status.pin": "Připnout na profil",
   "status.pinned": "Připnutý toot",
   "status.read_more": "Číst více",
@@ -350,7 +351,7 @@
   "status.unmute_conversation": "Odkrýt konverzaci",
   "status.unpin": "Odepnout z profilu",
   "suggestions.dismiss": "Odmítnout návrh",
-  "suggestions.header": "Mohlo by vás zajímat…",
+  "suggestions.header": "Mohli by vás zajímat…",
   "tabs_bar.federated_timeline": "Federovaná",
   "tabs_bar.home": "Domů",
   "tabs_bar.local_timeline": "Místní",
diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json
index f03b54750..d886b2b54 100644
--- a/app/javascript/mastodon/locales/cy.json
+++ b/app/javascript/mastodon/locales/cy.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Symbolau",
   "emoji_button.travel": "Teithio & Llefydd",
   "empty_column.account_timeline": "No toots here!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "Nid ydych wedi blocio unrhyw ddefnyddwyr eto.",
   "empty_column.community": "Mae'r ffrwd lleol yn wag. Ysgrifenwch rhywbeth yn gyhoeddus i gael dechrau arni!",
   "empty_column.direct": "Nid oes gennych unrhyw negeseuon preifat eto. Pan y byddwch yn anfon neu derbyn un, mi fydd yn ymddangos yma.",
diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json
index 1be8d989d..89096b29b 100644
--- a/app/javascript/mastodon/locales/da.json
+++ b/app/javascript/mastodon/locales/da.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Symboler",
   "emoji_button.travel": "Rejser & steder",
   "empty_column.account_timeline": "Ingen bidrag her!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "Du har ikke blokeret nogen endnu.",
   "empty_column.community": "Den lokale tidslinje er tom. Skriv noget offentligt for at starte lavinen!",
   "empty_column.direct": "Du har endnu ingen direkte beskeder. Når du sender eller modtager en, vil den vises her.",
diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json
index a335af1bd..13b8ccafa 100644
--- a/app/javascript/mastodon/locales/de.json
+++ b/app/javascript/mastodon/locales/de.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Symbole",
   "emoji_button.travel": "Reisen und Orte",
   "empty_column.account_timeline": "Keine Beiträge!",
+  "empty_column.account_unavailable": "Konto nicht verfügbar",
   "empty_column.blocks": "Du hast keine Profile blockiert.",
   "empty_column.community": "Die lokale Zeitleiste ist leer. Schreibe einen öffentlichen Beitrag, um den Ball ins Rollen zu bringen!",
   "empty_column.direct": "Du hast noch keine Direktnachrichten erhalten. Wenn du eine sendest oder empfängst, wird sie hier zu sehen sein.",
diff --git a/app/javascript/mastodon/locales/defaultMessages.json b/app/javascript/mastodon/locales/defaultMessages.json
index 951745120..76d4351d0 100644
--- a/app/javascript/mastodon/locales/defaultMessages.json
+++ b/app/javascript/mastodon/locales/defaultMessages.json
@@ -204,26 +204,6 @@
   {
     "descriptors": [
       {
-        "defaultMessage": "Moments remaining",
-        "id": "time_remaining.moments"
-      },
-      {
-        "defaultMessage": "{number, plural, one {# second} other {# seconds}} left",
-        "id": "time_remaining.seconds"
-      },
-      {
-        "defaultMessage": "{number, plural, one {# minute} other {# minutes}} left",
-        "id": "time_remaining.minutes"
-      },
-      {
-        "defaultMessage": "{number, plural, one {# hour} other {# hours}} left",
-        "id": "time_remaining.hours"
-      },
-      {
-        "defaultMessage": "{number, plural, one {# day} other {# days}} left",
-        "id": "time_remaining.days"
-      },
-      {
         "defaultMessage": "Closed",
         "id": "poll.closed"
       },
@@ -263,6 +243,26 @@
       {
         "defaultMessage": "{number}d",
         "id": "relative_time.days"
+      },
+      {
+        "defaultMessage": "Moments remaining",
+        "id": "time_remaining.moments"
+      },
+      {
+        "defaultMessage": "{number, plural, one {# second} other {# seconds}} left",
+        "id": "time_remaining.seconds"
+      },
+      {
+        "defaultMessage": "{number, plural, one {# minute} other {# minutes}} left",
+        "id": "time_remaining.minutes"
+      },
+      {
+        "defaultMessage": "{number, plural, one {# hour} other {# hours}} left",
+        "id": "time_remaining.hours"
+      },
+      {
+        "defaultMessage": "{number, plural, one {# day} other {# days}} left",
+        "id": "time_remaining.days"
       }
     ],
     "path": "app/javascript/mastodon/components/relative_timestamp.json"
@@ -552,8 +552,8 @@
   {
     "descriptors": [
       {
-        "defaultMessage": "You are blocked",
-        "id": "empty_column.account_timeline_blocked"
+        "defaultMessage": "Profile unavailable",
+        "id": "empty_column.account_unavailable"
       },
       {
         "defaultMessage": "No toots here!",
@@ -1256,8 +1256,8 @@
   {
     "descriptors": [
       {
-        "defaultMessage": "You are blocked",
-        "id": "empty_column.account_timeline_blocked"
+        "defaultMessage": "Profile unavailable",
+        "id": "empty_column.account_unavailable"
       },
       {
         "defaultMessage": "No one follows this user yet.",
@@ -1269,8 +1269,8 @@
   {
     "descriptors": [
       {
-        "defaultMessage": "You are blocked",
-        "id": "empty_column.account_timeline_blocked"
+        "defaultMessage": "Profile unavailable",
+        "id": "empty_column.account_unavailable"
       },
       {
         "defaultMessage": "This user doesn't follow anyone yet.",
diff --git a/app/javascript/mastodon/locales/el.json b/app/javascript/mastodon/locales/el.json
index 701410a81..69c0dcbad 100644
--- a/app/javascript/mastodon/locales/el.json
+++ b/app/javascript/mastodon/locales/el.json
@@ -71,10 +71,10 @@
   "compose_form.lock_disclaimer": "Ο λογαριασμός σου δεν είναι {locked}. Οποιοσδήποτε μπορεί να σε ακολουθήσει για να δει τις δημοσιεύσεις σας προς τους ακολούθους σας.",
   "compose_form.lock_disclaimer.lock": "κλειδωμένος",
   "compose_form.placeholder": "Τι σκέφτεσαι;",
-  "compose_form.poll.add_option": "Add a choice",
-  "compose_form.poll.duration": "Poll duration",
-  "compose_form.poll.option_placeholder": "Choice {number}",
-  "compose_form.poll.remove_option": "Remove this choice",
+  "compose_form.poll.add_option": "Προσθήκη επιλογής",
+  "compose_form.poll.duration": "Διάρκεια δημοσκόπησης",
+  "compose_form.poll.option_placeholder": "Επιλογή {number}",
+  "compose_form.poll.remove_option": "Αφαίρεση επιλογής",
   "compose_form.publish": "Τουτ",
   "compose_form.publish_loud": "{publish}!",
   "compose_form.sensitive.marked": "Το πολυμέσο έχει σημειωθεί ως ευαίσθητο",
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Σύμβολα",
   "emoji_button.travel": "Ταξίδια & Τοποθεσίες",
   "empty_column.account_timeline": "Δεν έχει τουτ εδώ!",
+  "empty_column.account_unavailable": "Μη διαθέσιμο προφίλ",
   "empty_column.blocks": "Δεν έχεις αποκλείσει κανέναν χρήστη ακόμα.",
   "empty_column.community": "Η τοπική ροή είναι κενή. Γράψε κάτι δημόσιο παραμύθι ν' αρχινίσει!",
   "empty_column.direct": "Δεν έχεις προσωπικά μηνύματα ακόμα. Όταν στείλεις ή λάβεις κανένα, θα εμφανιστεί εδώ.",
@@ -154,8 +155,8 @@
   "home.column_settings.basic": "Βασικά",
   "home.column_settings.show_reblogs": "Εμφάνιση προωθήσεων",
   "home.column_settings.show_replies": "Εμφάνιση απαντήσεων",
-  "intervals.full.days": "{number, plural, one {# day} other {# days}}",
-  "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
+  "intervals.full.days": "{number, plural, one {# μέρα} other {# μέρες}}",
+  "intervals.full.hours": "{number, plural, one {# ώρα} other {# ώρες}}",
   "intervals.full.minutes": "{number, plural, one {# λεπτό} other {# λεπτά}}",
   "introduction.federation.action": "Επόμενο",
   "introduction.federation.federated.headline": "Ομοσπονδιακή",
@@ -273,8 +274,8 @@
   "poll.refresh": "Ανανέωση",
   "poll.total_votes": "{count, plural, one {# ψήφος} other {# ψήφοι}}",
   "poll.vote": "Ψήφισε",
-  "poll_button.add_poll": "Add a poll",
-  "poll_button.remove_poll": "Remove poll",
+  "poll_button.add_poll": "Προσθήκη δημοσκόπησης",
+  "poll_button.remove_poll": "Αφαίρεση δημοσκόπησης",
   "privacy.change": "Προσαρμογή ιδιωτικότητας δημοσίευσης",
   "privacy.direct.long": "Δημοσίευση μόνο σε όσους και όσες αναφέρονται",
   "privacy.direct.short": "Προσωπικά",
@@ -366,7 +367,7 @@
   "upload_area.title": "Drag & drop για να ανεβάσεις",
   "upload_button.label": "Πρόσθεσε πολυμέσα (JPEG, PNG, GIF, WebM, MP4, MOV)",
   "upload_error.limit": "Υπέρβαση ορίου μεγέθους ανεβασμένων αρχείων.",
-  "upload_error.poll": "File upload not allowed with polls.",
+  "upload_error.poll": "Στις δημοσκοπήσεις δεν επιτρέπεται η μεταφόρτωση αρχείου.",
   "upload_form.description": "Περιέγραψε για όσους & όσες έχουν προβλήματα όρασης",
   "upload_form.focus": "Αλλαγή προεπισκόπησης",
   "upload_form.undo": "Διαγραφή",
diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json
index de3c3da9d..79e0c504b 100644
--- a/app/javascript/mastodon/locales/en.json
+++ b/app/javascript/mastodon/locales/en.json
@@ -121,7 +121,7 @@
   "emoji_button.symbols": "Symbols",
   "emoji_button.travel": "Travel & Places",
   "empty_column.account_timeline": "No toots here!",
-  "empty_column.account_timeline_blocked": "You are blocked",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "You haven't blocked any users yet.",
   "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
   "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json
index dd2188d8e..740f2bfae 100644
--- a/app/javascript/mastodon/locales/eo.json
+++ b/app/javascript/mastodon/locales/eo.json
@@ -71,10 +71,10 @@
   "compose_form.lock_disclaimer": "Via konta ne estas {locked}. Iu ajn povas sekvi vin por vidi viajn mesaĝojn, kiuj estas nur por sekvantoj.",
   "compose_form.lock_disclaimer.lock": "ŝlosita",
   "compose_form.placeholder": "Pri kio vi pensas?",
-  "compose_form.poll.add_option": "Add a choice",
-  "compose_form.poll.duration": "Poll duration",
-  "compose_form.poll.option_placeholder": "Choice {number}",
-  "compose_form.poll.remove_option": "Remove this choice",
+  "compose_form.poll.add_option": "Aldoni elekto",
+  "compose_form.poll.duration": "Balotenketo daŭro",
+  "compose_form.poll.option_placeholder": "elekto {number}",
+  "compose_form.poll.remove_option": "Forigi ĉi tiu elekton",
   "compose_form.publish": "Hup",
   "compose_form.publish_loud": "{publish}!",
   "compose_form.sensitive.marked": "Aŭdovidaĵo markita tikla",
@@ -83,7 +83,7 @@
   "compose_form.spoiler.unmarked": "Teksto ne kaŝita",
   "compose_form.spoiler_placeholder": "Skribu vian averton ĉi tie",
   "confirmation_modal.cancel": "Nuligi",
-  "confirmations.block.block_and_report": "Block & Report",
+  "confirmations.block.block_and_report": "Bloki & Signali",
   "confirmations.block.confirm": "Bloki",
   "confirmations.block.message": "Ĉu vi certas, ke vi volas bloki {name}?",
   "confirmations.delete.confirm": "Forigi",
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Simboloj",
   "emoji_button.travel": "Vojaĝoj kaj lokoj",
   "empty_column.account_timeline": "Neniu mesaĝo ĉi tie!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "Vi ankoraŭ ne blokis uzanton.",
   "empty_column.community": "La loka tempolinio estas malplena. Skribu ion por plenigi ĝin!",
   "empty_column.direct": "Vi ankoraŭ ne havas rektan mesaĝon. Kiam vi sendos aŭ ricevos iun, ĝi aperos ĉi tie.",
@@ -154,15 +155,15 @@
   "home.column_settings.basic": "Bazaj agordoj",
   "home.column_settings.show_reblogs": "Montri diskonigojn",
   "home.column_settings.show_replies": "Montri respondojn",
-  "intervals.full.days": "{number, plural, one {# day} other {# days}}",
-  "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
+  "intervals.full.days": "{number, plural, one {# tago} other {# tagoj}}",
+  "intervals.full.hours": "{number, plural, one {# horo} other {# horoj}}",
   "intervals.full.minutes": "{number, plural, one {# minuto} other {# minutoj}}",
   "introduction.federation.action": "Sekva",
-  "introduction.federation.federated.headline": "Federated",
+  "introduction.federation.federated.headline": "Federacio",
   "introduction.federation.federated.text": "Publikaj mesaĝoj el aliaj serviloj de la Fediverse aperos en la fratara tempolinio.",
-  "introduction.federation.home.headline": "Home",
+  "introduction.federation.home.headline": "Heimo",
   "introduction.federation.home.text": "Mesaĝoj de homoj, kiujn vi sekvas, aperos en via hejma fluo. Vi povas sekvi iun ajn de ajna servilo!",
-  "introduction.federation.local.headline": "Local",
+  "introduction.federation.local.headline": "Loka",
   "introduction.federation.local.text": "Publikaj mesaĝoj de homoj de via servilo aperos en la loka tempolinio.",
   "introduction.interactions.action": "Fini la lernilon!",
   "introduction.interactions.favourite.headline": "Stelumi",
@@ -246,7 +247,7 @@
   "notification.favourite": "{name} stelumis vian mesaĝon",
   "notification.follow": "{name} eksekvis vin",
   "notification.mention": "{name} menciis vin",
-  "notification.poll": "A poll you have voted in has ended",
+  "notification.poll": "Balotenketo ke vi balotis estas finita",
   "notification.reblog": "{name} diskonigis vian mesaĝon",
   "notifications.clear": "Forviŝi sciigojn",
   "notifications.clear_confirmation": "Ĉu vi certas, ke vi volas porĉiame forviŝi ĉiujn viajn sciigojn?",
@@ -257,7 +258,7 @@
   "notifications.column_settings.filter_bar.show": "Montri",
   "notifications.column_settings.follow": "Novaj sekvantoj:",
   "notifications.column_settings.mention": "Mencioj:",
-  "notifications.column_settings.poll": "Poll results:",
+  "notifications.column_settings.poll": "Balotenketo rezulto:",
   "notifications.column_settings.push": "Puŝsciigoj",
   "notifications.column_settings.reblog": "Diskonigoj:",
   "notifications.column_settings.show": "Montri en kolumno",
@@ -267,14 +268,14 @@
   "notifications.filter.favourites": "Stelumoj",
   "notifications.filter.follows": "Sekvoj",
   "notifications.filter.mentions": "Mencioj",
-  "notifications.filter.polls": "Poll results",
+  "notifications.filter.polls": "Balotenketoj rezultoj",
   "notifications.group": "{count} sciigoj",
   "poll.closed": "Finita",
   "poll.refresh": "Aktualigi",
   "poll.total_votes": "{count, plural, one {# voĉdono} other {# voĉdonoj}}",
   "poll.vote": "Voĉdoni",
-  "poll_button.add_poll": "Add a poll",
-  "poll_button.remove_poll": "Remove poll",
+  "poll_button.add_poll": "Aldoni balotenketon",
+  "poll_button.remove_poll": "Forigi balotenketon",
   "privacy.change": "Agordi mesaĝan privatecon",
   "privacy.direct.long": "Afiŝi nur al menciitaj uzantoj",
   "privacy.direct.short": "Rekta",
@@ -356,17 +357,17 @@
   "tabs_bar.local_timeline": "Loka tempolinio",
   "tabs_bar.notifications": "Sciigoj",
   "tabs_bar.search": "Serĉi",
-  "time_remaining.days": "{number, plural, one {# day} other {# days}} left",
-  "time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left",
-  "time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left",
-  "time_remaining.moments": "Moments remaining",
-  "time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left",
+  "time_remaining.days": "{number, plural, one {# tago} other {# tagoj}} restanta",
+  "time_remaining.hours": "{number, plural, one {# horo} other {# horoj}} restanta",
+  "time_remaining.minutes": "{number, plural, one {# minuto} other {# minutoj}} restanta",
+  "time_remaining.moments": "Momento restanta",
+  "time_remaining.seconds": "{number, plural, one {# sekundo} other {# sekundoj}} restanta",
   "trends.count_by_accounts": "{count} {rawCount, plural, one {persono} other {personoj}} parolas",
   "ui.beforeunload": "Via malneto perdiĝos se vi eliras de Mastodon.",
   "upload_area.title": "Altreni kaj lasi por alŝuti",
   "upload_button.label": "Aldoni aŭdovidaĵon (JPEG, PNG, GIF, WebM, MP4, MOV)",
   "upload_error.limit": "Limo de dosiera alŝutado transpasita.",
-  "upload_error.poll": "File upload not allowed with polls.",
+  "upload_error.poll": "Alŝuto de dosiero ne permisita kun balotenketo",
   "upload_form.description": "Priskribi por misvidantaj homoj",
   "upload_form.focus": "Antaŭvido de ŝanĝo",
   "upload_form.undo": "Forigi",
diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json
index 97d03d840..158a116d0 100644
--- a/app/javascript/mastodon/locales/es.json
+++ b/app/javascript/mastodon/locales/es.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Símbolos",
   "emoji_button.travel": "Viajes y lugares",
   "empty_column.account_timeline": "No toots here!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "Aún no has bloqueado a ningún usuario.",
   "empty_column.community": "La línea de tiempo local está vacía. ¡Escribe algo para empezar la fiesta!",
   "empty_column.direct": "Aún no tienes ningún mensaje directo. Cuando envíes o recibas uno, se mostrará aquí.",
diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json
index 17f84dc27..bd26ae232 100644
--- a/app/javascript/mastodon/locales/eu.json
+++ b/app/javascript/mastodon/locales/eu.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Sinboloak",
   "emoji_button.travel": "Bidaiak eta tokiak",
   "empty_column.account_timeline": "Ez dago toot-ik hemen!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "Ez duzu erabiltzailerik blokeatu oraindik.",
   "empty_column.community": "Denbora-lerro lokala hutsik dago. Idatzi zerbait publikoki pilota biraka jartzeko!",
   "empty_column.direct": "Ez duzu mezu zuzenik oraindik. Baten bat bidali edo jasotzen duzunean, hemen agertuko da.",
diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json
index 91a27e366..6890fa971 100644
--- a/app/javascript/mastodon/locales/fa.json
+++ b/app/javascript/mastodon/locales/fa.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "نمادها",
   "emoji_button.travel": "سفر و مکان",
   "empty_column.account_timeline": "هیچ بوقی این‌جا نیست!",
+  "empty_column.account_unavailable": "نمایهٔ ناموجود",
   "empty_column.blocks": "شما هنوز هیچ کسی را مسدود نکرده‌اید.",
   "empty_column.community": "فهرست نوشته‌های محلی خالی است. چیزی بنویسید تا چرخش بچرخد!",
   "empty_column.direct": "شما هیچ پیغام مستقیمی ندارید. اگر چنین پیغامی بگیرید یا بفرستید این‌جا نمایش خواهد یافت.",
diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json
index 68381f6b3..825cd4a75 100644
--- a/app/javascript/mastodon/locales/fi.json
+++ b/app/javascript/mastodon/locales/fi.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Symbolit",
   "emoji_button.travel": "Matkailu",
   "empty_column.account_timeline": "Ei ole 'toots' täällä!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "Et ole vielä estänyt yhtään käyttäjää.",
   "empty_column.community": "Paikallinen aikajana on tyhjä. Homma lähtee käyntiin, kun kirjoitat jotain julkista!",
   "empty_column.direct": "Sinulla ei ole vielä yhtään viestiä yksittäiselle käyttäjälle. Kun lähetät tai vastaanotat sellaisen, se näkyy täällä.",
diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json
index 4d7451248..58f3ce147 100644
--- a/app/javascript/mastodon/locales/fr.json
+++ b/app/javascript/mastodon/locales/fr.json
@@ -71,10 +71,10 @@
   "compose_form.lock_disclaimer": "Votre compte n’est pas {locked}. Tout le monde peut vous suivre et voir vos pouets privés.",
   "compose_form.lock_disclaimer.lock": "verrouillé",
   "compose_form.placeholder": "Qu’avez-vous en tête ?",
-  "compose_form.poll.add_option": "Add a choice",
-  "compose_form.poll.duration": "Poll duration",
-  "compose_form.poll.option_placeholder": "Choice {number}",
-  "compose_form.poll.remove_option": "Remove this choice",
+  "compose_form.poll.add_option": "Ajouter un choix",
+  "compose_form.poll.duration": "Durée du sondage",
+  "compose_form.poll.option_placeholder": "Choix {number}",
+  "compose_form.poll.remove_option": "Supprimer ce choix",
   "compose_form.publish": "Pouet",
   "compose_form.publish_loud": "{publish} !",
   "compose_form.sensitive.marked": "Média marqué comme sensible",
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Symboles",
   "emoji_button.travel": "Lieux & Voyages",
   "empty_column.account_timeline": "Aucun pouet ici !",
+  "empty_column.account_unavailable": "Profil non disponible",
   "empty_column.blocks": "Vous n’avez bloqué aucun·e utilisateur·rice pour le moment.",
   "empty_column.community": "Le fil public local est vide. Écrivez donc quelque chose pour le remplir !",
   "empty_column.direct": "Vous n’avez pas encore de messages directs. Lorsque vous en enverrez ou recevrez un, il s’affichera ici.",
@@ -154,8 +155,8 @@
   "home.column_settings.basic": "Basique",
   "home.column_settings.show_reblogs": "Afficher les partages",
   "home.column_settings.show_replies": "Afficher les réponses",
-  "intervals.full.days": "{number, plural, one {# day} other {# days}}",
-  "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
+  "intervals.full.days": "{number, plural, one {# jour} other {# jours}}",
+  "intervals.full.hours": "{number, plural, one {# heure} other {# heures}}",
   "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
   "introduction.federation.action": "Suivant",
   "introduction.federation.federated.headline": "Fil public global",
@@ -246,7 +247,7 @@
   "notification.favourite": "{name} a ajouté à ses favoris :",
   "notification.follow": "{name} vous suit",
   "notification.mention": "{name} vous a mentionné :",
-  "notification.poll": "A poll you have voted in has ended",
+  "notification.poll": "Un sondage auquel vous avez participé vient de se terminer",
   "notification.reblog": "{name} a partagé votre statut :",
   "notifications.clear": "Nettoyer les notifications",
   "notifications.clear_confirmation": "Voulez-vous vraiment supprimer toutes vos notifications ?",
@@ -257,7 +258,7 @@
   "notifications.column_settings.filter_bar.show": "Afficher",
   "notifications.column_settings.follow": "Nouveaux⋅elles abonné⋅e·s :",
   "notifications.column_settings.mention": "Mentions :",
-  "notifications.column_settings.poll": "Poll results:",
+  "notifications.column_settings.poll": "Résultats du sondage :",
   "notifications.column_settings.push": "Notifications",
   "notifications.column_settings.reblog": "Partages :",
   "notifications.column_settings.show": "Afficher dans la colonne",
@@ -267,14 +268,14 @@
   "notifications.filter.favourites": "Favoris",
   "notifications.filter.follows": "Abonné·e·s",
   "notifications.filter.mentions": "Mentions",
-  "notifications.filter.polls": "Poll results",
+  "notifications.filter.polls": "Résultats des sondages",
   "notifications.group": "{count} notifications",
   "poll.closed": "Fermé",
   "poll.refresh": "Actualiser",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
   "poll.vote": "Voter",
-  "poll_button.add_poll": "Add a poll",
-  "poll_button.remove_poll": "Remove poll",
+  "poll_button.add_poll": "Ajouter un sondage",
+  "poll_button.remove_poll": "Supprimer le sondage",
   "privacy.change": "Ajuster la confidentialité du message",
   "privacy.direct.long": "N’envoyer qu’aux personnes mentionnées",
   "privacy.direct.short": "Direct",
@@ -366,7 +367,7 @@
   "upload_area.title": "Glissez et déposez pour envoyer",
   "upload_button.label": "Joindre un média (JPEG, PNG, GIF, WebM, MP4, MOV)",
   "upload_error.limit": "Taille maximale d'envoi de fichier dépassée.",
-  "upload_error.poll": "File upload not allowed with polls.",
+  "upload_error.poll": "L'envoi de fichiers n'est pas autorisé avec les sondages.",
   "upload_form.description": "Décrire pour les malvoyant·e·s",
   "upload_form.focus": "Modifier l’aperçu",
   "upload_form.undo": "Supprimer",
diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json
index 3011e7d07..723328ab4 100644
--- a/app/javascript/mastodon/locales/gl.json
+++ b/app/javascript/mastodon/locales/gl.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Símbolos",
   "emoji_button.travel": "Viaxes e Lugares",
   "empty_column.account_timeline": "Sen toots por aquí!",
+  "empty_column.account_unavailable": "Perfil non dispoñible",
   "empty_column.blocks": "Non bloqueou ningunha usuaria polo de agora.",
   "empty_column.community": "A liña temporal local está baldeira. Escriba algo de xeito público para que rule!",
   "empty_column.direct": "Aínda non ten mensaxes directas. Cando envíe ou reciba unha, aparecerá aquí.",
diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json
index c136c111f..c9228cffd 100644
--- a/app/javascript/mastodon/locales/he.json
+++ b/app/javascript/mastodon/locales/he.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "סמלים",
   "emoji_button.travel": "טיולים ואתרים",
   "empty_column.account_timeline": "No toots here!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "You haven't blocked any users yet.",
   "empty_column.community": "טור הסביבה ריק. יש לפרסם משהו כדי שדברים יתרחילו להתגלגל!",
   "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
diff --git a/app/javascript/mastodon/locales/hr.json b/app/javascript/mastodon/locales/hr.json
index 86bd01a79..55a4ec4ee 100644
--- a/app/javascript/mastodon/locales/hr.json
+++ b/app/javascript/mastodon/locales/hr.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Simboli",
   "emoji_button.travel": "Putovanja & Mjesta",
   "empty_column.account_timeline": "No toots here!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "You haven't blocked any users yet.",
   "empty_column.community": "Lokalni timeline je prazan. Napiši nešto javno kako bi pokrenuo stvari!",
   "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json
index 507e04400..c5b0831c3 100644
--- a/app/javascript/mastodon/locales/hu.json
+++ b/app/javascript/mastodon/locales/hu.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Szimbólumok",
   "emoji_button.travel": "Utazás és Helyek",
   "empty_column.account_timeline": "No toots here!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "You haven't blocked any users yet.",
   "empty_column.community": "A helyi idővonal üres. Írj egy publikus stástuszt, hogy elindítsd a labdát!",
   "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
diff --git a/app/javascript/mastodon/locales/hy.json b/app/javascript/mastodon/locales/hy.json
index a4c8bffba..c3971b09e 100644
--- a/app/javascript/mastodon/locales/hy.json
+++ b/app/javascript/mastodon/locales/hy.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Նշաններ",
   "emoji_button.travel": "Ուղեւորություն եւ տեղանքներ",
   "empty_column.account_timeline": "No toots here!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "You haven't blocked any users yet.",
   "empty_column.community": "Տեղական հոսքը դատա՛րկ է։ Հրապարակային մի բան գրիր շարժիչը խոդ տալու համար։",
   "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
diff --git a/app/javascript/mastodon/locales/id.json b/app/javascript/mastodon/locales/id.json
index 5319705dc..c4610c330 100644
--- a/app/javascript/mastodon/locales/id.json
+++ b/app/javascript/mastodon/locales/id.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Simbol",
   "emoji_button.travel": "Tempat Wisata",
   "empty_column.account_timeline": "No toots here!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "You haven't blocked any users yet.",
   "empty_column.community": "Linimasa lokal masih kosong. Tulis sesuatu secara publik dan buat roda berputar!",
   "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
diff --git a/app/javascript/mastodon/locales/io.json b/app/javascript/mastodon/locales/io.json
index 300bc4484..dcdae5771 100644
--- a/app/javascript/mastodon/locales/io.json
+++ b/app/javascript/mastodon/locales/io.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Symbols",
   "emoji_button.travel": "Travel & Places",
   "empty_column.account_timeline": "No toots here!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "You haven't blocked any users yet.",
   "empty_column.community": "La lokala tempolineo esas vakua. Skribez ulo publike por iniciar la agiveso!",
   "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json
index d70a88dbb..792204830 100644
--- a/app/javascript/mastodon/locales/it.json
+++ b/app/javascript/mastodon/locales/it.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Simboli",
   "emoji_button.travel": "Viaggi e luoghi",
   "empty_column.account_timeline": "Non ci sono toot qui!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "Non hai ancora bloccato nessun utente.",
   "empty_column.community": "La timeline locale è vuota. Condividi qualcosa pubblicamente per dare inizio alla festa!",
   "empty_column.direct": "Non hai ancora nessun messaggio diretto. Quando ne manderai o riceverai qualcuno, apparirà qui.",
diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json
index 84a65c6d2..0bf9a22c4 100644
--- a/app/javascript/mastodon/locales/ja.json
+++ b/app/javascript/mastodon/locales/ja.json
@@ -77,8 +77,8 @@
   "compose_form.placeholder": "今なにしてる?",
   "compose_form.poll.add_option": "追加",
   "compose_form.poll.duration": "アンケート期間",
-  "compose_form.poll.option_placeholder": "選択肢 {number}",
-  "compose_form.poll.remove_option": "この選択肢を削除",
+  "compose_form.poll.option_placeholder": "項目 {number}",
+  "compose_form.poll.remove_option": "この項目を削除",
   "compose_form.publish": "トゥート",
   "compose_form.publish_loud": "{publish}!",
   "compose_form.sensitive.marked": "メディアに閲覧注意が設定されています",
@@ -121,7 +121,7 @@
   "emoji_button.symbols": "記号",
   "emoji_button.travel": "旅行と場所",
   "empty_column.account_timeline": "トゥートがありません!",
-  "empty_column.account_timeline_blocked": "ブロックされています",
+  "empty_column.account_unavailable": "プロフィールは利用できません",
   "empty_column.blocks": "まだ誰もブロックしていません。",
   "empty_column.community": "ローカルタイムラインはまだ使われていません。何か書いてみましょう!",
   "empty_column.direct": "ダイレクトメッセージはまだありません。ダイレクトメッセージをやりとりすると、ここに表示されます。",
diff --git a/app/javascript/mastodon/locales/ka.json b/app/javascript/mastodon/locales/ka.json
index fa1d823d0..ac983a546 100644
--- a/app/javascript/mastodon/locales/ka.json
+++ b/app/javascript/mastodon/locales/ka.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "სიმბოლოები",
   "emoji_button.travel": "მოგზაურობა და ადგილები",
   "empty_column.account_timeline": "No toots here!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "You haven't blocked any users yet.",
   "empty_column.community": "ლოკალური თაიმლაინი ცარიელია. დაწერეთ რაიმე ღიად ან ქენით რაიმე სხვა!",
   "empty_column.direct": "ჯერ პირდაპირი წერილები არ გაქვთ. როდესაც მიიღებთ ან გააგზავნით, გამოჩნდება აქ.",
diff --git a/app/javascript/mastodon/locales/kk.json b/app/javascript/mastodon/locales/kk.json
index 12cdf25c9..ee7bf5d6e 100644
--- a/app/javascript/mastodon/locales/kk.json
+++ b/app/javascript/mastodon/locales/kk.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Таңбалар",
   "emoji_button.travel": "Саяхат",
   "empty_column.account_timeline": "Жазба жоқ ешқандай!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "Ешкімді бұғаттамағансыз.",
   "empty_column.community": "Жергілікті желі бос. Сіз бастап жазыңыз!",
   "empty_column.direct": "Әзірше дым хат жоқ. Өзіңіз жазып көріңіз алдымен.",
@@ -246,7 +247,7 @@
   "notification.favourite": "{name} жазбаңызды таңдаулыға қосты",
   "notification.follow": "{name} сізге жазылды",
   "notification.mention": "{name} сізді атап өтті",
-  "notification.poll": "A poll you have voted in has ended",
+  "notification.poll": "Бұл сауалнаманың мерзімі аяқталыпты",
   "notification.reblog": "{name} жазбаңызды бөлісті",
   "notifications.clear": "Ескертпелерді тазарт",
   "notifications.clear_confirmation": "Шынымен барлық ескертпелерді өшіресіз бе?",
@@ -257,7 +258,7 @@
   "notifications.column_settings.filter_bar.show": "Көрсету",
   "notifications.column_settings.follow": "Жаңа оқырмандар:",
   "notifications.column_settings.mention": "Аталымдар:",
-  "notifications.column_settings.poll": "Poll results:",
+  "notifications.column_settings.poll": "Нәтижелері:",
   "notifications.column_settings.push": "Push ескертпелер",
   "notifications.column_settings.reblog": "Бөлісулер:",
   "notifications.column_settings.show": "Бағанда көрсет",
@@ -267,7 +268,7 @@
   "notifications.filter.favourites": "Таңдаулылар",
   "notifications.filter.follows": "Жазылулар",
   "notifications.filter.mentions": "Аталымдар",
-  "notifications.filter.polls": "Poll results",
+  "notifications.filter.polls": "Сауалнама нәтижелері",
   "notifications.group": "{count} ескертпе",
   "poll.closed": "Жабық",
   "poll.refresh": "Жаңарту",
@@ -366,7 +367,7 @@
   "upload_area.title": "Жүктеу үшін сүйреп әкеліңіз",
   "upload_button.label": "Медиа қосу (JPEG, PNG, GIF, WebM, MP4, MOV)",
   "upload_error.limit": "Файл жүктеу лимитінен асып кеттіңіз.",
-  "upload_error.poll": "Сауалнамамен бірге файл жүктеуге болмайды",
+  "upload_error.poll": "Сауалнамамен бірге файл жүктеуге болмайды.",
   "upload_form.description": "Көру қабілеті нашар адамдар үшін сипаттаңыз",
   "upload_form.focus": "Превьюді өзгерту",
   "upload_form.undo": "Өшіру",
diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json
index 433592ffd..a1e81a9d0 100644
--- a/app/javascript/mastodon/locales/ko.json
+++ b/app/javascript/mastodon/locales/ko.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "기호",
   "emoji_button.travel": "여행과 장소",
   "empty_column.account_timeline": "여긴 툿이 없어요!",
+  "empty_column.account_unavailable": "프로필 사용 불가",
   "empty_column.blocks": "아직 아무도 차단하지 않았습니다.",
   "empty_column.community": "로컬 타임라인에 아무 것도 없습니다. 아무거나 적어 보세요!",
   "empty_column.direct": "아직 다이렉트 메시지가 없습니다. 다이렉트 메시지를 보내거나 받은 경우, 여기에 표시 됩니다.",
diff --git a/app/javascript/mastodon/locales/lv.json b/app/javascript/mastodon/locales/lv.json
index 0fa0c4fde..ac3342699 100644
--- a/app/javascript/mastodon/locales/lv.json
+++ b/app/javascript/mastodon/locales/lv.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Simboli",
   "emoji_button.travel": "Ceļošana & Vietas",
   "empty_column.account_timeline": "Šeit ziņojumu nav!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "Tu neesi vēl nevienu bloķējis.",
   "empty_column.community": "Lokālā laika līnija ir tukša. :/ Ieraksti kaut ko lai sākas rosība!",
   "empty_column.direct": "Tev nav privāto ziņu. Tiklīdz saņemsi tās šeit parādīsies.",
diff --git a/app/javascript/mastodon/locales/ms.json b/app/javascript/mastodon/locales/ms.json
index eedd4c6f3..220cc86f9 100644
--- a/app/javascript/mastodon/locales/ms.json
+++ b/app/javascript/mastodon/locales/ms.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Symbols",
   "emoji_button.travel": "Travel & Places",
   "empty_column.account_timeline": "No toots here!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "You haven't blocked any users yet.",
   "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
   "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json
index e5e4748d7..5fb445209 100644
--- a/app/javascript/mastodon/locales/nl.json
+++ b/app/javascript/mastodon/locales/nl.json
@@ -71,10 +71,10 @@
   "compose_form.lock_disclaimer": "Jouw account is niet {locked}. Iedereen kan jou volgen en kan de toots zien die je alleen aan jouw volgers hebt gericht.",
   "compose_form.lock_disclaimer.lock": "besloten",
   "compose_form.placeholder": "Wat wil je kwijt?",
-  "compose_form.poll.add_option": "Add a choice",
-  "compose_form.poll.duration": "Poll duration",
-  "compose_form.poll.option_placeholder": "Choice {number}",
-  "compose_form.poll.remove_option": "Remove this choice",
+  "compose_form.poll.add_option": "Keuze toevoegen",
+  "compose_form.poll.duration": "Duur van de poll",
+  "compose_form.poll.option_placeholder": "Keuze {number}",
+  "compose_form.poll.remove_option": "Deze keuze verwijderen",
   "compose_form.publish": "Toot",
   "compose_form.publish_loud": "{publish}!",
   "compose_form.sensitive.marked": "Media is als gevoelig gemarkeerd",
@@ -83,7 +83,7 @@
   "compose_form.spoiler.unmarked": "Tekst is niet verborgen",
   "compose_form.spoiler_placeholder": "Waarschuwingstekst",
   "confirmation_modal.cancel": "Annuleren",
-  "confirmations.block.block_and_report": "Block & Report",
+  "confirmations.block.block_and_report": "Blokkeren en rapporteren",
   "confirmations.block.confirm": "Blokkeren",
   "confirmations.block.message": "Weet je het zeker dat je {name} wilt blokkeren?",
   "confirmations.delete.confirm": "Verwijderen",
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Symbolen",
   "emoji_button.travel": "Reizen en plekken",
   "empty_column.account_timeline": "Hier zijn geen toots!",
+  "empty_column.account_unavailable": "Profiel is niet beschikbaar",
   "empty_column.blocks": "Jij hebt nog geen enkele gebruiker geblokkeerd.",
   "empty_column.community": "De lokale tijdlijn is nog leeg. Toot iets in het openbaar om de bal aan het rollen te krijgen!",
   "empty_column.direct": "Je hebt nog geen directe berichten. Wanneer je er een verzend of ontvangt, zijn deze hier te zien.",
@@ -154,9 +155,9 @@
   "home.column_settings.basic": "Algemeen",
   "home.column_settings.show_reblogs": "Boosts tonen",
   "home.column_settings.show_replies": "Reacties tonen",
-  "intervals.full.days": "{number, plural, one {# day} other {# days}}",
-  "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
-  "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
+  "intervals.full.days": "{number, plural, one {# dag} other {# dagen}}",
+  "intervals.full.hours": "{number, plural, one {# uur} other {# uur}}",
+  "intervals.full.minutes": "{number, plural, one {# minuut} other {# minuten}}",
   "introduction.federation.action": "Volgende",
   "introduction.federation.federated.headline": "Globaal",
   "introduction.federation.federated.text": "Openbare toots van mensen op andere servers in de fediverse verschijnen op de globale tijdlijn.",
@@ -246,7 +247,7 @@
   "notification.favourite": "{name} voegde jouw toot als favoriet toe",
   "notification.follow": "{name} volgt jou nu",
   "notification.mention": "{name} vermeldde jou",
-  "notification.poll": "A poll you have voted in has ended",
+  "notification.poll": "Een poll waaraan jij hebt meegedaan is beëindigd",
   "notification.reblog": "{name} boostte jouw toot",
   "notifications.clear": "Meldingen verwijderen",
   "notifications.clear_confirmation": "Weet je het zeker dat je al jouw meldingen wilt verwijderen?",
@@ -257,7 +258,7 @@
   "notifications.column_settings.filter_bar.show": "Tonen",
   "notifications.column_settings.follow": "Nieuwe volgers:",
   "notifications.column_settings.mention": "Vermeldingen:",
-  "notifications.column_settings.poll": "Poll results:",
+  "notifications.column_settings.poll": "Pollresultaten:",
   "notifications.column_settings.push": "Pushmeldingen",
   "notifications.column_settings.reblog": "Boosts:",
   "notifications.column_settings.show": "In kolom tonen",
@@ -267,14 +268,14 @@
   "notifications.filter.favourites": "Favorieten",
   "notifications.filter.follows": "Die jij volgt",
   "notifications.filter.mentions": "Vermeldingen",
-  "notifications.filter.polls": "Poll results",
+  "notifications.filter.polls": "Pollresultaten",
   "notifications.group": "{count} meldingen",
   "poll.closed": "Gesloten",
   "poll.refresh": "Vernieuwen",
   "poll.total_votes": "{count, plural, one {# stem} other {# stemmen}}",
   "poll.vote": "Stemmen",
-  "poll_button.add_poll": "Add a poll",
-  "poll_button.remove_poll": "Remove poll",
+  "poll_button.add_poll": "Poll toevoegen",
+  "poll_button.remove_poll": "Poll verwijderen",
   "privacy.change": "Zichtbaarheid toot aanpassen",
   "privacy.direct.long": "Alleen aan vermelde gebruikers tonen",
   "privacy.direct.short": "Direct",
@@ -366,7 +367,7 @@
   "upload_area.title": "Hierin slepen om te uploaden",
   "upload_button.label": "Media toevoegen (JPEG, PNG, GIF, WebM, MP4, MOV)",
   "upload_error.limit": "Uploadlimiet van bestand overschreden.",
-  "upload_error.poll": "File upload not allowed with polls.",
+  "upload_error.poll": "Het uploaden van bestanden is in polls niet toegestaan.",
   "upload_form.description": "Omschrijf dit voor mensen met een visuele beperking",
   "upload_form.focus": "Voorvertoning aanpassen",
   "upload_form.undo": "Verwijderen",
diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json
index 9556c5ad8..fc2c3c573 100644
--- a/app/javascript/mastodon/locales/no.json
+++ b/app/javascript/mastodon/locales/no.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Symboler",
   "emoji_button.travel": "Reise & steder",
   "empty_column.account_timeline": "No toots here!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "You haven't blocked any users yet.",
   "empty_column.community": "Den lokale tidslinjen er tom. Skriv noe offentlig for å få snøballen til å rulle!",
   "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json
index 8fc8762a4..4dfb9904e 100644
--- a/app/javascript/mastodon/locales/oc.json
+++ b/app/javascript/mastodon/locales/oc.json
@@ -83,7 +83,7 @@
   "compose_form.spoiler.unmarked": "Lo tèxte es pas rescondut",
   "compose_form.spoiler_placeholder": "Escrivètz l’avertiment aquí",
   "confirmation_modal.cancel": "Anullar",
-  "confirmations.block.block_and_report": "Block & Report",
+  "confirmations.block.block_and_report": "Blocar e senhalar",
   "confirmations.block.confirm": "Blocar",
   "confirmations.block.message": "Volètz vertadièrament blocar {name} ?",
   "confirmations.delete.confirm": "Escafar",
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Simbòls",
   "emoji_button.travel": "Viatges & lòcs",
   "empty_column.account_timeline": "Cap de tuts aquí !",
+  "empty_column.account_unavailable": "Perfil pas disponible",
   "empty_column.blocks": "Avètz pas blocat degun pel moment.",
   "empty_column.community": "Lo flux public local es void. Escrivètz quicòm per lo garnir !",
   "empty_column.direct": "Avètz pas encara cap de messatges. Quand ne mandatz un o que ne recebètz un, serà mostrat aquí.",
@@ -358,7 +359,7 @@
   "tabs_bar.search": "Recèrcas",
   "time_remaining.days": "demòra{number, plural, one  { # jorn} other {n # jorns}}",
   "time_remaining.hours": "demòra{number, plural, one { # ora} other {n # oras}}",
-  "time_remaining.minutes": "demòr{number, plural, one { # minuta} other {nn # minutas}}",
+  "time_remaining.minutes": "demòra{number, plural, one { # minuta} other {n # minutas}}",
   "time_remaining.moments": "Moments restants",
   "time_remaining.seconds": "demòra{number, plural, one { # segonda} other {n # segondas}}",
   "trends.count_by_accounts": "{count} {rawCount, plural, one {person} ne charra other {people}} ne charran",
diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json
index 107ac8757..fce97f00e 100644
--- a/app/javascript/mastodon/locales/pl.json
+++ b/app/javascript/mastodon/locales/pl.json
@@ -121,6 +121,7 @@
   "emoji_button.symbols": "Symbole",
   "emoji_button.travel": "Podróże i miejsca",
   "empty_column.account_timeline": "Brak wpisów tutaj!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "Nie zablokowałeś(-aś) jeszcze żadnego użytkownika.",
   "empty_column.community": "Lokalna oś czasu jest pusta. Napisz coś publicznie, aby zagaić!",
   "empty_column.direct": "Nie masz żadnych wiadomości bezpośrednich. Kiedy dostaniesz lub wyślesz jakąś, pojawi się ona tutaj.",
@@ -251,7 +252,7 @@
   "notification.favourite": "{name} dodał(a) Twój wpis do ulubionych",
   "notification.follow": "{name} zaczął(-ęła) Cię śledzić",
   "notification.mention": "{name} wspomniał(a) o tobie",
-  "notification.poll": "A poll you have voted in has ended",
+  "notification.poll": "Głosowanie w którym brałeś(-aś) udział zakończyła się",
   "notification.reblog": "{name} podbił(a) Twój wpis",
   "notifications.clear": "Wyczyść powiadomienia",
   "notifications.clear_confirmation": "Czy na pewno chcesz bezpowrotnie usunąć wszystkie powiadomienia?",
@@ -262,7 +263,7 @@
   "notifications.column_settings.filter_bar.show": "Pokaż",
   "notifications.column_settings.follow": "Nowi śledzący:",
   "notifications.column_settings.mention": "Wspomnienia:",
-  "notifications.column_settings.poll": "Poll results:",
+  "notifications.column_settings.poll": "Wyniki głosowania:",
   "notifications.column_settings.push": "Powiadomienia push",
   "notifications.column_settings.reblog": "Podbicia:",
   "notifications.column_settings.show": "Pokaż w kolumnie",
diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json
index 7533a462b..5b07c2295 100644
--- a/app/javascript/mastodon/locales/pt-BR.json
+++ b/app/javascript/mastodon/locales/pt-BR.json
@@ -71,10 +71,10 @@
   "compose_form.lock_disclaimer": "A sua conta não está {locked}. Qualquer pessoa pode te seguir e visualizar postagens direcionadas a apenas seguidores.",
   "compose_form.lock_disclaimer.lock": "trancada",
   "compose_form.placeholder": "No que você está pensando?",
-  "compose_form.poll.add_option": "Add a choice",
-  "compose_form.poll.duration": "Poll duration",
-  "compose_form.poll.option_placeholder": "Choice {number}",
-  "compose_form.poll.remove_option": "Remove this choice",
+  "compose_form.poll.add_option": "Adicionar uma opção",
+  "compose_form.poll.duration": "Duração da enquete",
+  "compose_form.poll.option_placeholder": "Opção {number}",
+  "compose_form.poll.remove_option": "Remover essa opção",
   "compose_form.publish": "Publicar",
   "compose_form.publish_loud": "{publish}!",
   "compose_form.sensitive.marked": "Mídia está marcada como sensível",
@@ -83,7 +83,7 @@
   "compose_form.spoiler.unmarked": "O texto não está escondido",
   "compose_form.spoiler_placeholder": "Aviso de conteúdo",
   "confirmation_modal.cancel": "Cancelar",
-  "confirmations.block.block_and_report": "Block & Report",
+  "confirmations.block.block_and_report": "Bloquear e denunciar",
   "confirmations.block.confirm": "Bloquear",
   "confirmations.block.message": "Você tem certeza de que quer bloquear {name}?",
   "confirmations.delete.confirm": "Excluir",
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Símbolos",
   "emoji_button.travel": "Viagens & Lugares",
   "empty_column.account_timeline": "Não há toots aqui!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "Você ainda não bloqueou nenhum usuário.",
   "empty_column.community": "A timeline local está vazia. Escreva algo publicamente para começar!",
   "empty_column.direct": "Você não tem nenhuma mensagem direta ainda. Quando você enviar ou receber uma, as mensagens aparecerão por aqui.",
@@ -145,17 +146,17 @@
   "hashtag.column_header.tag_mode.all": "e {additional}",
   "hashtag.column_header.tag_mode.any": "ou {additional}",
   "hashtag.column_header.tag_mode.none": "sem {additional}",
-  "hashtag.column_settings.select.no_options_message": "No suggestions found",
-  "hashtag.column_settings.select.placeholder": "Enter hashtags…",
+  "hashtag.column_settings.select.no_options_message": "Nenhuma sugestão encontrada",
+  "hashtag.column_settings.select.placeholder": "Adicione as hashtags…",
   "hashtag.column_settings.tag_mode.all": "Todas essas",
   "hashtag.column_settings.tag_mode.any": "Qualquer uma dessas",
   "hashtag.column_settings.tag_mode.none": "Nenhuma dessas",
-  "hashtag.column_settings.tag_toggle": "Include additional tags in this column",
+  "hashtag.column_settings.tag_toggle": "Incluir outras hashtags nessa coluna",
   "home.column_settings.basic": "Básico",
   "home.column_settings.show_reblogs": "Mostrar compartilhamentos",
   "home.column_settings.show_replies": "Mostrar as respostas",
-  "intervals.full.days": "{number, plural, one {# day} other {# days}}",
-  "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
+  "intervals.full.days": "{number, plural, one {# dia} other {# dias}}",
+  "intervals.full.hours": "{number, plural, one {# hora} other {# horas}}",
   "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
   "introduction.federation.action": "Próximo",
   "introduction.federation.federated.headline": "Federated",
@@ -212,7 +213,7 @@
   "lists.account.remove": "Remover da lista",
   "lists.delete": "Delete list",
   "lists.edit": "Editar lista",
-  "lists.edit.submit": "Change title",
+  "lists.edit.submit": "Mudar o título",
   "lists.new.create": "Adicionar lista",
   "lists.new.title_placeholder": "Novo título da lista",
   "lists.search": "Procurar entre as pessoas que você segue",
@@ -246,7 +247,7 @@
   "notification.favourite": "{name} adicionou a sua postagem aos favoritos",
   "notification.follow": "{name} te seguiu",
   "notification.mention": "{name} te mencionou",
-  "notification.poll": "A poll you have voted in has ended",
+  "notification.poll": "Uma enquete em que você votou chegou ao fim",
   "notification.reblog": "{name} compartilhou a sua postagem",
   "notifications.clear": "Limpar notificações",
   "notifications.clear_confirmation": "Você tem certeza de que quer limpar todas as suas notificações permanentemente?",
@@ -257,7 +258,7 @@
   "notifications.column_settings.filter_bar.show": "Mostrar",
   "notifications.column_settings.follow": "Novos seguidores:",
   "notifications.column_settings.mention": "Menções:",
-  "notifications.column_settings.poll": "Poll results:",
+  "notifications.column_settings.poll": "Resultados da enquete:",
   "notifications.column_settings.push": "Enviar notificações",
   "notifications.column_settings.reblog": "Compartilhamento:",
   "notifications.column_settings.show": "Mostrar nas colunas",
@@ -267,14 +268,14 @@
   "notifications.filter.favourites": "Favoritos",
   "notifications.filter.follows": "Seguidores",
   "notifications.filter.mentions": "Menções",
-  "notifications.filter.polls": "Poll results",
+  "notifications.filter.polls": "Resultados da enquete",
   "notifications.group": "{count} notificações",
-  "poll.closed": "Closed",
-  "poll.refresh": "Refresh",
-  "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
+  "poll.closed": "Fechada",
+  "poll.refresh": "Atualizar",
+  "poll.total_votes": "{count, plural, one {# voto} other {# votos}}",
   "poll.vote": "Votar",
-  "poll_button.add_poll": "Add a poll",
-  "poll_button.remove_poll": "Remove poll",
+  "poll_button.add_poll": "Adicionar uma enquete",
+  "poll_button.remove_poll": "Remover enquete",
   "privacy.change": "Ajustar a privacidade da mensagem",
   "privacy.direct.long": "Apenas para usuários mencionados",
   "privacy.direct.short": "Direta",
@@ -314,7 +315,7 @@
   "status.block": "Block @{name}",
   "status.cancel_reblog_private": "Desfazer compartilhamento",
   "status.cannot_reblog": "Esta postagem não pode ser compartilhada",
-  "status.copy": "Copy link to status",
+  "status.copy": "Copiar o link para o status",
   "status.delete": "Excluir",
   "status.detailed_status": "Visão detalhada da conversa",
   "status.direct": "Enviar mensagem direta a @{name}",
@@ -356,17 +357,17 @@
   "tabs_bar.local_timeline": "Local",
   "tabs_bar.notifications": "Notificações",
   "tabs_bar.search": "Buscar",
-  "time_remaining.days": "{number, plural, one {# day} other {# days}} left",
-  "time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left",
-  "time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left",
-  "time_remaining.moments": "Moments remaining",
-  "time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left",
+  "time_remaining.days": "{number, plural, one {# dia restante} other {# dias restantes}}",
+  "time_remaining.hours": "{number, plural, one {# hora restante} other {# horas restantes}}",
+  "time_remaining.minutes": "{number, plural, one {# minuto restante} other {# minutos restantes}}",
+  "time_remaining.moments": "Momentos restantes",
+  "time_remaining.seconds": "{number, plural, one {# segundo restante} other {# segundos restantes}}",
   "trends.count_by_accounts": "{count} {rawCount, plural, one {pessoa} other {pessoas}} falando sobre",
   "ui.beforeunload": "Seu rascunho será perdido se você sair do Mastodon.",
   "upload_area.title": "Arraste e solte para enviar",
   "upload_button.label": "Adicionar mídia (JPEG, PNG, GIF, WebM, MP4, MOV)",
-  "upload_error.limit": "File upload limit exceeded.",
-  "upload_error.poll": "File upload not allowed with polls.",
+  "upload_error.limit": "Limite de envio de arquivos excedido.",
+  "upload_error.poll": "Envio de arquivos não é permitido com enquetes.",
   "upload_form.description": "Descreva a imagem para deficientes visuais",
   "upload_form.focus": "Ajustar foco",
   "upload_form.undo": "Remover",
diff --git a/app/javascript/mastodon/locales/pt.json b/app/javascript/mastodon/locales/pt.json
index 001a48b04..2abc3e252 100644
--- a/app/javascript/mastodon/locales/pt.json
+++ b/app/javascript/mastodon/locales/pt.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Símbolos",
   "emoji_button.travel": "Viagens & Lugares",
   "empty_column.account_timeline": "Sem publicações!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "Ainda não bloqueaste qualquer utilizador.",
   "empty_column.community": "Ainda não existe conteúdo local para mostrar!",
   "empty_column.direct": "Ainda não tens qualquer mensagem directa. Quando enviares ou receberes alguma, ela irá aparecer aqui.",
diff --git a/app/javascript/mastodon/locales/ro.json b/app/javascript/mastodon/locales/ro.json
index 7192e10b9..c0ec77cc6 100644
--- a/app/javascript/mastodon/locales/ro.json
+++ b/app/javascript/mastodon/locales/ro.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Simboluri",
   "emoji_button.travel": "Călătorii si Locuri",
   "empty_column.account_timeline": "Nici o postare aici!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "Nu ai blocat nici un utilizator incă.",
   "empty_column.community": "Fluxul local este gol. Scrie ceva public pentru a împinge bila la vale!",
   "empty_column.direct": "Nu ai nici un mesaj direct incă. Când trimiți sau primești unul, va fi afișat aici.",
diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json
index 09425c32e..13f511cbf 100644
--- a/app/javascript/mastodon/locales/ru.json
+++ b/app/javascript/mastodon/locales/ru.json
@@ -1,5 +1,5 @@
 {
-  "account.add_or_remove_from_list": "Add or Remove from lists",
+  "account.add_or_remove_from_list": "Добавить или удалить из списков",
   "account.badges.bot": "Бот",
   "account.block": "Блокировать",
   "account.block_domain": "Блокировать все с {domain}",
@@ -15,8 +15,8 @@
   "account.follows.empty": "Этот пользователь ни на кого не подписан.",
   "account.follows_you": "Подписан(а) на Вас",
   "account.hide_reblogs": "Скрыть продвижения от @{name}",
-  "account.link_verified_on": "Ownership of this link was checked on {date}",
-  "account.locked_info": "This account privacy status is set to locked. The owner manually reviews who can follow them.",
+  "account.link_verified_on": "Владение этой ссылкой было проверено {date}",
+  "account.locked_info": "Это закрытый аккаунт. Его владелец вручную одобряет подписчиков.",
   "account.media": "Медиа",
   "account.mention": "Упомянуть",
   "account.moved_to": "Ищите {name} здесь:",
@@ -71,10 +71,10 @@
   "compose_form.lock_disclaimer": "Ваш аккаунт не {locked}. Любой человек может подписаться на Вас и просматривать посты для подписчиков.",
   "compose_form.lock_disclaimer.lock": "закрыт",
   "compose_form.placeholder": "О чем Вы думаете?",
-  "compose_form.poll.add_option": "Add a choice",
-  "compose_form.poll.duration": "Poll duration",
-  "compose_form.poll.option_placeholder": "Choice {number}",
-  "compose_form.poll.remove_option": "Remove this choice",
+  "compose_form.poll.add_option": "Добавить",
+  "compose_form.poll.duration": "Длительность опроса",
+  "compose_form.poll.option_placeholder": "Вариант {number}",
+  "compose_form.poll.remove_option": "Удалить этот вариант",
   "compose_form.publish": "Трубить",
   "compose_form.publish_loud": "{publish}!",
   "compose_form.sensitive.marked": "Медиафайлы не отмечены как чувствительные",
@@ -83,7 +83,7 @@
   "compose_form.spoiler.unmarked": "Текст не скрыт",
   "compose_form.spoiler_placeholder": "Текст предупреждения",
   "confirmation_modal.cancel": "Отмена",
-  "confirmations.block.block_and_report": "Block & Report",
+  "confirmations.block.block_and_report": "Заблокировать и пожаловаться",
   "confirmations.block.confirm": "Заблокировать",
   "confirmations.block.message": "Вы уверены, что хотите заблокировать {name}?",
   "confirmations.delete.confirm": "Удалить",
@@ -96,8 +96,8 @@
   "confirmations.mute.message": "Вы уверены, что хотите заглушить {name}?",
   "confirmations.redraft.confirm": "Удалить и исправить",
   "confirmations.redraft.message": "Вы уверены, что хотите удалить этот статус и превратить в черновик? Вы потеряете все ответы, продвижения и отметки 'нравится' к нему.",
-  "confirmations.reply.confirm": "Reply",
-  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
+  "confirmations.reply.confirm": "Ответить",
+  "confirmations.reply.message": "При ответе текст набираемого сообщения будет перезаписан. Продолжить?",
   "confirmations.unfollow.confirm": "Отписаться",
   "confirmations.unfollow.message": "Вы уверены, что хотите отписаться от {name}?",
   "embed.instructions": "Встройте этот статус на Вашем сайте, скопировав код внизу.",
@@ -116,7 +116,9 @@
   "emoji_button.search_results": "Результаты поиска",
   "emoji_button.symbols": "Символы",
   "emoji_button.travel": "Путешествия",
-  "empty_column.account_timeline": "No toots here!",
+  "empty_column.account_timeline": "Статусов нет!",
+  "empty_column.account_unavailable": "Профиль недоступен",
+  "empty_column.account_timeline_blocked": "Вы заблокированы",
   "empty_column.blocks": "Вы ещё никого не заблокировали.",
   "empty_column.community": "Локальная лента пуста. Напишите что-нибудь, чтобы разогреть народ!",
   "empty_column.direct": "У Вас пока нет личных сообщений. Когда Вы начнёте их отправлять или получать, они появятся здесь.",
@@ -135,45 +137,45 @@
   "follow_request.authorize": "Авторизовать",
   "follow_request.reject": "Отказать",
   "getting_started.developers": "Для разработчиков",
-  "getting_started.directory": "Profile directory",
+  "getting_started.directory": "Каталог профилей",
   "getting_started.documentation": "Документация",
   "getting_started.heading": "Добро пожаловать",
   "getting_started.invite": "Пригласить людей",
   "getting_started.open_source_notice": "Mastodon - сервис с открытым исходным кодом. Вы можете помочь проекту или сообщить о проблемах на GitHub по адресу {github}.",
   "getting_started.security": "Безопасность",
   "getting_started.terms": "Условия использования",
-  "hashtag.column_header.tag_mode.all": "and {additional}",
-  "hashtag.column_header.tag_mode.any": "or {additional}",
-  "hashtag.column_header.tag_mode.none": "without {additional}",
-  "hashtag.column_settings.select.no_options_message": "No suggestions found",
-  "hashtag.column_settings.select.placeholder": "Enter hashtags…",
-  "hashtag.column_settings.tag_mode.all": "All of these",
-  "hashtag.column_settings.tag_mode.any": "Any of these",
-  "hashtag.column_settings.tag_mode.none": "None of these",
-  "hashtag.column_settings.tag_toggle": "Include additional tags in this column",
+  "hashtag.column_header.tag_mode.all": "и {additional}",
+  "hashtag.column_header.tag_mode.any": "или {additional}",
+  "hashtag.column_header.tag_mode.none": "без {additional}",
+  "hashtag.column_settings.select.no_options_message": "Предложений не найдено",
+  "hashtag.column_settings.select.placeholder": "Введите хэштеги…",
+  "hashtag.column_settings.tag_mode.all": "Все из списка",
+  "hashtag.column_settings.tag_mode.any": "Любой из списка",
+  "hashtag.column_settings.tag_mode.none": "Ни один из списка",
+  "hashtag.column_settings.tag_toggle": "Включая дополнительные хэштеге из этой колонки",
   "home.column_settings.basic": "Основные",
   "home.column_settings.show_reblogs": "Показывать продвижения",
   "home.column_settings.show_replies": "Показывать ответы",
-  "intervals.full.days": "{number, plural, one {# day} other {# days}}",
-  "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
-  "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
-  "introduction.federation.action": "Next",
-  "introduction.federation.federated.headline": "Federated",
-  "introduction.federation.federated.text": "Public posts from other servers of the fediverse will appear in the federated timeline.",
-  "introduction.federation.home.headline": "Home",
-  "introduction.federation.home.text": "Posts from people you follow will appear in your home feed. You can follow anyone on any server!",
-  "introduction.federation.local.headline": "Local",
-  "introduction.federation.local.text": "Public posts from people on the same server as you will appear in the local timeline.",
-  "introduction.interactions.action": "Finish tutorial!",
-  "introduction.interactions.favourite.headline": "Favourite",
-  "introduction.interactions.favourite.text": "You can save a toot for later, and let the author know that you liked it, by favouriting it.",
-  "introduction.interactions.reblog.headline": "Boost",
-  "introduction.interactions.reblog.text": "You can share other people's toots with your followers by boosting them.",
-  "introduction.interactions.reply.headline": "Reply",
-  "introduction.interactions.reply.text": "You can reply to other people's and your own toots, which will chain them together in a conversation.",
-  "introduction.welcome.action": "Let's go!",
-  "introduction.welcome.headline": "First steps",
-  "introduction.welcome.text": "Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.",
+  "intervals.full.days": "{number, plural, one {# день} few {# дня} many {# дней} other {# дней}}",
+  "intervals.full.hours": "{number, plural, one {# час} few {# часа} many {# часов} other {# часов}}",
+  "intervals.full.minutes": "{number, plural, one {# минута} few {# минуты} many {# минут} other {# минут}}",
+  "introduction.federation.action": "Далее",
+  "introduction.federation.federated.headline": "Глобальная лента",
+  "introduction.federation.federated.text": "Публичные статусы с других серверов федеративной сети расположатся в глобальной ленте.",
+  "introduction.federation.home.headline": "Домашняя лента",
+  "introduction.federation.home.text": "Статусы от тех, на кого вы подписаны, появятся в вашей домашней ленте. Вы можете подписаться на кого угодно с любого сервера!",
+  "introduction.federation.local.headline": "Локальная лента",
+  "introduction.federation.local.text": "Публичные статусы от людей с того же сервера, что и вы, будут отображены в локальной ленте.",
+  "introduction.interactions.action": "Завершить обучение",
+  "introduction.interactions.favourite.headline": "Отметки \"нравится\"",
+  "introduction.interactions.favourite.text": "Вы можете отметить статус, чтобы вернуться к нему позже и дать знать автору, что запись вам понравилась, поставив отметку \"нравится\".",
+  "introduction.interactions.reblog.headline": "Продвижения",
+  "introduction.interactions.reblog.text": "Вы можете делиться статусами других людей, продвигая их в своём аккаунте.",
+  "introduction.interactions.reply.headline": "Ответы",
+  "introduction.interactions.reply.text": "Вы можете отвечать свои и чужие посты, образуя цепочки сообщений (обсуждения).",
+  "introduction.welcome.action": "Поехали!",
+  "introduction.welcome.headline": "Первые шаги",
+  "introduction.welcome.text": "Добро пожаловать в федеративную сеть! Уже через мгновение вы сможете отправлять сообщения и общаться со своими друзьями на любом сервере. Но этот сервер — {domain} — особенный: на нём располагается ваш профиль. Запомните его название.",
   "keyboard_shortcuts.back": "перейти назад",
   "keyboard_shortcuts.blocked": "чтобы открыть список заблокированных",
   "keyboard_shortcuts.boost": "продвинуть пост",
@@ -212,7 +214,7 @@
   "lists.account.remove": "Убрать из списка",
   "lists.delete": "Удалить список",
   "lists.edit": "Изменить список",
-  "lists.edit.submit": "Change title",
+  "lists.edit.submit": "Изменить название",
   "lists.new.create": "Новый список",
   "lists.new.title_placeholder": "Заголовок списка",
   "lists.search": "Искать из ваших подписок",
@@ -222,7 +224,7 @@
   "missing_indicator.label": "Не найдено",
   "missing_indicator.sublabel": "Запрашиваемый ресурс не найден",
   "mute_modal.hide_notifications": "Убрать уведомления от этого пользователя?",
-  "navigation_bar.apps": "Mobile apps",
+  "navigation_bar.apps": "Мобильные приложения",
   "navigation_bar.blocks": "Список блокировки",
   "navigation_bar.community_timeline": "Локальная лента",
   "navigation_bar.compose": "Создать новый статус",
@@ -246,35 +248,35 @@
   "notification.favourite": "{name} понравился Ваш статус",
   "notification.follow": "{name} подписался(-лась) на Вас",
   "notification.mention": "{name} упомянул(а) Вас",
-  "notification.poll": "A poll you have voted in has ended",
+  "notification.poll": "Опрос, в котором вы приняли участие, завершился",
   "notification.reblog": "{name} продвинул(а) Ваш статус",
   "notifications.clear": "Очистить уведомления",
   "notifications.clear_confirmation": "Вы уверены, что хотите очистить все уведомления?",
   "notifications.column_settings.alert": "Десктопные уведомления",
   "notifications.column_settings.favourite": "Нравится:",
-  "notifications.column_settings.filter_bar.advanced": "Display all categories",
-  "notifications.column_settings.filter_bar.category": "Quick filter bar",
-  "notifications.column_settings.filter_bar.show": "Show",
+  "notifications.column_settings.filter_bar.advanced": "Отображать все категории",
+  "notifications.column_settings.filter_bar.category": "Фильтры по категориям",
+  "notifications.column_settings.filter_bar.show": "Показывать",
   "notifications.column_settings.follow": "Новые подписчики:",
   "notifications.column_settings.mention": "Упоминания:",
-  "notifications.column_settings.poll": "Poll results:",
+  "notifications.column_settings.poll": "Результаты опроса:",
   "notifications.column_settings.push": "Push-уведомления",
   "notifications.column_settings.reblog": "Продвижения:",
   "notifications.column_settings.show": "Показывать в колонке",
   "notifications.column_settings.sound": "Проигрывать звук",
-  "notifications.filter.all": "All",
-  "notifications.filter.boosts": "Boosts",
-  "notifications.filter.favourites": "Favourites",
-  "notifications.filter.follows": "Follows",
-  "notifications.filter.mentions": "Mentions",
-  "notifications.filter.polls": "Poll results",
+  "notifications.filter.all": "Все",
+  "notifications.filter.boosts": "Продвижения",
+  "notifications.filter.favourites": "Отметки \"нравится\"",
+  "notifications.filter.follows": "Новые подписчики",
+  "notifications.filter.mentions": "Упоминания",
+  "notifications.filter.polls": "Результаты опросов",
   "notifications.group": "{count} уведомл.",
-  "poll.closed": "Closed",
-  "poll.refresh": "Refresh",
-  "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
-  "poll.vote": "Vote",
-  "poll_button.add_poll": "Add a poll",
-  "poll_button.remove_poll": "Remove poll",
+  "poll.closed": "Завершён",
+  "poll.refresh": "Обновить",
+  "poll.total_votes": "{count, plural, one {# голос} few {# голоса} many {# голосов} other {# голосов}}",
+  "poll.vote": "Голосовать",
+  "poll_button.add_poll": "Добавить опрос",
+  "poll_button.remove_poll": "Удалить опрос",
   "privacy.change": "Изменить видимость статуса",
   "privacy.direct.long": "Показать только упомянутым",
   "privacy.direct.short": "Направленный",
@@ -292,12 +294,12 @@
   "relative_time.minutes": "{number}м",
   "relative_time.seconds": "{number}с",
   "reply_indicator.cancel": "Отмена",
-  "report.forward": "Переслать для {target}",
+  "report.forward": "Переслать в {target}",
   "report.forward_hint": "Этот аккаунт расположен на другом сервере. Отправить туда анонимную копию Вашей жалобы?",
   "report.hint": "Жалоба будет отправлена модераторам Вашего сервера. Вы также можете указать подробную причину жалобы ниже:",
   "report.placeholder": "Комментарий",
   "report.submit": "Отправить",
-  "report.target": "Жалуемся на {target}",
+  "report.target": "Жалоба на {target}",
   "search.placeholder": "Поиск",
   "search_popout.search_format": "Продвинутый формат поиска",
   "search_popout.tips.full_text": "Возвращает посты, которые Вы написали, отметили как 'избранное', продвинули или в которых были упомянуты, а также содержащие юзернейм, имя и хэштеги.",
@@ -309,12 +311,12 @@
   "search_results.hashtags": "Хэштеги",
   "search_results.statuses": "Посты",
   "search_results.total": "{count, number} {count, plural, one {результат} few {результата} many {результатов} other {результатов}}",
-  "status.admin_account": "Open moderation interface for @{name}",
-  "status.admin_status": "Open this status in the moderation interface",
+  "status.admin_account": "Открыть интерфейс модератора для @{name}",
+  "status.admin_status": "Открыть этот статус в интерфейсе модератора",
   "status.block": "Заблокировать @{name}",
   "status.cancel_reblog_private": "Не продвигать",
   "status.cannot_reblog": "Этот статус не может быть продвинут",
-  "status.copy": "Copy link to status",
+  "status.copy": "Копировать ссылку на запись",
   "status.delete": "Удалить",
   "status.detailed_status": "Подробный просмотр обсуждения",
   "status.direct": "Написать @{name}",
@@ -326,11 +328,11 @@
   "status.mention": "Упомянуть @{name}",
   "status.more": "Больше",
   "status.mute": "Заглушить @{name}",
-  "status.mute_conversation": "Заглушить всю цепочку",
+  "status.mute_conversation": "Заглушить всё обсуждение",
   "status.open": "Развернуть статус",
   "status.pin": "Закрепить в профиле",
   "status.pinned": "Закреплённый статус",
-  "status.read_more": "Read more",
+  "status.read_more": "Ещё",
   "status.reblog": "Продвинуть",
   "status.reblog_private": "Продвинуть для своей аудитории",
   "status.reblogged_by": "{name} продвинул(а)",
@@ -346,27 +348,27 @@
   "status.show_less_all": "Свернуть для всех",
   "status.show_more": "Развернуть",
   "status.show_more_all": "Развернуть для всех",
-  "status.show_thread": "Show thread",
-  "status.unmute_conversation": "Снять глушение с треда",
+  "status.show_thread": "Показать обсуждение",
+  "status.unmute_conversation": "Снять глушение с обсуждения",
   "status.unpin": "Открепить от профиля",
-  "suggestions.dismiss": "Dismiss suggestion",
-  "suggestions.header": "You might be interested in…",
+  "suggestions.dismiss": "Удалить предложение",
+  "suggestions.header": "Вам может быть интересно…",
   "tabs_bar.federated_timeline": "Глобальная",
   "tabs_bar.home": "Главная",
   "tabs_bar.local_timeline": "Локальная",
   "tabs_bar.notifications": "Уведомления",
   "tabs_bar.search": "Поиск",
-  "time_remaining.days": "{number, plural, one {# day} other {# days}} left",
-  "time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left",
-  "time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left",
-  "time_remaining.moments": "Moments remaining",
-  "time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left",
+  "time_remaining.days": "{number, plural, one {остался # день} few {осталось # дня} many {осталось # дней} other {осталось # дней}}",
+  "time_remaining.hours": "{number, plural, one {остался # час} few {осталось # часа} many {осталось # часов} other {осталось # часов}}",
+  "time_remaining.minutes": "{number, plural, one {осталась # минута} few {осталось # минуты} many {осталось # минут} other {осталось # минут}}",
+  "time_remaining.moments": "остались считанные мгновения",
+  "time_remaining.seconds": "{number, plural, one {осталась # секунду} few {осталось # секунды} many {осталось # секунд} other {осталось # секунд}}",
   "trends.count_by_accounts": "Популярно у {count} {rawCount, plural, one {человека} few {человек} many {человек} other {человек}}",
   "ui.beforeunload": "Ваш черновик будет утерян, если вы покинете Mastodon.",
   "upload_area.title": "Перетащите сюда, чтобы загрузить",
   "upload_button.label": "Добавить медиаконтент",
-  "upload_error.limit": "File upload limit exceeded.",
-  "upload_error.poll": "File upload not allowed with polls.",
+  "upload_error.limit": "Достигнут лимит загруженных файлов.",
+  "upload_error.poll": "К опросам нельзя прикреплять файлы.",
   "upload_form.description": "Описать для людей с нарушениями зрения",
   "upload_form.focus": "Обрезать",
   "upload_form.undo": "Отменить",
diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json
index 5542198f7..c4fcb9f18 100644
--- a/app/javascript/mastodon/locales/sk.json
+++ b/app/javascript/mastodon/locales/sk.json
@@ -6,7 +6,7 @@
   "account.blocked": "Blokovaný/á",
   "account.direct": "Súkromná správa pre @{name}",
   "account.domain_blocked": "Doména ukrytá",
-  "account.edit_profile": "Upraviť profil",
+  "account.edit_profile": "Uprav profil",
   "account.endorse": "Zobrazuj na profile",
   "account.follow": "Následuj",
   "account.followers": "Sledujúci",
@@ -14,38 +14,38 @@
   "account.follows": "Následuje",
   "account.follows.empty": "Tento užívateľ ešte nikoho nenásleduje.",
   "account.follows_you": "Následuje ťa",
-  "account.hide_reblogs": "Skryť povýšenia od @{name}",
+  "account.hide_reblogs": "Skry vyzdvihnutia od @{name}",
   "account.link_verified_on": "Vlastníctvo tohto odkazu bolo skontrolované {date}",
   "account.locked_info": "Stav súkromia pre tento účet je nastavený na zamknutý. Jeho vlastník sám prehodnocuje, kto ho môže sledovať.",
   "account.media": "Médiá",
   "account.mention": "Spomeň @{name}",
   "account.moved_to": "{name} sa presunul/a na:",
   "account.mute": "Ignorovať @{name}",
-  "account.mute_notifications": "Stĺmiť oboznámenia od @{name}",
+  "account.mute_notifications": "Stĺm oboznámenia od @{name}",
   "account.muted": "Utíšený/á",
   "account.posts": "Príspevky",
   "account.posts_with_replies": "Príspevky aj s odpoveďami",
   "account.report": "Nahlás @{name}",
-  "account.requested": "Čaká na schválenie. Kliknite pre zrušenie žiadosti",
-  "account.share": "Zdieľať @{name} profil",
+  "account.requested": "Čaká na schválenie. Klikni pre zrušenie žiadosti",
+  "account.share": "Zdieľaj @{name} profil",
   "account.show_reblogs": "Ukáž vyzdvihnutia od @{name}",
   "account.unblock": "Odblokuj @{name}",
   "account.unblock_domain": "Prestaň skrývať {domain}",
   "account.unendorse": "Nezobrazuj na profile",
   "account.unfollow": "Prestaň následovať",
   "account.unmute": "Prestaň ignorovať @{name}",
-  "account.unmute_notifications": "Zrušiť stlmenie oznámení od @{name}",
+  "account.unmute_notifications": "Zruš stĺmenie oboznámení od @{name}",
   "alert.unexpected.message": "Vyskytla sa nečakaná chyba.",
   "alert.unexpected.title": "Oops!",
   "boost_modal.combo": "Nabudúce môžeš kliknúť {combo} pre preskočenie",
   "bundle_column_error.body": "Pri načítaní tohto prvku nastala nejaká chyba.",
   "bundle_column_error.retry": "Skús to znova",
   "bundle_column_error.title": "Chyba siete",
-  "bundle_modal_error.close": "Zatvoriť",
+  "bundle_modal_error.close": "Zatvor",
   "bundle_modal_error.message": "Nastala chyba pri načítaní tohto komponentu.",
   "bundle_modal_error.retry": "Skúsiť znova",
   "column.blocks": "Blokovaní užívatelia",
-  "column.community": "Lokálna časová os",
+  "column.community": "Miestna časová os",
   "column.direct": "Súkromné správy",
   "column.domain_blocks": "Skryté domény",
   "column.favourites": "Obľúbené",
@@ -64,11 +64,11 @@
   "column_header.show_settings": "Ukáž nastavenia",
   "column_header.unpin": "Odopnúť",
   "column_subheading.settings": "Nastavenia",
-  "community.column_settings.media_only": "Iba media",
+  "community.column_settings.media_only": "Iba médiá",
   "compose_form.direct_message_warning": "Tento príspevok bude videný výhradne iba spomenutými užívateľmi. Ber ale na vedomie že správci tvojej a všetkých iných zahrnutých instancií majú možnosť skontrolovať túto správu.",
   "compose_form.direct_message_warning_learn_more": "Zistiť viac",
   "compose_form.hashtag_warning": "Tento toot nebude zobrazený pod žiadným haštagom lebo nieje listovaný. Iba verejné tooty môžu byť nájdené podľa haštagu.",
-  "compose_form.lock_disclaimer": "Váš účet nie je {locked}. Ktokoľvek ťa môže nasledovať a vidieť tvoje správy pre sledujúcich.",
+  "compose_form.lock_disclaimer": "Tvoj účet nie je {locked}. Ktokoľvek ťa môže nasledovať a vidieť tvoje správy pre sledujúcich.",
   "compose_form.lock_disclaimer.lock": "zamknutý",
   "compose_form.placeholder": "Čo máš na mysli?",
   "compose_form.poll.add_option": "Pridaj voľbu",
@@ -90,33 +90,34 @@
   "confirmations.delete.message": "Si si istý/á, že chceš vymazať túto správu?",
   "confirmations.delete_list.confirm": "Vymaž",
   "confirmations.delete_list.message": "Si si istý/á, že chceš natrvalo vymazať tento zoznam?",
-  "confirmations.domain_block.confirm": "Skryť celú doménu",
-  "confirmations.domain_block.message": "Si si naozaj istý, že chceš blokovať celú {domain}? Vo väčšine prípadov stačí blokovať alebo ignorovať pár konkrétnych užívateľov, čo sa doporučuje. Neuvidíš obsah z tejto domény v žiadnej verejnej časovej osi, ani v oznámeniach. Tvoji následovníci pochádzajúci z tejto domény budú odstránení.",
+  "confirmations.domain_block.confirm": "Skry celú doménu",
+  "confirmations.domain_block.message": "Si si naozaj istý/á, že chceš blokovať celú doménu {domain}? Vo väčšine prípadov stačí blokovať alebo ignorovať pár konkrétnych užívateľov, čo sa doporučuje. Neuvidíš obsah z tejto domény v žiadnej verejnej časovej osi, ani v oznámeniach. Tvoji následovníci pochádzajúci z tejto domény budú odstránení.",
   "confirmations.mute.confirm": "Ignoruj",
-  "confirmations.mute.message": "Naozaj chcete ignorovať {name}?",
-  "confirmations.redraft.confirm": "Vyčistiť a prepísať",
+  "confirmations.mute.message": "Naozaj chceš ignorovať {name}?",
+  "confirmations.redraft.confirm": "Vyčisti a prepíš",
   "confirmations.redraft.message": "Si si istý/á, že chceš premazať a prepísať tento príspevok? Jeho nadobudnuté vyzdvihnutia a obľúbenia, ale i odpovede na pôvodný príspevok budú odlúčené.",
   "confirmations.reply.confirm": "Odpovedz",
   "confirmations.reply.message": "Odpovedaním akurát teraz prepíšeš správu, ktorú máš práve rozpísanú. Si si istý/á, že chceš pokračovať?",
-  "confirmations.unfollow.confirm": "Nesledovať",
-  "confirmations.unfollow.message": "Naozaj chcete prestať sledovať {name}?",
+  "confirmations.unfollow.confirm": "Nesleduj",
+  "confirmations.unfollow.message": "Naozaj chceš prestať sledovať {name}?",
   "embed.instructions": "Umiestni kód uvedený nižšie pre pridanie tohto statusu na tvoju web stránku.",
   "embed.preview": "Tu je ako to bude vyzerať:",
   "emoji_button.activity": "Aktivita",
   "emoji_button.custom": "Vlastné",
   "emoji_button.flags": "Vlajky",
   "emoji_button.food": "Jedlá a nápoje",
-  "emoji_button.label": "Vložiť emotikony",
+  "emoji_button.label": "Vlož emotikony",
   "emoji_button.nature": "Prírodné",
   "emoji_button.not_found": "Nie emotikony!! (╯°□°)╯︵ ┻━┻",
   "emoji_button.objects": "Predmety",
   "emoji_button.people": "Ľudia",
   "emoji_button.recent": "Často používané",
-  "emoji_button.search": "Hľadať...",
+  "emoji_button.search": "Hľadaj...",
   "emoji_button.search_results": "Nájdené",
   "emoji_button.symbols": "Symboly",
   "emoji_button.travel": "Cestovanie a miesta",
   "empty_column.account_timeline": "Niesú tu žiadne príspevky!",
+  "empty_column.account_unavailable": "Profil nedostupný",
   "empty_column.blocks": "Ešte si nikoho nezablokoval/a.",
   "empty_column.community": "Lokálna časová os je prázdna. Napíšte niečo, aby sa to tu začalo hýbať!",
   "empty_column.direct": "Ešte nemáš žiadne súkromné správy. Keď nejakú pošleš, alebo dostaneš, ukáže sa tu.",
@@ -158,16 +159,16 @@
   "intervals.full.hours": "{number, plural, one {# hodina} few {# hodín} many {# hodín} other {# hodiny}}",
   "intervals.full.minutes": "{number, plural, one {# minúta} few {# minút} many {# minút} other {# minúty}}",
   "introduction.federation.action": "Ďalej",
-  "introduction.federation.federated.headline": "Federated",
-  "introduction.federation.federated.text": "Verejné príspevky z ostatných serverov vo fediverse budú zobrazenie vo federovanej časovej osi.",
-  "introduction.federation.home.headline": "Home",
+  "introduction.federation.federated.headline": "Federovaná",
+  "introduction.federation.federated.text": "Verejné príspevky z ostatných serverov vo fediverse budú zobrazené vo federovanej časovej osi.",
+  "introduction.federation.home.headline": "Domovská",
   "introduction.federation.home.text": "Príspevky od ľudí ktorých následuješ sa zobrazia na tvojej domovskej nástenke. Môžeš následovať hocikoho na ktoromkoľvek serveri!",
-  "introduction.federation.local.headline": "Local",
+  "introduction.federation.local.headline": "Miestna",
   "introduction.federation.local.text": "Verejné príspevky od ľudí v rámci toho istého serveru na akom si aj ty, budú zobrazované na miestnej časovej osi.",
   "introduction.interactions.action": "Ukonči návod!",
   "introduction.interactions.favourite.headline": "Obľúbené",
   "introduction.interactions.favourite.text": "Obľúbením si môžeš príspevok uložiť na neskôr, a zároveň dať jeho autorovi vedieť, že sa ti páčil.",
-  "introduction.interactions.reblog.headline": "Povýš",
+  "introduction.interactions.reblog.headline": "Vyzdvihni",
   "introduction.interactions.reblog.text": "Môžeš zdieľať príspevky iných ľudí s vašimi následovateľmi tým, že ich povýšiš.",
   "introduction.interactions.reply.headline": "Odpovedz",
   "introduction.interactions.reply.text": "Odpovedať môžeš na príspevky iných ľudí, aj na svoje vlastné, čím sa spolu prepoja do konverzácie.",
@@ -177,61 +178,61 @@
   "keyboard_shortcuts.back": "dostať sa naspäť",
   "keyboard_shortcuts.blocked": "otvor zoznam blokovaných užívateľov",
   "keyboard_shortcuts.boost": "vyzdvihnúť",
-  "keyboard_shortcuts.column": "zamerať sa na status v jednom zo stĺpcov",
-  "keyboard_shortcuts.compose": "zamerať sa na písaciu plochu",
+  "keyboard_shortcuts.column": "zameraj sa na príspevok v jednom zo stĺpcov",
+  "keyboard_shortcuts.compose": "zameraj sa na písaciu plochu",
   "keyboard_shortcuts.description": "Popis",
   "keyboard_shortcuts.direct": "otvor panel súkromných správ",
   "keyboard_shortcuts.down": "posunúť sa dole v zozname",
   "keyboard_shortcuts.enter": "otvoriť správu",
-  "keyboard_shortcuts.favourite": "pridať do obľúbených",
+  "keyboard_shortcuts.favourite": "pridaj do obľúbených",
   "keyboard_shortcuts.favourites": "otvor zoznam obľúbených",
   "keyboard_shortcuts.federated": "otvor federovanú časovú os",
   "keyboard_shortcuts.heading": "Klávesové skratky",
   "keyboard_shortcuts.home": "otvor domácu časovú os",
   "keyboard_shortcuts.hotkey": "Klávesa",
-  "keyboard_shortcuts.legend": "zobraziť túto legendu",
+  "keyboard_shortcuts.legend": "zobraz túto legendu",
   "keyboard_shortcuts.local": "otvor miestnu časovú os",
-  "keyboard_shortcuts.mention": "spomenúť autora",
+  "keyboard_shortcuts.mention": "spomeň autora",
   "keyboard_shortcuts.muted": "otvor zoznam stíšených užívateľov",
   "keyboard_shortcuts.my_profile": "otvor svoj profil",
   "keyboard_shortcuts.notifications": "otvor panel oboznámení",
   "keyboard_shortcuts.pinned": "otvor zoznam pripnutých príspevkov",
   "keyboard_shortcuts.profile": "otvor autorov profil",
   "keyboard_shortcuts.reply": "odpovedať",
-  "keyboard_shortcuts.requests": "otvor zoznam požiadavok k následovaniu",
-  "keyboard_shortcuts.search": "zamerať sa na vyhľadávanie",
+  "keyboard_shortcuts.requests": "otvor zoznam žiadostí o sledovanie",
+  "keyboard_shortcuts.search": "zameraj sa na vyhľadávanie",
   "keyboard_shortcuts.start": "otvor panel ''začíname''",
   "keyboard_shortcuts.toggle_hidden": "ukáž/skry text za CW",
-  "keyboard_shortcuts.toot": "začať úplne novú hlášku",
-  "keyboard_shortcuts.unfocus": "nesústrediť sa na písaciu plochu, alebo hľadanie",
-  "keyboard_shortcuts.up": "posunúť sa vyššie v zozname",
-  "lightbox.close": "Zatvoriť",
+  "keyboard_shortcuts.toot": "začni úplne nový príspevok",
+  "keyboard_shortcuts.unfocus": "nesústreď sa na písaciu plochu, alebo hľadanie",
+  "keyboard_shortcuts.up": "posuň sa vyššie v zozname",
+  "lightbox.close": "Zatvor",
   "lightbox.next": "Ďalšie",
   "lightbox.previous": "Predchádzajúci",
-  "lists.account.add": "Pridať do zoznamu",
-  "lists.account.remove": "Odobrať zo zoznamu",
-  "lists.delete": "Vymazať list",
+  "lists.account.add": "Pridaj do zoznamu",
+  "lists.account.remove": "Odober zo zoznamu",
+  "lists.delete": "Vymaž list",
   "lists.edit": "Uprav zoznam",
   "lists.edit.submit": "Zmeň názov",
   "lists.new.create": "Pridaj zoznam",
   "lists.new.title_placeholder": "Názov nového zoznamu",
-  "lists.search": "Vyhľadávajte medzi užívateľmi ktorých sledujete",
+  "lists.search": "Vyhľadávaj medzi užívateľmi, ktorých sleduješ",
   "lists.subheading": "Tvoje zoznamy",
   "loading_indicator.label": "Načítam...",
-  "media_gallery.toggle_visible": "Zapnúť/Vypnúť viditeľnosť",
+  "media_gallery.toggle_visible": "Zapni/Vypni viditeľnosť",
   "missing_indicator.label": "Nenájdené",
   "missing_indicator.sublabel": "Tento zdroj sa ešte nepodarilo nájsť",
-  "mute_modal.hide_notifications": "Skryť oznámenia od tohto používateľa?",
-  "navigation_bar.apps": "Mobilné aplikácie",
+  "mute_modal.hide_notifications": "Skry oznámenia od tohto používateľa?",
+  "navigation_bar.apps": "Aplikácie",
   "navigation_bar.blocks": "Blokovaní užívatelia",
-  "navigation_bar.community_timeline": "Lokálna časová os",
+  "navigation_bar.community_timeline": "Miestna časová os",
   "navigation_bar.compose": "Napíš nový príspevok",
   "navigation_bar.direct": "Súkromné správy",
   "navigation_bar.discover": "Objavuj",
   "navigation_bar.domain_blocks": "Skryté domény",
-  "navigation_bar.edit_profile": "Upraviť profil",
+  "navigation_bar.edit_profile": "Uprav profil",
   "navigation_bar.favourites": "Obľúbené",
-  "navigation_bar.filters": "Utĺmené slová",
+  "navigation_bar.filters": "Filtrované slová",
   "navigation_bar.follow_requests": "Žiadosti o sledovanie",
   "navigation_bar.info": "O tomto serveri",
   "navigation_bar.keyboard_shortcuts": "Klávesové skratky",
@@ -239,7 +240,7 @@
   "navigation_bar.logout": "Odhlás sa",
   "navigation_bar.mutes": "Ignorovaní užívatelia",
   "navigation_bar.personal": "Osobné",
-  "navigation_bar.pins": "Pripnuté tooty",
+  "navigation_bar.pins": "Pripnuté príspevky",
   "navigation_bar.preferences": "Voľby",
   "navigation_bar.public_timeline": "Federovaná časová os",
   "navigation_bar.security": "Zabezbečenie",
@@ -247,21 +248,21 @@
   "notification.follow": "{name} ťa začal/a následovať",
   "notification.mention": "{name} ťa spomenul/a",
   "notification.poll": "Anketa v ktorej si hlasoval/a sa skončila",
-  "notification.reblog": "{name} zdieľal/a tvoj status",
-  "notifications.clear": "Vyčistiť zoznam notifikácii",
-  "notifications.clear_confirmation": "Naozaj chcete nenávratne prečistiť všetky vaše notifikácie?",
-  "notifications.column_settings.alert": "Notifikácie na ploche",
+  "notification.reblog": "{name} zdieľal/a tvoj príspevok",
+  "notifications.clear": "Vyčistiť zoznam oboznámení",
+  "notifications.clear_confirmation": "Naozaj chceš nenávratne prečistiť všetky tvoje oboznámenia?",
+  "notifications.column_settings.alert": "Oboznámenia na ploche",
   "notifications.column_settings.favourite": "Obľúbené:",
   "notifications.column_settings.filter_bar.advanced": "Zobraz všetky kategórie",
   "notifications.column_settings.filter_bar.category": "Rýchle triedenie",
   "notifications.column_settings.filter_bar.show": "Ukáž",
-  "notifications.column_settings.follow": "Noví následujúci:",
+  "notifications.column_settings.follow": "Noví sledujúci:",
   "notifications.column_settings.mention": "Zmienenia:",
   "notifications.column_settings.poll": "Výsledky ankiet:",
   "notifications.column_settings.push": "Push notifikácie",
-  "notifications.column_settings.reblog": "Boosty:",
-  "notifications.column_settings.show": "Zobraziť v stĺpci",
-  "notifications.column_settings.sound": "Prehrať zvuk",
+  "notifications.column_settings.reblog": "Vyzdvihnutia:",
+  "notifications.column_settings.show": "Zobraz v stĺpci",
+  "notifications.column_settings.sound": "Prehraj zvuk",
   "notifications.filter.all": "Všetky",
   "notifications.filter.boosts": "Vyzdvihnutia",
   "notifications.filter.favourites": "Obľúbené",
@@ -276,13 +277,13 @@
   "poll_button.add_poll": "Pridaj anketu",
   "poll_button.remove_poll": "Odstráň anketu",
   "privacy.change": "Uprav súkromie príspevku",
-  "privacy.direct.long": "Pošli iba spomenutým používateľom",
+  "privacy.direct.long": "Pošli iba spomenutým užívateľom",
   "privacy.direct.short": "Súkromne",
-  "privacy.private.long": "Poslať iba následovateľom",
+  "privacy.private.long": "Pošli iba následovateľom",
   "privacy.private.short": "Iba pre sledujúcich",
-  "privacy.public.long": "Poslať všetkým verejne",
+  "privacy.public.long": "Pošli všetkým verejne",
   "privacy.public.short": "Verejné",
-  "privacy.unlisted.long": "Neposielať do verejných časových osí",
+  "privacy.unlisted.long": "Neposielaj do verejných časových osí",
   "privacy.unlisted.short": "Verejne, ale nezobraziť v osi",
   "regeneration_indicator.label": "Načítava sa…",
   "regeneration_indicator.sublabel": "Vaša domovská nástenka sa pripravuje!",
@@ -293,11 +294,11 @@
   "relative_time.seconds": "{number}s",
   "reply_indicator.cancel": "Zrušiť",
   "report.forward": "Posuň ku {target}",
-  "report.forward_hint": "Tento účet je z iného serveru. Chceš poslať anonymnú kópiu reportu aj tam?",
+  "report.forward_hint": "Tento účet je z iného serveru. Chceš poslať anonymnú kópiu hlásenia aj tam?",
   "report.hint": "Toto nahlásenie bude zaslané správcom tvojho servera. Môžeš napísať odvôvodnenie, prečo nahlasuješ tento účet:",
   "report.placeholder": "Ďalšie komentáre",
-  "report.submit": "Poslať",
-  "report.target": "Nahlásenie {target}",
+  "report.submit": "Odošli",
+  "report.target": "Nahlás {target}",
   "search.placeholder": "Hľadaj",
   "search_popout.search_format": "Pokročilé vyhľadávanie",
   "search_popout.tips.full_text": "Vráti jednoduchý textový výpis príspevkov ktoré si napísal/a, ktoré si obľúbil/a, povýšil/a, alebo aj tých, v ktorých si bol/a spomenutý/á, a potom všetky zadaniu odpovedajúce prezívky, mená a haštagy.",
@@ -311,9 +312,9 @@
   "search_results.total": "{count, number} {count, plural, one {výsledok} many {výsledkov} other {výsledky}}",
   "status.admin_account": "Otvor moderovacie rozhranie užívateľa @{name}",
   "status.admin_status": "Otvor tento príspevok v moderovacom rozhraní",
-  "status.block": "Blokovať @{name}",
+  "status.block": "Blokuj @{name}",
   "status.cancel_reblog_private": "Nezdieľaj",
-  "status.cannot_reblog": "Tento príspevok nemôže byť re-tootnutý",
+  "status.cannot_reblog": "Tento príspevok nemôže byť zdieľaný",
   "status.copy": "Skopíruj odkaz na príspevok",
   "status.delete": "Zmazať",
   "status.detailed_status": "Podrobný náhľad celej konverzácie",
@@ -325,23 +326,23 @@
   "status.media_hidden": "Skryté médiá",
   "status.mention": "Spomeň @{name}",
   "status.more": "Viac",
-  "status.mute": "Utíšiť @{name}",
-  "status.mute_conversation": "Ignorovať konverzáciu",
-  "status.open": "Otvoriť tento status",
+  "status.mute": "Utíš @{name}",
+  "status.mute_conversation": "Ignoruj konverzáciu",
+  "status.open": "Otvor tento príspevok",
   "status.pin": "Pripni na profil",
   "status.pinned": "Pripnutý príspevok",
   "status.read_more": "Čítaj ďalej",
-  "status.reblog": "Povýšiť",
-  "status.reblog_private": "Povýš k pôvodnému publiku",
+  "status.reblog": "Vyzdvihni",
+  "status.reblog_private": "Vyzdvihni k pôvodnému publiku",
   "status.reblogged_by": "{name} povýšil/a",
-  "status.reblogs.empty": "Nikto ešte nepovýšil tento príspevok. Keď tak niekto urobí, bude to zobrazené práve tu.",
+  "status.reblogs.empty": "Nikto ešte nevyzdvihol tento príspevok. Keď tak niekto urobí, bude to zobrazené práve tu.",
   "status.redraft": "Vymaž a prepíš",
   "status.reply": "Odpovedať",
-  "status.replyAll": "Odpovedať na diskusiu",
-  "status.report": "Nahlásiť @{name}",
+  "status.replyAll": "Odpovedz na diskusiu",
+  "status.report": "Nahlás @{name}",
   "status.sensitive_toggle": "Klikni pre zobrazenie",
   "status.sensitive_warning": "Chúlostivý obsah",
-  "status.share": "Zdieľať",
+  "status.share": "Zdieľaj",
   "status.show_less": "Zobraz menej",
   "status.show_less_all": "Všetkým ukáž menej",
   "status.show_more": "Ukáž viac",
@@ -352,32 +353,32 @@
   "suggestions.dismiss": "Zavrhni návrh",
   "suggestions.header": "Mohlo by ťa zaujímať…",
   "tabs_bar.federated_timeline": "Federovaná",
-  "tabs_bar.home": "Domov",
-  "tabs_bar.local_timeline": "Lokálna",
-  "tabs_bar.notifications": "Notifikácie",
+  "tabs_bar.home": "Domovská",
+  "tabs_bar.local_timeline": "Miestna",
+  "tabs_bar.notifications": "Oboznámenia",
   "tabs_bar.search": "Hľadaj",
-  "time_remaining.days": "Zostáva {number, plural, one {# deň} few {# dní} many {# dni} other {# dni}}",
-  "time_remaining.hours": "Zostáva {number, plural, one {# hodina} few {# hodín} many {# hodín} other {# hodiny}}",
-  "time_remaining.minutes": "Zostáva {number, plural, one {# minúta} few {# minút} many {# minút} other {# minúty}}",
+  "time_remaining.days": "Ostáva {number, plural, one {# deň} few {# dní} many {# dni} other {# dni}}",
+  "time_remaining.hours": "Ostáva {number, plural, one {# hodina} few {# hodín} many {# hodín} other {# hodiny}}",
+  "time_remaining.minutes": "Ostáva {number, plural, one {# minúta} few {# minút} many {# minút} other {# minúty}}",
   "time_remaining.moments": "Ostáva už iba chviľka",
-  "time_remaining.seconds": "Zostáva {number, plural, one {# sekunda} few {# sekúnd} many {# sekúnd} other {# sekundy}}",
+  "time_remaining.seconds": "Ostáva {number, plural, one {# sekunda} few {# sekúnd} many {# sekúnd} other {# sekundy}}",
   "trends.count_by_accounts": "{count} {rawCount, plural, one {človek vraví} other {ľudia vravia}}",
   "ui.beforeunload": "Čo máš rozpísané sa stratí, ak opustíš Mastodon.",
   "upload_area.title": "Pretiahni a pusť pre nahratie",
-  "upload_button.label": "Pridať médiálny súbor (JPEG, PNG, GIF, WebM, MP4, MOV)",
+  "upload_button.label": "Pridaj médiálny súbor (JPEG, PNG, GIF, WebM, MP4, MOV)",
   "upload_error.limit": "Limit pre nahrávanie súborov bol prekročený.",
-  "upload_error.poll": "Nahrávanie súborov pri anketách nieje dovolené.",
+  "upload_error.poll": "Nahrávanie súborov pri anketách nieje možné.",
   "upload_form.description": "Opis pre slabo vidiacich",
   "upload_form.focus": "Pozmeň náhľad",
   "upload_form.undo": "Vymaž",
   "upload_progress.label": "Nahráva sa...",
-  "video.close": "Zavrieť video",
-  "video.exit_fullscreen": "Vpnúť zobrazenie na celú obrazovku",
-  "video.expand": "Zväčšiť video",
-  "video.fullscreen": "Zobraziť na celú obrazovku",
-  "video.hide": "Skryť video",
-  "video.mute": "Vypnúť zvuk",
+  "video.close": "Zavri video",
+  "video.exit_fullscreen": "Vypni zobrazenie na celú obrazovku",
+  "video.expand": "Zväčši video",
+  "video.fullscreen": "Zobraz na celú obrazovku",
+  "video.hide": "Skry video",
+  "video.mute": "Vypni zvuk",
   "video.pause": "Pauza",
-  "video.play": "Prehrať",
-  "video.unmute": "Zapnúť zvuk"
+  "video.play": "Prehraj",
+  "video.unmute": "Zapni zvuk"
 }
diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json
index bef4efe0e..f7a294cfe 100644
--- a/app/javascript/mastodon/locales/sl.json
+++ b/app/javascript/mastodon/locales/sl.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Simboli",
   "emoji_button.travel": "Potovanja in Kraji",
   "empty_column.account_timeline": "No toots here!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "Niste še blokirali nobenega uporabnika.",
   "empty_column.community": "Lokalna časovnica je prazna. Napišite nekaj javnega, da se bo žoga zakotalila!",
   "empty_column.direct": "Nimate še nobenih neposrednih sporočil. Ko ga pošljete ali prejmete, se prikaže tukaj.",
diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json
index b86c6e2ee..89df633cc 100644
--- a/app/javascript/mastodon/locales/sq.json
+++ b/app/javascript/mastodon/locales/sq.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Simbole",
   "emoji_button.travel": "Udhëtime & Vende",
   "empty_column.account_timeline": "S’ka mesazhe këtu!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "S’keni bllokuar ende ndonjë përdorues.",
   "empty_column.community": "Rrjedha kohore vendore është e zbrazët. Shkruani diçka publikisht që t’i hyhet valles!",
   "empty_column.direct": "S’keni ende ndonjë mesazh të drejtpërdrejt. Kur dërgoni ose merrni një të tillë, ai do të shfaqet këtu.",
diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json
index 155935306..2fc5f985a 100644
--- a/app/javascript/mastodon/locales/sr-Latn.json
+++ b/app/javascript/mastodon/locales/sr-Latn.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Simboli",
   "emoji_button.travel": "Putovanja & mesta",
   "empty_column.account_timeline": "No toots here!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "You haven't blocked any users yet.",
   "empty_column.community": "Lokalna lajna je prazna. Napišite nešto javno da lajna produva!",
   "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json
index 1124ed8d5..2ae34adca 100644
--- a/app/javascript/mastodon/locales/sr.json
+++ b/app/javascript/mastodon/locales/sr.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Симболи",
   "emoji_button.travel": "Путовања и места",
   "empty_column.account_timeline": "No toots here!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "Још увек немате блокираних корисника.",
   "empty_column.community": "Локална временска линија је празна. Напишите нешто јавно да започнете!",
   "empty_column.direct": "Још увек немате директних порука. Када пошаљете или примите једну, појавиће се овде.",
diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json
index 9093637b3..71264ba52 100644
--- a/app/javascript/mastodon/locales/sv.json
+++ b/app/javascript/mastodon/locales/sv.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Symboler",
   "emoji_button.travel": "Resor & Platser",
   "empty_column.account_timeline": "No toots here!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "You haven't blocked any users yet.",
   "empty_column.community": "Den lokala tidslinjen är tom. Skriv något offentligt för att få bollen att rulla!",
   "empty_column.direct": "Du har inga direktmeddelanden än. När du skickar eller tar emot kommer den att dyka upp här.",
diff --git a/app/javascript/mastodon/locales/ta.json b/app/javascript/mastodon/locales/ta.json
index eedd4c6f3..220cc86f9 100644
--- a/app/javascript/mastodon/locales/ta.json
+++ b/app/javascript/mastodon/locales/ta.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Symbols",
   "emoji_button.travel": "Travel & Places",
   "empty_column.account_timeline": "No toots here!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "You haven't blocked any users yet.",
   "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
   "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
diff --git a/app/javascript/mastodon/locales/te.json b/app/javascript/mastodon/locales/te.json
index c93ff63df..7e818c787 100644
--- a/app/javascript/mastodon/locales/te.json
+++ b/app/javascript/mastodon/locales/te.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "చిహ్నాలు",
   "emoji_button.travel": "ప్రయాణం & ప్రదేశాలు",
   "empty_column.account_timeline": "ఇక్కడ ఏ టూట్లూ లేవు!No toots here!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "మీరు ఇంకా ఏ వినియోగదారులనూ బ్లాక్ చేయలేదు.",
   "empty_column.community": "స్థానిక కాలక్రమం ఖాళీగా ఉంది. మొదలుపెట్టడానికి బహిరంగంగా ఏదో ఒకటి వ్రాయండి!",
   "empty_column.direct": "మీకు ఇంకా ఏ ప్రత్యక్ష సందేశాలు లేవు. మీరు ఒకదాన్ని పంపినప్పుడు లేదా స్వీకరించినప్పుడు, అది ఇక్కడ చూపబడుతుంది.",
diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json
index e15382402..630543ada 100644
--- a/app/javascript/mastodon/locales/th.json
+++ b/app/javascript/mastodon/locales/th.json
@@ -7,7 +7,7 @@
   "account.direct": "ส่งข้อความโดยตรงถึง @{name}",
   "account.domain_blocked": "ซ่อนโดเมนอยู่",
   "account.edit_profile": "แก้ไขโปรไฟล์",
-  "account.endorse": "Feature on profile",
+  "account.endorse": "แสดงให้เห็นในโปรไฟล์",
   "account.follow": "ติดตาม",
   "account.followers": "ผู้ติดตาม",
   "account.followers.empty": "ยังไม่มีใครติดตามผู้ใช้นี้",
@@ -15,7 +15,7 @@
   "account.follows.empty": "ผู้ใช้นี้ยังไม่ได้ติดตามใคร",
   "account.follows_you": "ติดตามคุณ",
   "account.hide_reblogs": "ซ่อนการดันจาก @{name}",
-  "account.link_verified_on": "Ownership of this link was checked on {date}",
+  "account.link_verified_on": "ตรวจสอบความเป็นเจ้าของของลิงก์นี้เมื่อ {date}",
   "account.locked_info": "This account privacy status is set to locked. The owner manually reviews who can follow them.",
   "account.media": "สื่อ",
   "account.mention": "กล่าวถึง @{name}",
@@ -31,18 +31,18 @@
   "account.show_reblogs": "แสดงการดันจาก @{name}",
   "account.unblock": "เลิกปิดกั้น @{name}",
   "account.unblock_domain": "เลิกซ่อน {domain}",
-  "account.unendorse": "Don't feature on profile",
+  "account.unendorse": "ไม่แสดงให้เห็นในโปรไฟล์",
   "account.unfollow": "เลิกติดตาม",
   "account.unmute": "เลิกปิดเสียง @{name}",
   "account.unmute_notifications": "เลิกปิดเสียงการแจ้งเตือนจาก @{name}",
   "alert.unexpected.message": "เกิดข้อผิดพลาดที่ไม่คาดคิด",
   "alert.unexpected.title": "อุปส์!",
   "boost_modal.combo": "You can press {combo} to skip this next time",
-  "bundle_column_error.body": "Something went wrong while loading this component.",
+  "bundle_column_error.body": "มีบางอย่างผิดพลาดขณะโหลดส่วนประกอบนี้",
   "bundle_column_error.retry": "ลองอีกครั้ง",
   "bundle_column_error.title": "ข้อผิดพลาดเครือข่าย",
   "bundle_modal_error.close": "ปิด",
-  "bundle_modal_error.message": "Something went wrong while loading this component.",
+  "bundle_modal_error.message": "มีบางอย่างผิดพลาดขณะโหลดส่วนประกอบนี้",
   "bundle_modal_error.retry": "ลองอีกครั้ง",
   "column.blocks": "ผู้ใช้ที่ปิดกั้นอยู่",
   "column.community": "เส้นเวลาในเว็บ",
@@ -83,7 +83,7 @@
   "compose_form.spoiler.unmarked": "Text is not hidden",
   "compose_form.spoiler_placeholder": "เขียนคำเตือนของคุณที่นี่",
   "confirmation_modal.cancel": "ยกเลิก",
-  "confirmations.block.block_and_report": "Block & Report",
+  "confirmations.block.block_and_report": "ปิดกั้นแล้วรายงาน",
   "confirmations.block.confirm": "ปิดกั้น",
   "confirmations.block.message": "คุณแน่ใจหรือไม่ว่าต้องการปิดกั้น {name}?",
   "confirmations.delete.confirm": "ลบ",
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "สัญลักษณ์",
   "emoji_button.travel": "การเดินทางและสถานที่",
   "empty_column.account_timeline": "ไม่มีโพสต์ที่นี่!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "You haven't blocked any users yet.",
   "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
   "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
@@ -141,7 +142,7 @@
   "getting_started.invite": "เชิญผู้คน",
   "getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}.",
   "getting_started.security": "ความปลอดภัย",
-  "getting_started.terms": "Terms of service",
+  "getting_started.terms": "เงื่อนไขการให้บริการ",
   "hashtag.column_header.tag_mode.all": "และ {additional}",
   "hashtag.column_header.tag_mode.any": "หรือ {additional}",
   "hashtag.column_header.tag_mode.none": "โดยไม่มี {additional}",
diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json
index cbe1c5726..26eca8239 100644
--- a/app/javascript/mastodon/locales/tr.json
+++ b/app/javascript/mastodon/locales/tr.json
@@ -4,7 +4,7 @@
   "account.block": "Engelle @{name}",
   "account.block_domain": "{domain} alanından her şeyi gizle",
   "account.blocked": "Engellenmiş",
-  "account.direct": "Direct Message @{name}",
+  "account.direct": "Mesaj gönder : @{name}",
   "account.domain_blocked": "Alan adı gizlendi",
   "account.edit_profile": "Profili düzenle",
   "account.endorse": "Profildeki özellik",
@@ -19,28 +19,28 @@
   "account.locked_info": "Bu hesabın gizlilik durumu kilitli olarak ayarlanmış. Sahibi, onu kimin takip edebileceğini elle inceler.",
   "account.media": "Medya",
   "account.mention": "@{name} kullanıcısından bahset",
-  "account.moved_to": "{name} has moved to:",
+  "account.moved_to": "{name} şuraya taşındı:",
   "account.mute": "@{name} kullanıcısını sessize al",
   "account.mute_notifications": "@{name} kullanıcısının bildirimlerini kapat",
-  "account.muted": "Sessiz",
+  "account.muted": "Sesi kısık",
   "account.posts": "Gönderiler",
   "account.posts_with_replies": "Gönderiler ve yanıtlar",
   "account.report": "@{name} kullanıcısını bildir",
   "account.requested": "Onay bekliyor. Takip isteğini iptal etmek için tıklayın",
   "account.share": "@{name} kullanıcısının profilini paylaş",
-  "account.show_reblogs": "@{name} kullanıcısından boost'ları göster",
+  "account.show_reblogs": "@{name} kullanıcısından boostları göster",
   "account.unblock": "Engeli kaldır @{name}",
   "account.unblock_domain": "{domain} göster",
   "account.unendorse": "Profilde özellik yok",
   "account.unfollow": "Takipten vazgeç",
-  "account.unmute": "Sesi aç @{name}",
+  "account.unmute": "Sesi aç : @{name}",
   "account.unmute_notifications": "@{name} kullanıcısından bildirimleri aç",
   "alert.unexpected.message": "Beklenmedik bir hata oluştu.",
   "alert.unexpected.title": "Hay aksi!",
   "boost_modal.combo": "Bir dahaki sefere {combo} tuşuna basabilirsiniz",
   "bundle_column_error.body": "Bu bileşen yüklenirken bir şeyler ters gitti.",
   "bundle_column_error.retry": "Tekrar deneyin",
-  "bundle_column_error.title": "Network error",
+  "bundle_column_error.title": "Ağ hatası",
   "bundle_modal_error.close": "Kapat",
   "bundle_modal_error.message": "Bu bileşen yüklenirken bir şeyler ters gitti.",
   "bundle_modal_error.retry": "Tekrar deneyin",
@@ -54,7 +54,7 @@
   "column.lists": "Listeler",
   "column.mutes": "Susturulmuş kullanıcılar",
   "column.notifications": "Bildirimler",
-  "column.pins": "Pinned toot",
+  "column.pins": "Sabitlenmiş gönderi",
   "column.public": "Federe zaman tüneli",
   "column_back_button.label": "Geri",
   "column_header.hide_settings": "Ayarları gizle",
@@ -66,16 +66,16 @@
   "column_subheading.settings": "Ayarlar",
   "community.column_settings.media_only": "Sadece medya",
   "compose_form.direct_message_warning": "Bu gönderi sadece belirtilen kullanıcılara gönderilecektir.",
-  "compose_form.direct_message_warning_learn_more": "Daha fazla bilgi edin",
-  "compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
+  "compose_form.direct_message_warning_learn_more": "Daha fazla bilgi edinin",
+  "compose_form.hashtag_warning": "Bu paylaşım liste dışı olduğu için hiç bir hashtag'de yer almayacak. Sadece herkese açık gönderiler hashtaglerde bulunabilir.",
   "compose_form.lock_disclaimer": "Hesabınız {locked} değil. Sadece takipçilerle paylaştığınız gönderileri görebilmek için sizi herhangi bir kullanıcı takip edebilir.",
   "compose_form.lock_disclaimer.lock": "kilitli",
   "compose_form.placeholder": "Aklınızdan ne geçiyor?",
-  "compose_form.poll.add_option": "Add a choice",
-  "compose_form.poll.duration": "Poll duration",
-  "compose_form.poll.option_placeholder": "Choice {number}",
-  "compose_form.poll.remove_option": "Remove this choice",
-  "compose_form.publish": "Toot",
+  "compose_form.poll.add_option": "Bir seçenek ekleyin",
+  "compose_form.poll.duration": "Anket süresi",
+  "compose_form.poll.option_placeholder": "Seçim {number}",
+  "compose_form.poll.remove_option": "Bu seçimi kaldır",
+  "compose_form.publish": "Gönder",
   "compose_form.publish_loud": "{publish}!",
   "compose_form.sensitive.marked": "Medya hassas olarak işaretlendi",
   "compose_form.sensitive.unmarked": "Medya hassas olarak işaretlenmemiş",
@@ -83,24 +83,24 @@
   "compose_form.spoiler.unmarked": "Metin gizli değil",
   "compose_form.spoiler_placeholder": "İçerik uyarısı",
   "confirmation_modal.cancel": "İptal",
-  "confirmations.block.block_and_report": "Block & Report",
+  "confirmations.block.block_and_report": "Engelle & Bildir",
   "confirmations.block.confirm": "Engelle",
   "confirmations.block.message": "{name} kullanıcısını engellemek istiyor musunuz?",
   "confirmations.delete.confirm": "Sil",
   "confirmations.delete.message": "Bu gönderiyi silmek istiyor musunuz?",
-  "confirmations.delete_list.confirm": "Delete",
+  "confirmations.delete_list.confirm": "Sil",
   "confirmations.delete_list.message": "Bu listeyi kalıcı olarak silmek istediğinize emin misiniz?",
   "confirmations.domain_block.confirm": "Alan adının tamamını gizle",
-  "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.",
+  "confirmations.domain_block.message": "tüm {domain} alan adını engellemek istediğinizden emin misiniz? Genellikle birkaç hedefli engel ve susturma işi görür ve tercih edilir.",
   "confirmations.mute.confirm": "Sessize al",
   "confirmations.mute.message": "{name} kullanıcısını sessize almak istiyor musunuz?",
   "confirmations.redraft.confirm": "Sil ve yeniden tasarla",
-  "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
+  "confirmations.redraft.message": "Bu durumu silip tekrar taslaklaştırmak istediğinizden emin misiniz? Tüm cevapları, boostları ve favorileri kaybedeceksiniz.",
   "confirmations.reply.confirm": "Yanıtla",
   "confirmations.reply.message": "Şimdi yanıtlarken o an oluşturduğunuz mesajın üzerine yazılır. Devam etmek istediğinize emin misiniz?",
   "confirmations.unfollow.confirm": "Takibi kaldır",
-  "confirmations.unfollow.message": "Are you sure you want to unfollow {name}?",
-  "embed.instructions": "Embed this status on your website by copying the code below.",
+  "confirmations.unfollow.message": "{name}'yi takipten çıkarmak istediğinizden emin misiniz?",
+  "embed.instructions": "Aşağıdaki kodu kopyalayarak bu durumu sitenize gömün.",
   "embed.preview": "İşte nasıl görüneceği:",
   "emoji_button.activity": "Aktivite",
   "emoji_button.custom": "Özel",
@@ -112,22 +112,23 @@
   "emoji_button.objects": "Nesneler",
   "emoji_button.people": "İnsanlar",
   "emoji_button.recent": "Sık kullanılan",
-  "emoji_button.search": "Emoji ara...",
+  "emoji_button.search": "Ara...",
   "emoji_button.search_results": "Arama sonuçları",
   "emoji_button.symbols": "Semboller",
   "emoji_button.travel": "Seyahat ve Yerler",
   "empty_column.account_timeline": "Burada hiç gönderi yok!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "Henüz bir kullanıcıyı engellemediniz.",
   "empty_column.community": "Yerel zaman çizelgesi boş. Daha fazla eğlence için herkese açık bir gönderi paylaşın!",
   "empty_column.direct": "Henüz doğrudan mesajınız yok. Bir tane gönderdiğinizde veya aldığınızda burada görünecektir.",
   "empty_column.domain_blocks": "Henüz hiçbir gizli alan adı yok.",
-  "empty_column.favourited_statuses": "You don't have any favourite toots yet. When you favourite one, it will show up here.",
-  "empty_column.favourites": "No one has favourited this toot yet. When someone does, they will show up here.",
-  "empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.",
+  "empty_column.favourited_statuses": "Hiç favori gönderiminiz yok. Bir tane olursa burada görünecek.",
+  "empty_column.favourites": "Kimse bu gönderiyi favorilerine eklememiş. Biri eklerse burada görünecek.",
+  "empty_column.follow_requests": "Hiç takip isteğiniz yok. Bir tane aldığınızda burada görünecek.",
   "empty_column.hashtag": "Henüz bu hashtag’e sahip hiçbir gönderi yok.",
   "empty_column.home": "Henüz kimseyi takip etmiyorsunuz. {public} ziyaret edebilir veya arama kısmını kullanarak diğer kullanıcılarla iletişime geçebilirsiniz.",
   "empty_column.home.public_timeline": "herkese açık zaman tüneli",
-  "empty_column.list": "There is nothing in this list yet.",
+  "empty_column.list": "Bu listede henüz hiçbir şey yok.",
   "empty_column.lists": "Henüz hiç listeniz yok. Bir tane oluşturduğunuzda burada görünecek.",
   "empty_column.mutes": "Henüz hiçbir kullanıcıyı sessize almadınız.",
   "empty_column.notifications": "Henüz hiçbir bildiriminiz yok. Diğer insanlarla sobhet edebilmek için etkileşime geçebilirsiniz.",
@@ -136,7 +137,7 @@
   "follow_request.reject": "Reddet",
   "getting_started.developers": "Geliştiriciler",
   "getting_started.directory": "Profil dizini",
-  "getting_started.documentation": "Documentation",
+  "getting_started.documentation": "Belgeler",
   "getting_started.heading": "Başlangıç",
   "getting_started.invite": "İnsanları davet edin",
   "getting_started.open_source_notice": "Mastodon açık kaynaklı bir yazılımdır. Github {github}. {apps} üzerinden katkıda bulunabilir, hata raporlayabilirsiniz.",
@@ -145,12 +146,12 @@
   "hashtag.column_header.tag_mode.all": "ve {additional}",
   "hashtag.column_header.tag_mode.any": "ya da {additional}",
   "hashtag.column_header.tag_mode.none": "{additional} olmadan",
-  "hashtag.column_settings.select.no_options_message": "No suggestions found",
-  "hashtag.column_settings.select.placeholder": "Enter hashtags…",
+  "hashtag.column_settings.select.no_options_message": "Hiç öneri bulunamadı",
+  "hashtag.column_settings.select.placeholder": "Hashtagler girin…",
   "hashtag.column_settings.tag_mode.all": "Bunların hepsi",
   "hashtag.column_settings.tag_mode.any": "Bunların hiçbiri",
   "hashtag.column_settings.tag_mode.none": "Bunların hiçbiri",
-  "hashtag.column_settings.tag_toggle": "Include additional tags in this column",
+  "hashtag.column_settings.tag_toggle": "Bu sütundaki ek etiketleri içer",
   "home.column_settings.basic": "Temel",
   "home.column_settings.show_reblogs": "Boost edilenleri göster",
   "home.column_settings.show_replies": "Cevapları göster",
@@ -159,122 +160,122 @@
   "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
   "introduction.federation.action": "İleri",
   "introduction.federation.federated.headline": "Birleşik",
-  "introduction.federation.federated.text": "Diğer dosya sunucularından gelen genel yayınlar, birleşik zaman çizelgesinde görünecektir.",
+  "introduction.federation.federated.text": "Diğer dosya sunucularından gelen genel gönderiler, birleşik zaman çizelgesinde görünecektir.",
   "introduction.federation.home.headline": "Ana sayfa",
   "introduction.federation.home.text": "Posts from people you follow will appear in your home feed. You can follow anyone on any server!",
   "introduction.federation.local.headline": "Yerel",
-  "introduction.federation.local.text": "Public posts from people on the same server as you will appear in the local timeline.",
+  "introduction.federation.local.text": "Aynı sunucudaki kişilerin gönderileri yerel zaman tünelinde gözükecektir.",
   "introduction.interactions.action": "Öğreticiyi bitirin!",
   "introduction.interactions.favourite.headline": "Favori",
-  "introduction.interactions.favourite.text": "You can save a toot for later, and let the author know that you liked it, by favouriting it.",
+  "introduction.interactions.favourite.text": "Bir gönderiyi favorilerinize alarak sonrası için saklayabilirsiniz ve yazara gönderiyi beğendiğinizi söyleyebilirsiniz.",
   "introduction.interactions.reblog.headline": "Boost",
-  "introduction.interactions.reblog.text": "You can share other people's toots with your followers by boosting them.",
+  "introduction.interactions.reblog.text": "Başkalarının gönderilerini boostlayarak kendi takipçilerinizle paylaşabillirsiniz.",
   "introduction.interactions.reply.headline": "Yanıt",
-  "introduction.interactions.reply.text": "You can reply to other people's and your own toots, which will chain them together in a conversation.",
+  "introduction.interactions.reply.text": "Başkalarının gönderilerini ve kendi gönderilerinizi yanıtlayabilirsiniz. Bir konuşmada zincirli bir şekilde olacaklardır.",
   "introduction.welcome.action": "Hadi gidelim!",
   "introduction.welcome.headline": "İlk adımlar",
-  "introduction.welcome.text": "Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.",
-  "keyboard_shortcuts.back": "to navigate back",
-  "keyboard_shortcuts.blocked": "to open blocked users list",
-  "keyboard_shortcuts.boost": "to boost",
-  "keyboard_shortcuts.column": "to focus a status in one of the columns",
-  "keyboard_shortcuts.compose": "to focus the compose textarea",
+  "introduction.welcome.text": "Krallığa hoş geldiniz! Az sonra, geniş bir sunucu yelpazesinde mesaj gönderip arkadaşlarınızla konuşabileceksiniz. Ama bu sunucu, {domain}, özel (profilinizi barındırır, bu yüzden adresini hatırlayın).",
+  "keyboard_shortcuts.back": "geriye gitmek için",
+  "keyboard_shortcuts.blocked": "engelli kullanıcılar listesini açmak için",
+  "keyboard_shortcuts.boost": "boostlamak için",
+  "keyboard_shortcuts.column": "sütunlardan birindeki duruma odaklanmak için",
+  "keyboard_shortcuts.compose": "yazma alanına odaklanmak için",
   "keyboard_shortcuts.description": "Açıklama",
-  "keyboard_shortcuts.direct": "to open direct messages column",
-  "keyboard_shortcuts.down": "to move down in the list",
-  "keyboard_shortcuts.enter": "to open status",
-  "keyboard_shortcuts.favourite": "to favourite",
-  "keyboard_shortcuts.favourites": "to open favourites list",
-  "keyboard_shortcuts.federated": "to open federated timeline",
+  "keyboard_shortcuts.direct": "direkt mesajlar sütununu açmak için",
+  "keyboard_shortcuts.down": "listede aşağıya inmek için",
+  "keyboard_shortcuts.enter": "durumu açmak için",
+  "keyboard_shortcuts.favourite": "favorilere eklemek için",
+  "keyboard_shortcuts.favourites": "favoriler listesini açmak için",
+  "keyboard_shortcuts.federated": "federe edilmiş zaman tünelini açmak için",
   "keyboard_shortcuts.heading": "Klavye kısayolları",
-  "keyboard_shortcuts.home": "Ana sayfa zaman çizelgesini açmak için",
-  "keyboard_shortcuts.hotkey": "Hotkey",
-  "keyboard_shortcuts.legend": "to display this legend",
-  "keyboard_shortcuts.local": "to open local timeline",
-  "keyboard_shortcuts.mention": "to mention author",
-  "keyboard_shortcuts.muted": "to open muted users list",
-  "keyboard_shortcuts.my_profile": "to open your profile",
-  "keyboard_shortcuts.notifications": "to open notifications column",
-  "keyboard_shortcuts.pinned": "to open pinned toots list",
-  "keyboard_shortcuts.profile": "to open author's profile",
-  "keyboard_shortcuts.reply": "to reply",
-  "keyboard_shortcuts.requests": "to open follow requests list",
-  "keyboard_shortcuts.search": "to focus search",
-  "keyboard_shortcuts.start": "to open \"get started\" column",
-  "keyboard_shortcuts.toggle_hidden": "to show/hide text behind CW",
-  "keyboard_shortcuts.toot": "to start a brand new toot",
-  "keyboard_shortcuts.unfocus": "to un-focus compose textarea/search",
-  "keyboard_shortcuts.up": "to move up in the list",
+  "keyboard_shortcuts.home": "ana sayfa zaman çizelgesini açmak için",
+  "keyboard_shortcuts.hotkey": "Kısatuş",
+  "keyboard_shortcuts.legend": "bu efsaneyi görüntülemek için",
+  "keyboard_shortcuts.local": "yerel zaman tünelini açmak için",
+  "keyboard_shortcuts.mention": "yazardan bahsetmek için",
+  "keyboard_shortcuts.muted": "susturulmuş kullanıcı listesini açmak için",
+  "keyboard_shortcuts.my_profile": "profilinizi açmak için",
+  "keyboard_shortcuts.notifications": "bildirimler sütununu açmak için",
+  "keyboard_shortcuts.pinned": "sabitlenmiş gönderiler listesini açmak için",
+  "keyboard_shortcuts.profile": "yazarın profilini açmak için",
+  "keyboard_shortcuts.reply": "cevaplamak için",
+  "keyboard_shortcuts.requests": "takip istekleri listesini açmak için",
+  "keyboard_shortcuts.search": "aramaya odaklanmak için",
+  "keyboard_shortcuts.start": "\"başlayın\" sütununu açmak için",
+  "keyboard_shortcuts.toggle_hidden": "CW'den önceki yazıyı göstermek/gizlemek için",
+  "keyboard_shortcuts.toot": "yeni bir gönderiye başlamak için",
+  "keyboard_shortcuts.unfocus": "aramada bir gönderiye odaklanmamak için",
+  "keyboard_shortcuts.up": "listede yukarıya çıkmak için",
   "lightbox.close": "Kapat",
-  "lightbox.next": "Next",
-  "lightbox.previous": "Previous",
-  "lists.account.add": "Add to list",
-  "lists.account.remove": "Remove from list",
-  "lists.delete": "Delete list",
-  "lists.edit": "Edit list",
-  "lists.edit.submit": "Change title",
-  "lists.new.create": "Add list",
-  "lists.new.title_placeholder": "New list title",
-  "lists.search": "Search among people you follow",
-  "lists.subheading": "Your lists",
+  "lightbox.next": "Sonraki",
+  "lightbox.previous": "Önceli",
+  "lists.account.add": "Listeye ekle",
+  "lists.account.remove": "Listeden kaldır",
+  "lists.delete": "Listeyi sil",
+  "lists.edit": "listeyi düzenle",
+  "lists.edit.submit": "Başlığı değiştir",
+  "lists.new.create": "Liste ekle",
+  "lists.new.title_placeholder": "Yeni liste başlığı",
+  "lists.search": "Takip ettiğiniz kişiler arasından arayın",
+  "lists.subheading": "Listeleriniz",
   "loading_indicator.label": "Yükleniyor...",
   "media_gallery.toggle_visible": "Görünürlüğü değiştir",
   "missing_indicator.label": "Bulunamadı",
-  "missing_indicator.sublabel": "This resource could not be found",
-  "mute_modal.hide_notifications": "Hide notifications from this user?",
-  "navigation_bar.apps": "Mobile apps",
+  "missing_indicator.sublabel": "Bu kaynak bulunamadı",
+  "mute_modal.hide_notifications": "Bu kullanıcıdan bildirimler gizlensin mı?",
+  "navigation_bar.apps": "Mobil uygulamalar",
   "navigation_bar.blocks": "Engellenen kullanıcılar",
   "navigation_bar.community_timeline": "Yerel zaman tüneli",
-  "navigation_bar.compose": "Compose new toot",
-  "navigation_bar.direct": "Direct messages",
-  "navigation_bar.discover": "Discover",
-  "navigation_bar.domain_blocks": "Hidden domains",
+  "navigation_bar.compose": "Yeni bir gönderi yazın",
+  "navigation_bar.direct": "Direkt Mesajlar",
+  "navigation_bar.discover": "Keşfet",
+  "navigation_bar.domain_blocks": "Gizli alan adları",
   "navigation_bar.edit_profile": "Profili düzenle",
   "navigation_bar.favourites": "Favoriler",
-  "navigation_bar.filters": "Muted words",
+  "navigation_bar.filters": "Susturulmuş kelimeler",
   "navigation_bar.follow_requests": "Takip istekleri",
   "navigation_bar.info": "Genişletilmiş bilgi",
-  "navigation_bar.keyboard_shortcuts": "Keyboard shortcuts",
-  "navigation_bar.lists": "Lists",
+  "navigation_bar.keyboard_shortcuts": "Klavye kısayolları",
+  "navigation_bar.lists": "Listeler",
   "navigation_bar.logout": "Çıkış",
   "navigation_bar.mutes": "Sessize alınmış kullanıcılar",
-  "navigation_bar.personal": "Personal",
-  "navigation_bar.pins": "Pinned toots",
+  "navigation_bar.personal": "Kişisel",
+  "navigation_bar.pins": "Sabitlenmiş gönderiler",
   "navigation_bar.preferences": "Tercihler",
   "navigation_bar.public_timeline": "Federe zaman tüneli",
-  "navigation_bar.security": "Security",
+  "navigation_bar.security": "Güvenlik",
   "notification.favourite": "{name} senin durumunu favorilere ekledi",
   "notification.follow": "{name} seni takip ediyor",
   "notification.mention": "{name} mentioned you",
-  "notification.poll": "A poll you have voted in has ended",
+  "notification.poll": "Oy verdiğiniz bir anket bitti",
   "notification.reblog": "{name} senin durumunu boost etti",
   "notifications.clear": "Bildirimleri temizle",
   "notifications.clear_confirmation": "Tüm bildirimlerinizi kalıcı olarak temizlemek ister misiniz?",
   "notifications.column_settings.alert": "Masaüstü bildirimleri",
   "notifications.column_settings.favourite": "Favoriler:",
-  "notifications.column_settings.filter_bar.advanced": "Display all categories",
-  "notifications.column_settings.filter_bar.category": "Quick filter bar",
-  "notifications.column_settings.filter_bar.show": "Show",
+  "notifications.column_settings.filter_bar.advanced": "Tüm kategorileri göster",
+  "notifications.column_settings.filter_bar.category": "Hızlı filtre çubuğu",
+  "notifications.column_settings.filter_bar.show": "Göster",
   "notifications.column_settings.follow": "Yeni takipçiler:",
   "notifications.column_settings.mention": "Bahsedilenler:",
-  "notifications.column_settings.poll": "Poll results:",
-  "notifications.column_settings.push": "Push notifications",
-  "notifications.column_settings.reblog": "Boost’lar:",
+  "notifications.column_settings.poll": "Anket sonuçları:",
+  "notifications.column_settings.push": "Push bildirimleri",
+  "notifications.column_settings.reblog": "Boostlar:",
   "notifications.column_settings.show": "Bildirimlerde göster",
   "notifications.column_settings.sound": "Ses çal",
-  "notifications.filter.all": "All",
-  "notifications.filter.boosts": "Boosts",
-  "notifications.filter.favourites": "Favourites",
-  "notifications.filter.follows": "Follows",
-  "notifications.filter.mentions": "Mentions",
-  "notifications.filter.polls": "Poll results",
-  "notifications.group": "{count} notifications",
-  "poll.closed": "Closed",
-  "poll.refresh": "Refresh",
+  "notifications.filter.all": "Tümü",
+  "notifications.filter.boosts": "Boostlar",
+  "notifications.filter.favourites": "Favoriler",
+  "notifications.filter.follows": "Takip edilenler",
+  "notifications.filter.mentions": "Bahsetmeler",
+  "notifications.filter.polls": "Anket sonuçları",
+  "notifications.group": "{count} bildirim",
+  "poll.closed": "Kapandı",
+  "poll.refresh": "Yenile",
   "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
-  "poll.vote": "Vote",
-  "poll_button.add_poll": "Add a poll",
-  "poll_button.remove_poll": "Remove poll",
+  "poll.vote": "Oy ver",
+  "poll_button.add_poll": "Bir anket ekleyin",
+  "poll_button.remove_poll": "Anket kaldır",
   "privacy.change": "Gönderi gizliliğini ayarla",
   "privacy.direct.long": "Sadece bahsedilen kişilere gönder",
   "privacy.direct.short": "Direkt",
@@ -284,100 +285,100 @@
   "privacy.public.short": "Herkese açık",
   "privacy.unlisted.long": "Herkese açık zaman tüneline gönderme",
   "privacy.unlisted.short": "Listelenmemiş",
-  "regeneration_indicator.label": "Loading…",
-  "regeneration_indicator.sublabel": "Your home feed is being prepared!",
-  "relative_time.days": "{number}d",
-  "relative_time.hours": "{number}h",
-  "relative_time.just_now": "now",
-  "relative_time.minutes": "{number}m",
-  "relative_time.seconds": "{number}s",
+  "regeneration_indicator.label": "Yükleniyor…",
+  "regeneration_indicator.sublabel": "Ev akışınız hazırlanıyor!",
+  "relative_time.days": "{number}g",
+  "relative_time.hours": "{number}s",
+  "relative_time.just_now": "şimdi",
+  "relative_time.minutes": "{number}dk",
+  "relative_time.seconds": "{number}sn",
   "reply_indicator.cancel": "İptal",
-  "report.forward": "Forward to {target}",
-  "report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?",
-  "report.hint": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:",
+  "report.forward": "Şu kişiye ilet : {target}",
+  "report.forward_hint": "Bu hesap başka bir sunucudan. Anonimleştirilmiş bir rapor oraya da gönderilsin mi?",
+  "report.hint": "Bu rapor sunucu moderatörlerine gönderilecek. Bu hesabı neden bildirdiğiniz hakkında bilgi verebirsiniz:",
   "report.placeholder": "Ek yorumlar",
   "report.submit": "Gönder",
   "report.target": "Raporlama",
   "search.placeholder": "Ara",
-  "search_popout.search_format": "Advanced search format",
+  "search_popout.search_format": "Gelişmiş arama formatı",
   "search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.",
   "search_popout.tips.hashtag": "hashtag",
-  "search_popout.tips.status": "status",
+  "search_popout.tips.status": "durum",
   "search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags",
-  "search_popout.tips.user": "user",
-  "search_results.accounts": "People",
-  "search_results.hashtags": "Hashtags",
-  "search_results.statuses": "Toots",
+  "search_popout.tips.user": "kullanıcı",
+  "search_results.accounts": "İnsanlar",
+  "search_results.hashtags": "Hashtagler",
+  "search_results.statuses": "Gönderiler",
   "search_results.total": "{count, number} {count, plural, one {sonuç} other {sonuçlar}}",
   "status.admin_account": "@{name} için denetim arayüzünü açın",
   "status.admin_status": "Denetim arayüzünde bu durumu açın",
-  "status.block": "Block @{name}",
-  "status.cancel_reblog_private": "Unboost",
+  "status.block": "Engelle : @{name}",
+  "status.cancel_reblog_private": "Boost'u geri al",
   "status.cannot_reblog": "Bu gönderi boost edilemez",
   "status.copy": "Bağlantı durumunu kopyala",
   "status.delete": "Sil",
-  "status.detailed_status": "Detailed conversation view",
-  "status.direct": "Direct message @{name}",
-  "status.embed": "Embed",
+  "status.detailed_status": "Detaylı yazışma dökümü",
+  "status.direct": "@{name}'e gönder",
+  "status.embed": "Gömülü",
   "status.favourite": "Favorilere ekle",
-  "status.filtered": "Filtered",
+  "status.filtered": "Filtrelenmiş",
   "status.load_more": "Daha fazla",
   "status.media_hidden": "Gizli görsel",
-  "status.mention": "Bahset @{name}",
-  "status.more": "More",
-  "status.mute": "Mute @{name}",
-  "status.mute_conversation": "Mute conversation",
+  "status.mention": "Bahset : @{name}",
+  "status.more": "Daha fazla",
+  "status.mute": "Sustur : @{name}",
+  "status.mute_conversation": "Yazışmayı sustur",
   "status.open": "Bu gönderiyi genişlet",
-  "status.pin": "Pin on profile",
-  "status.pinned": "Pinned toot",
-  "status.read_more": "Read more",
-  "status.reblog": "Boost'la",
+  "status.pin": "Profile sabitle",
+  "status.pinned": "Sabitlenmiş gönderi",
+  "status.read_more": "Daha dazla oku",
+  "status.reblog": "Boostla",
   "status.reblog_private": "Boost to original audience",
   "status.reblogged_by": "{name} boost etti",
-  "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.",
-  "status.redraft": "Delete & re-draft",
+  "status.reblogs.empty": "Kimse bu gönderiyi boostlamadı. Biri yaptığında burada gözükecek.",
+  "status.redraft": "Sil & tekrar taslakla",
   "status.reply": "Cevapla",
   "status.replyAll": "Konuşmayı cevapla",
   "status.report": "@{name}'i raporla",
   "status.sensitive_toggle": "Görmek için tıklayınız",
   "status.sensitive_warning": "Hassas içerik",
-  "status.share": "Share",
-  "status.show_less": "Daha azı",
-  "status.show_less_all": "Show less for all",
-  "status.show_more": "Daha fazlası",
-  "status.show_more_all": "Show more for all",
-  "status.show_thread": "Show thread",
+  "status.share": "Paylaş",
+  "status.show_less": "Daha az göster",
+  "status.show_less_all": "Hepsi için daha az göster",
+  "status.show_more": "Daha fazla göster",
+  "status.show_more_all": "Hepsi için daha fazla göster",
+  "status.show_thread": "Başlığı göster",
   "status.unmute_conversation": "Unmute conversation",
-  "status.unpin": "Unpin from profile",
-  "suggestions.dismiss": "Dismiss suggestion",
-  "suggestions.header": "You might be interested in…",
+  "status.unpin": "Profilden sabitlemeyi kaldır",
+  "suggestions.dismiss": "Öneriyi görmezden gel",
+  "suggestions.header": "Şuna ilgi duyuyor olabilirsiniz…",
   "tabs_bar.federated_timeline": "Federe",
   "tabs_bar.home": "Ana sayfa",
   "tabs_bar.local_timeline": "Yerel",
   "tabs_bar.notifications": "Bildirimler",
-  "tabs_bar.search": "Search",
+  "tabs_bar.search": "Ara",
   "time_remaining.days": "{number, plural, one {# day} other {# days}} left",
   "time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left",
   "time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left",
   "time_remaining.moments": "Moments remaining",
   "time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left",
   "trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking",
-  "ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
-  "upload_area.title": "Upload için sürükle bırak yapınız",
+  "ui.beforeunload": "Mastodon'dan ayrılırsanız taslağınız kaybolacak.",
+  "upload_area.title": "Karşıya yükleme için sürükle bırak yapınız",
   "upload_button.label": "Görsel ekle",
   "upload_error.limit": "Dosya yükleme sınırı aşıldı.",
-  "upload_error.poll": "File upload not allowed with polls.",
+  "upload_error.poll": "Anketlerde dosya yüklemesine izin verilmez.",
   "upload_form.description": "Describe for the visually impaired",
-  "upload_form.focus": "Crop",
+  "upload_form.focus": "Kırp",
   "upload_form.undo": "Geri al",
   "upload_progress.label": "Yükleniyor...",
-  "video.close": "Close video",
-  "video.exit_fullscreen": "Exit full screen",
-  "video.expand": "Expand video",
-  "video.fullscreen": "Full screen",
-  "video.hide": "Hide video",
-  "video.mute": "Mute sound",
-  "video.pause": "Pause",
-  "video.play": "Play",
-  "video.unmute": "Unmute sound"
+  "video.close": "Videoyu kapat",
+  "video.exit_fullscreen": "Tam ekrandan çık",
+  "video.expand": "Videoyu genişlet",
+  "video.fullscreen": "Tam ekran",
+  "video.hide": "Videoyu gizle",
+  "video.mute": "Sesi kıs",
+  "video.pause": "Duraklat",
+  "video.play": "Oynat",
+  "video.unmute": "Sesi aç"
 }
diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json
index fc1c4f5d5..51a48a2b2 100644
--- a/app/javascript/mastodon/locales/uk.json
+++ b/app/javascript/mastodon/locales/uk.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "Символи",
   "emoji_button.travel": "Подорожі",
   "empty_column.account_timeline": "No toots here!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "You haven't blocked any users yet.",
   "empty_column.community": "Локальна стрічка пуста. Напишіть щось, щоб розігріти народ!",
   "empty_column.direct": "У вас ще немає прямих повідомлень. Коли ви відправите чи отримаєте якесь, воно з'явиться тут.",
diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json
index 702be0ded..f9c6b4d41 100644
--- a/app/javascript/mastodon/locales/zh-CN.json
+++ b/app/javascript/mastodon/locales/zh-CN.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "符号",
   "emoji_button.travel": "旅行和地点",
   "empty_column.account_timeline": "No toots here!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "You haven't blocked any users yet.",
   "empty_column.community": "本站时间轴暂时没有内容,快嘟几个来抢头香啊!",
   "empty_column.direct": "你还没有使用过私信。当你发出或者收到私信时,它会在这里显示。",
diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json
index 5ea738bc9..ed448f65a 100644
--- a/app/javascript/mastodon/locales/zh-HK.json
+++ b/app/javascript/mastodon/locales/zh-HK.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "符號",
   "emoji_button.travel": "旅遊景物",
   "empty_column.account_timeline": "No toots here!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "You haven't blocked any users yet.",
   "empty_column.community": "本站時間軸暫時未有內容,快寫一點東西來搶頭香啊!",
   "empty_column.direct": "你沒有個人訊息。當你發出或接收個人訊息,就會在這裡出現。",
diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json
index 6d33ef070..b43a0b72c 100644
--- a/app/javascript/mastodon/locales/zh-TW.json
+++ b/app/javascript/mastodon/locales/zh-TW.json
@@ -117,6 +117,7 @@
   "emoji_button.symbols": "符號",
   "emoji_button.travel": "旅遊與地點",
   "empty_column.account_timeline": "這裡還沒有嘟文!",
+  "empty_column.account_unavailable": "Profile unavailable",
   "empty_column.blocks": "你還沒有封鎖任何使用者。",
   "empty_column.community": "本地時間軸是空的。快公開嘟些文搶頭香啊!",
   "empty_column.direct": "您還沒有任何私訊。當您私訊別人或收到私訊時,它將於此顯示。",
diff --git a/app/javascript/styles/mastodon/accounts.scss b/app/javascript/styles/mastodon/accounts.scss
index f4f458cf4..a790251f4 100644
--- a/app/javascript/styles/mastodon/accounts.scss
+++ b/app/javascript/styles/mastodon/accounts.scss
@@ -292,3 +292,29 @@
 .directory__tag .trends__item__current {
   width: auto;
 }
+
+.pending-account {
+  &__header {
+    color: $darker-text-color;
+
+    a {
+      color: $ui-secondary-color;
+      text-decoration: none;
+
+      &:hover,
+      &:active,
+      &:focus {
+        text-decoration: underline;
+      }
+    }
+
+    strong {
+      color: $primary-text-color;
+      font-weight: 700;
+    }
+  }
+
+  &__body {
+    margin-top: 10px;
+  }
+}
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index 2ad93c59d..9fcaeb8dd 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -46,7 +46,8 @@
     }
   }
 
-  &:disabled {
+  &:disabled,
+  &.disabled {
     background-color: $ui-primary-color;
     cursor: default;
   }
diff --git a/app/javascript/styles/mastodon/stream_entries.scss b/app/javascript/styles/mastodon/stream_entries.scss
index d8bd30377..63eeffe25 100644
--- a/app/javascript/styles/mastodon/stream_entries.scss
+++ b/app/javascript/styles/mastodon/stream_entries.scss
@@ -109,6 +109,23 @@
     }
   }
 
+  &:disabled,
+  &.disabled {
+    svg path:last-child {
+      fill: $ui-primary-color;
+    }
+
+    &:active,
+    &:focus,
+    &:hover {
+      background: $ui-primary-color;
+
+      svg path:last-child {
+        fill: $ui-primary-color;
+      }
+    }
+  }
+
   &.button--destructive {
     &:active,
     &:focus,
diff --git a/app/javascript/styles/mastodon/widgets.scss b/app/javascript/styles/mastodon/widgets.scss
index 307e509d5..e736d7a7e 100644
--- a/app/javascript/styles/mastodon/widgets.scss
+++ b/app/javascript/styles/mastodon/widgets.scss
@@ -377,6 +377,10 @@
     border: 0;
   }
 
+  strong {
+    font-weight: 700;
+  }
+
   thead th {
     text-align: center;
     text-transform: uppercase;
@@ -414,6 +418,11 @@
     }
   }
 
+  &__comment {
+    width: 50%;
+    vertical-align: initial !important;
+  }
+
   @media screen and (max-width: $no-gap-breakpoint) {
     tbody td.optional {
       display: none;
diff --git a/app/lib/proof_provider/keybase.rb b/app/lib/proof_provider/keybase.rb
index 628972e9d..9680b90ee 100644
--- a/app/lib/proof_provider/keybase.rb
+++ b/app/lib/proof_provider/keybase.rb
@@ -2,7 +2,7 @@
 
 class ProofProvider::Keybase
   BASE_URL = ENV.fetch('KEYBASE_BASE_URL', 'https://keybase.io')
-  DOMAIN = ENV.fetch('KEYBASE_DOMAIN', Rails.configuration.x.local_domain)
+  DOMAIN   = ENV.fetch('KEYBASE_DOMAIN', Rails.configuration.x.local_domain)
 
   class Error < StandardError; end
 
@@ -50,12 +50,20 @@ class ProofProvider::Keybase
   end
 
   def badge
-    @badge ||= ProofProvider::Keybase::Badge.new(@proof.account.username, @proof.provider_username, @proof.token)
+    @badge ||= ProofProvider::Keybase::Badge.new(@proof.account.username, @proof.provider_username, @proof.token, domain)
+  end
+
+  def verifier
+    @verifier ||= ProofProvider::Keybase::Verifier.new(@proof.account.username, @proof.provider_username, @proof.token, domain)
   end
 
   private
 
-  def verifier
-    @verifier ||= ProofProvider::Keybase::Verifier.new(@proof.account.username, @proof.provider_username, @proof.token)
+  def domain
+    if @proof.account.local?
+      DOMAIN
+    else
+      @proof.account.domain
+    end
   end
 end
diff --git a/app/lib/proof_provider/keybase/badge.rb b/app/lib/proof_provider/keybase/badge.rb
index 3aa067ecf..f587b1cc7 100644
--- a/app/lib/proof_provider/keybase/badge.rb
+++ b/app/lib/proof_provider/keybase/badge.rb
@@ -3,10 +3,11 @@
 class ProofProvider::Keybase::Badge
   include RoutingHelper
 
-  def initialize(local_username, provider_username, token)
+  def initialize(local_username, provider_username, token, domain)
     @local_username    = local_username
     @provider_username = provider_username
     @token             = token
+    @domain            = domain
   end
 
   def proof_url
@@ -18,7 +19,7 @@ class ProofProvider::Keybase::Badge
   end
 
   def icon_url
-    "#{ProofProvider::Keybase::BASE_URL}/#{@provider_username}/proof_badge/#{@token}?username=#{@local_username}&domain=#{domain}"
+    "#{ProofProvider::Keybase::BASE_URL}/#{@provider_username}/proof_badge/#{@token}?username=#{@local_username}&domain=#{@domain}"
   end
 
   def avatar_url
@@ -41,8 +42,4 @@ class ProofProvider::Keybase::Badge
   def default_avatar_url
     asset_pack_path('media/images/proof_providers/keybase.png')
   end
-
-  def domain
-    Rails.configuration.x.local_domain
-  end
 end
diff --git a/app/lib/proof_provider/keybase/config_serializer.rb b/app/lib/proof_provider/keybase/config_serializer.rb
index 5241d201f..2840f1823 100644
--- a/app/lib/proof_provider/keybase/config_serializer.rb
+++ b/app/lib/proof_provider/keybase/config_serializer.rb
@@ -34,7 +34,7 @@ class ProofProvider::Keybase::ConfigSerializer < ActiveModel::Serializer
   end
 
   def username
-    { min: 1, max: 30, re: '[a-z0-9_]+([a-z0-9_\.-]+[a-z0-9_]+)?' }
+    { min: 1, max: 30, re: '[a-z0-9_]+([a-z0-9_.-]+[a-z0-9_]+)?' }
   end
 
   def prefill_url
diff --git a/app/lib/proof_provider/keybase/verifier.rb b/app/lib/proof_provider/keybase/verifier.rb
index ab1422323..af69b1bfc 100644
--- a/app/lib/proof_provider/keybase/verifier.rb
+++ b/app/lib/proof_provider/keybase/verifier.rb
@@ -1,10 +1,11 @@
 # frozen_string_literal: true
 
 class ProofProvider::Keybase::Verifier
-  def initialize(local_username, provider_username, token)
+  def initialize(local_username, provider_username, token, domain)
     @local_username    = local_username
     @provider_username = provider_username
     @token             = token
+    @domain            = domain
   end
 
   def valid?
@@ -49,7 +50,7 @@ class ProofProvider::Keybase::Verifier
 
   def query_params
     {
-      domain: ProofProvider::Keybase::DOMAIN,
+      domain: @domain,
       kb_username: @provider_username,
       username: @local_username,
       sig_hash: @token,
diff --git a/app/lib/proof_provider/keybase/worker.rb b/app/lib/proof_provider/keybase/worker.rb
index 2872f59c1..bcdd18cc5 100644
--- a/app/lib/proof_provider/keybase/worker.rb
+++ b/app/lib/proof_provider/keybase/worker.rb
@@ -19,9 +19,8 @@ class ProofProvider::Keybase::Worker
   end
 
   def perform(proof_id)
-    proof    = proof_id.is_a?(AccountIdentityProof) ? proof_id : AccountIdentityProof.find(proof_id)
-    verifier = ProofProvider::Keybase::Verifier.new(proof.account.username, proof.provider_username, proof.token)
-    status   = verifier.status
+    proof  = proof_id.is_a?(AccountIdentityProof) ? proof_id : AccountIdentityProof.find(proof_id)
+    status = proof.provider_instance.verifier.status
 
     # If Keybase thinks the proof is valid, and it exists here in Mastodon,
     # then it should be live. Keybase just has to notice that it's here
diff --git a/app/models/account.rb b/app/models/account.rb
index 983d38e0e..a82251d2e 100644
--- a/app/models/account.rb
+++ b/app/models/account.rb
@@ -102,7 +102,6 @@ class Account < ApplicationRecord
   scope :tagged_with, ->(tag) { joins(:accounts_tags).where(accounts_tags: { tag_id: tag }) }
   scope :by_recent_status, -> { order(Arel.sql('(case when account_stats.last_status_at is null then 1 else 0 end) asc, account_stats.last_status_at desc')) }
   scope :popular, -> { order('account_stats.followers_count desc') }
-  scope :without_blocking, ->(account) { account.nil? ? all : where.not(id: Block.where(target_account_id: account.id).pluck(:account_id)) }
 
   delegate :email,
            :unconfirmed_email,
diff --git a/app/models/account_identity_proof.rb b/app/models/account_identity_proof.rb
index 1ac234735..10b66cccf 100644
--- a/app/models/account_identity_proof.rb
+++ b/app/models/account_identity_proof.rb
@@ -18,7 +18,7 @@ class AccountIdentityProof < ApplicationRecord
   belongs_to :account
 
   validates :provider, inclusion: { in: ProofProvider::SUPPORTED_PROVIDERS }
-  validates :provider_username, format: { with: /\A[a-z0-9_]+\z/i }, length: { minimum: 2, maximum: 15 }
+  validates :provider_username, format: { with: /\A[a-z0-9_]+\z/i }, length: { minimum: 2, maximum: 30 }
   validates :provider_username, uniqueness: { scope: [:account_id, :provider] }
   validates :token, format: { with: /\A[a-f0-9]+\z/ }, length: { maximum: 66 }
 
@@ -30,12 +30,12 @@ class AccountIdentityProof < ApplicationRecord
 
   delegate :refresh!, :on_success_path, :badge, to: :provider_instance
 
-  private
-
   def provider_instance
     @provider_instance ||= ProofProvider.find(provider, self)
   end
 
+  private
+
   def queue_worker
     provider_instance.worker_class.perform_async(id)
   end
diff --git a/app/models/concerns/account_finder_concern.rb b/app/models/concerns/account_finder_concern.rb
index 7e3bbde09..0ac49cc12 100644
--- a/app/models/concerns/account_finder_concern.rb
+++ b/app/models/concerns/account_finder_concern.rb
@@ -13,7 +13,7 @@ module AccountFinderConcern
     end
 
     def representative
-      find_local(Setting.site_contact_username.gsub(/\A@/, '')) || Account.local.find_by(suspended: false)
+      find_local(Setting.site_contact_username.strip.gsub(/\A@/, '')) || Account.local.find_by(suspended: false)
     end
 
     def find_local(username)
diff --git a/app/models/export.rb b/app/models/export.rb
index 9bf866d35..cab01f11a 100644
--- a/app/models/export.rb
+++ b/app/models/export.rb
@@ -14,11 +14,19 @@ class Export
   end
 
   def to_muted_accounts_csv
-    to_csv account.muting.select(:username, :domain)
+    CSV.generate(headers: ['Account address', 'Hide notifications'], write_headers: true) do |csv|
+      account.mute_relationships.includes(:target_account).reorder(id: :desc).each do |mute|
+        csv << [acct(mute.target_account), mute.hide_notifications]
+      end
+    end
   end
 
   def to_following_accounts_csv
-    to_csv account.following.select(:username, :domain)
+    CSV.generate(headers: ['Account address', 'Show boosts'], write_headers: true) do |csv|
+      account.active_relationships.includes(:target_account).reorder(id: :desc).each do |follow|
+        csv << [acct(follow.target_account), follow.show_reblogs]
+      end
+    end
   end
 
   def to_lists_csv
diff --git a/app/models/form/account_batch.rb b/app/models/form/account_batch.rb
index 60eaaf0e2..5bc44e809 100644
--- a/app/models/form/account_batch.rb
+++ b/app/models/form/account_batch.rb
@@ -2,6 +2,7 @@
 
 class Form::AccountBatch
   include ActiveModel::Model
+  include Authorization
 
   attr_accessor :account_ids, :action, :current_account
 
@@ -13,6 +14,10 @@ class Form::AccountBatch
       remove_from_followers!
     when 'block_domains'
       block_domains!
+    when 'approve'
+      approve!
+    when 'reject'
+      reject!
     end
   end
 
@@ -57,4 +62,18 @@ class Form::AccountBatch
 
     ActivityPub::DeliveryWorker.perform_async(json, current_account.id, follow.account.inbox_url)
   end
+
+  def approve!
+    users = accounts.includes(:user).map(&:user)
+
+    users.each { |user| authorize(user, :approve?) }
+         .each(&:approve!)
+  end
+
+  def reject!
+    records = accounts.includes(:user)
+
+    records.each { |account| authorize(account.user, :reject?) }
+           .each { |account| SuspendAccountService.new.call(account, including_user: true, destroy: true, skip_distribution: true) }
+  end
 end
diff --git a/app/models/form/admin_settings.rb b/app/models/form/admin_settings.rb
index 5b71dfad5..83d303c33 100644
--- a/app/models/form/admin_settings.rb
+++ b/app/models/form/admin_settings.rb
@@ -57,7 +57,8 @@ class Form::AdminSettings
 
   attr_accessor(*KEYS)
 
-  validates :site_short_description, :site_description, :site_extended_description, :site_terms, :closed_registrations_message, html: true
+  validates :site_short_description, :site_description, html: { wrap_with: :p }
+  validates :site_extended_description, :site_terms, :closed_registrations_message, html: true
   validates :registrations_mode, inclusion: { in: %w(open approved none) }
   validates :min_invite_role, inclusion: { in: %w(disabled user moderator admin) }
   validates :site_contact_email, :site_contact_username, presence: true
diff --git a/app/models/user.rb b/app/models/user.rb
index 66c1543ff..b2fb820af 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -74,6 +74,9 @@ class User < ApplicationRecord
   has_many :applications, class_name: 'Doorkeeper::Application', as: :owner
   has_many :backups, inverse_of: :user
 
+  has_one :invite_request, class_name: 'UserInviteRequest', inverse_of: :user, dependent: :destroy
+  accepts_nested_attributes_for :invite_request, reject_if: ->(attributes) { attributes['text'].blank? }
+
   validates :locale, inclusion: I18n.available_locales.map(&:to_s), if: :locale?
   validates_with BlacklistedEmailValidator, if: :email_changed?
   validates_with EmailMxValidator, if: :validate_email_dns?
@@ -188,6 +191,10 @@ class User < ApplicationRecord
     settings.notification_emails['report']
   end
 
+  def allows_pending_account_emails?
+    settings.notification_emails['pending_account']
+  end
+
   def hides_network?
     @hides_network ||= settings.hide_network
   end
@@ -292,7 +299,7 @@ class User < ApplicationRecord
 
   def notify_staff_about_pending_account!
     User.staff.includes(:account).each do |u|
-      next unless u.allows_report_emails?
+      next unless u.allows_pending_account_emails?
       AdminMailer.new_pending_account(u.account, self).deliver_later
     end
   end
diff --git a/app/models/user_invite_request.rb b/app/models/user_invite_request.rb
new file mode 100644
index 000000000..2b76c88b9
--- /dev/null
+++ b/app/models/user_invite_request.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+# == Schema Information
+#
+# Table name: user_invite_requests
+#
+#  id         :bigint(8)        not null, primary key
+#  user_id    :bigint(8)
+#  text       :text
+#  created_at :datetime         not null
+#  updated_at :datetime         not null
+#
+
+class UserInviteRequest < ApplicationRecord
+  belongs_to :user, inverse_of: :invite_request
+  validates :text, presence: true, length: { maximum: 420 }
+end
diff --git a/app/presenters/account_relationships_presenter.rb b/app/presenters/account_relationships_presenter.rb
index e4aaa65f6..b05673a3d 100644
--- a/app/presenters/account_relationships_presenter.rb
+++ b/app/presenters/account_relationships_presenter.rb
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 class AccountRelationshipsPresenter
-  attr_reader :following, :followed_by, :blocking,
+  attr_reader :following, :followed_by, :blocking, :blocked_by,
               :muting, :requested, :domain_blocking,
               :endorsed
 
@@ -12,6 +12,7 @@ class AccountRelationshipsPresenter
     @following       = cached[:following].merge(Account.following_map(@uncached_account_ids, @current_account_id))
     @followed_by     = cached[:followed_by].merge(Account.followed_by_map(@uncached_account_ids, @current_account_id))
     @blocking        = cached[:blocking].merge(Account.blocking_map(@uncached_account_ids, @current_account_id))
+    @blocked_by      = cached[:blocked_by].merge(Account.blocked_by_map(@uncached_account_ids, @current_account_id))
     @muting          = cached[:muting].merge(Account.muting_map(@uncached_account_ids, @current_account_id))
     @requested       = cached[:requested].merge(Account.requested_map(@uncached_account_ids, @current_account_id))
     @domain_blocking = cached[:domain_blocking].merge(Account.domain_blocking_map(@uncached_account_ids, @current_account_id))
@@ -22,6 +23,7 @@ class AccountRelationshipsPresenter
     @following.merge!(options[:following_map] || {})
     @followed_by.merge!(options[:followed_by_map] || {})
     @blocking.merge!(options[:blocking_map] || {})
+    @blocked_by.merge!(options[:blocked_by_map] || {})
     @muting.merge!(options[:muting_map] || {})
     @requested.merge!(options[:requested_map] || {})
     @domain_blocking.merge!(options[:domain_blocking_map] || {})
@@ -37,6 +39,7 @@ class AccountRelationshipsPresenter
       following: {},
       followed_by: {},
       blocking: {},
+      blocked_by: {},
       muting: {},
       requested: {},
       domain_blocking: {},
@@ -64,6 +67,7 @@ class AccountRelationshipsPresenter
         following:       { account_id => following[account_id] },
         followed_by:     { account_id => followed_by[account_id] },
         blocking:        { account_id => blocking[account_id] },
+        blocked_by:      { account_id => blocked_by[account_id] },
         muting:          { account_id => muting[account_id] },
         requested:       { account_id => requested[account_id] },
         domain_blocking: { account_id => domain_blocking[account_id] },
diff --git a/app/presenters/instance_presenter.rb b/app/presenters/instance_presenter.rb
index d234516e0..534752932 100644
--- a/app/presenters/instance_presenter.rb
+++ b/app/presenters/instance_presenter.rb
@@ -13,7 +13,7 @@ class InstancePresenter
   )
 
   def contact_account
-    Account.find_local(Setting.site_contact_username.gsub(/\A@/, ''))
+    Account.find_local(Setting.site_contact_username.strip.gsub(/\A@/, ''))
   end
 
   def user_count
diff --git a/app/serializers/rest/relationship_serializer.rb b/app/serializers/rest/relationship_serializer.rb
index c6c722a54..1a3fd915c 100644
--- a/app/serializers/rest/relationship_serializer.rb
+++ b/app/serializers/rest/relationship_serializer.rb
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 class REST::RelationshipSerializer < ActiveModel::Serializer
-  attributes :id, :following, :showing_reblogs, :followed_by, :blocking,
+  attributes :id, :following, :showing_reblogs, :followed_by, :blocking, :blocked_by,
              :muting, :muting_notifications, :requested, :domain_blocking,
              :endorsed
 
@@ -27,6 +27,10 @@ class REST::RelationshipSerializer < ActiveModel::Serializer
     instance_options[:relationships].blocking[object.id] || false
   end
 
+  def blocked_by
+    instance_options[:relationships].blocked_by[object.id] || false
+  end
+
   def muting
     instance_options[:relationships].muting[object.id] ? true : false
   end
diff --git a/app/services/account_search_service.rb b/app/services/account_search_service.rb
index c47b1c094..7bdffbbd2 100644
--- a/app/services/account_search_service.rb
+++ b/app/services/account_search_service.rb
@@ -10,15 +10,7 @@ class AccountSearchService < BaseService
     @options = options
     @account = account
 
-    results = search_service_results
-
-    unless account.nil?
-      account_ids    = results.map(&:id)
-      blocked_by_map = Account.blocked_by_map(account_ids, account.id)
-      results.reject! { |item| blocked_by_map[item.id] }
-    end
-
-    results
+    search_service_results
   end
 
   private
diff --git a/app/services/import_service.rb b/app/services/import_service.rb
index 3f558626e..4ee431ea3 100644
--- a/app/services/import_service.rb
+++ b/app/services/import_service.rb
@@ -8,7 +8,6 @@ class ImportService < BaseService
   def call(import)
     @import  = import
     @account = @import.account
-    @data    = CSV.new(import_data).reject(&:blank?)
 
     case @import.type
     when 'following'
@@ -25,19 +24,23 @@ class ImportService < BaseService
   private
 
   def import_follows!
-    import_relationships!('follow', 'unfollow', @account.following, follow_limit)
+    parse_import_data!(['Account address'])
+    import_relationships!('follow', 'unfollow', @account.following, follow_limit, reblogs: 'Show boosts')
   end
 
   def import_blocks!
+    parse_import_data!(['Account address'])
     import_relationships!('block', 'unblock', @account.blocking, ROWS_PROCESSING_LIMIT)
   end
 
   def import_mutes!
-    import_relationships!('mute', 'unmute', @account.muting, ROWS_PROCESSING_LIMIT)
+    parse_import_data!(['Account address'])
+    import_relationships!('mute', 'unmute', @account.muting, ROWS_PROCESSING_LIMIT, notifications: 'Hide notifications')
   end
 
   def import_domain_blocks!
-    items = @data.take(ROWS_PROCESSING_LIMIT).map { |row| row.first.strip }
+    parse_import_data!(['#domain'])
+    items = @data.take(ROWS_PROCESSING_LIMIT).map { |row| row['#domain'].strip }
 
     if @import.overwrite?
       presence_hash = items.each_with_object({}) { |id, mapping| mapping[id] = true }
@@ -60,26 +63,34 @@ class ImportService < BaseService
     end
   end
 
-  def import_relationships!(action, undo_action, overwrite_scope, limit)
-    items = @data.take(limit).map { |row| row.first.strip }
+  def import_relationships!(action, undo_action, overwrite_scope, limit, extra_fields = {})
+    items = @data.take(limit).map { |row| [row['Account address']&.strip, Hash[extra_fields.map { |key, header| [key, row[header]&.strip] }]] }.reject { |(id, _)| id.blank? }
 
     if @import.overwrite?
-      presence_hash = items.each_with_object({}) { |id, mapping| mapping[id] = true }
+      presence_hash = items.each_with_object({}) { |(id, extra), mapping| mapping[id] = [true, extra] }
 
       overwrite_scope.find_each do |target_account|
         if presence_hash[target_account.acct]
           items.delete(target_account.acct)
+          extra = presence_hash[target_account.acct][1]
+          Import::RelationshipWorker.perform_async(@account.id, target_account.acct, action, extra)
         else
           Import::RelationshipWorker.perform_async(@account.id, target_account.acct, undo_action)
         end
       end
     end
 
-    Import::RelationshipWorker.push_bulk(items) do |acct|
-      [@account.id, acct, action]
+    Import::RelationshipWorker.push_bulk(items) do |acct, extra|
+      [@account.id, acct, action, extra]
     end
   end
 
+  def parse_import_data!(default_headers)
+    data = CSV.parse(import_data, headers: true)
+    data = CSV.parse(import_data, headers: default_headers) unless data.headers&.first&.strip&.include?(' ')
+    @data = data.reject(&:blank?)
+  end
+
   def import_data
     Paperclip.io_adapters.for(@import.data).read
   end
diff --git a/app/services/search_service.rb b/app/services/search_service.rb
index a8442654c..e0da61dac 100644
--- a/app/services/search_service.rb
+++ b/app/services/search_service.rb
@@ -12,8 +12,6 @@ class SearchService < BaseService
     default_results.tap do |results|
       if url_query?
         results.merge!(url_resource_results) unless url_resource.nil?
-        results[:accounts].reject! { |item| item.blocking?(@account) }
-        results[:statuses].reject! { |status| StatusFilter.new(status, @account).filtered? }
       elsif @query.present?
         results[:accounts] = perform_accounts_search! if account_searchable?
         results[:statuses] = perform_statuses_search! if full_text_searchable?
diff --git a/app/validators/existing_username_validator.rb b/app/validators/existing_username_validator.rb
index 4388a0c98..b31d09827 100644
--- a/app/validators/existing_username_validator.rb
+++ b/app/validators/existing_username_validator.rb
@@ -5,16 +5,10 @@ class ExistingUsernameValidator < ActiveModel::EachValidator
     return if value.blank?
 
     if options[:multiple]
-      missing_usernames = value.split(',').map { |username| username unless Account.find_local(username) }.compact
+      missing_usernames = value.split(',').map { |username| username.strip.gsub(/\A@/, '') }.map { |username| username unless Account.find_local(username) }.compact
       record.errors.add(attribute, I18n.t('existing_username_validator.not_found_multiple', usernames: missing_usernames.join(', '))) if missing_usernames.any?
     else
-      record.errors.add(attribute, I18n.t('existing_username_validator.not_found')) unless Account.find_local(value)
+      record.errors.add(attribute, I18n.t('existing_username_validator.not_found')) unless Account.find_local(value.strip.gsub(/\A@/, ''))
     end
   end
-
-  private
-
-  def valid_html?(str)
-    Nokogiri::HTML.fragment(str).to_s == str
-  end
 end
diff --git a/app/validators/html_validator.rb b/app/validators/html_validator.rb
index b7caee5a9..1c9cd303c 100644
--- a/app/validators/html_validator.rb
+++ b/app/validators/html_validator.rb
@@ -1,18 +1,20 @@
 # frozen_string_literal: true
 
 class HtmlValidator < ActiveModel::EachValidator
+  ERROR_RE = /Opening and ending tag mismatch|Unexpected end tag/
+
   def validate_each(record, attribute, value)
     return if value.blank?
+
     errors = html_errors(value)
-    unless errors.empty?
-      record.errors.add(attribute, I18n.t('html_validator.invalid_markup', error: errors.first.to_s))
-    end
+
+    record.errors.add(attribute, I18n.t('html_validator.invalid_markup', error: errors.first.to_s)) unless errors.empty?
   end
 
   private
 
   def html_errors(str)
-    fragment = Nokogiri::HTML.fragment(str)
-    fragment.errors
+    fragment = Nokogiri::HTML.fragment(options[:wrap_with] ? "<#{options[:wrap_with]}>#{str}</#{options[:wrap_with]}>" : str)
+    fragment.errors.select { |error| ERROR_RE =~ error.message }
   end
 end
diff --git a/app/validators/poll_validator.rb b/app/validators/poll_validator.rb
index fd497c8d0..9d7321cad 100644
--- a/app/validators/poll_validator.rb
+++ b/app/validators/poll_validator.rb
@@ -14,6 +14,6 @@ class PollValidator < ActiveModel::Validator
     poll.errors.add(:options, I18n.t('polls.errors.over_character_limit', max: MAX_OPTION_CHARS)) if poll.options.any? { |option| option.mb_chars.grapheme_length > MAX_OPTION_CHARS }
     poll.errors.add(:options, I18n.t('polls.errors.duplicate_options')) unless poll.options.uniq.size == poll.options.size
     poll.errors.add(:expires_at, I18n.t('polls.errors.duration_too_long')) if poll.expires_at.nil? || poll.expires_at - current_time > MAX_EXPIRATION
-    poll.errors.add(:expires_at, I18n.t('polls.errors.duration_too_short')) if poll.expires_at.present? && poll.expires_at - current_time < MIN_EXPIRATION
+    poll.errors.add(:expires_at, I18n.t('polls.errors.duration_too_short')) if poll.expires_at.present? && (poll.expires_at - current_time).ceil < MIN_EXPIRATION
   end
 end
diff --git a/app/views/about/_registration.html.haml b/app/views/about/_registration.html.haml
index 09cbe2e28..ff32ec8c4 100644
--- a/app/views/about/_registration.html.haml
+++ b/app/views/about/_registration.html.haml
@@ -10,6 +10,11 @@
       = f.input :password, placeholder: t('simple_form.labels.defaults.password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.password'), :autocomplete => 'off' }, hint: false, disabled: closed_registrations?
       = f.input :password_confirmation, placeholder: t('simple_form.labels.defaults.confirm_password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.confirm_password'), :autocomplete => 'off' }, hint: false, disabled: closed_registrations?
 
+    - if approved_registrations?
+      .fields-group
+        = f.simple_fields_for :invite_request do |invite_request_fields|
+          = invite_request_fields.input :text, as: :text, wrapper: :with_block_label, required: false
+
     .fields-group
       = f.input :agreement, as: :boolean, wrapper: :with_label, label: t('auth.checkbox_agreement_html', rules_path: about_more_path, terms_path: terms_path), disabled: closed_registrations?
 
diff --git a/app/views/accounts/show.html.haml b/app/views/accounts/show.html.haml
index 0da69728f..e4223119c 100644
--- a/app/views/accounts/show.html.haml
+++ b/app/views/accounts/show.html.haml
@@ -33,7 +33,9 @@
         = active_link_to t('accounts.posts_with_replies'), short_account_with_replies_url(@account)
         = active_link_to t('accounts.media'), short_account_media_url(@account)
 
-      - if @statuses.empty?
+      - if user_signed_in? && @account.blocking?(current_account)
+        .nothing-here.nothing-here--under-tabs= t('accounts.unavailable')
+      - elsif @statuses.empty?
         = nothing_here 'nothing-here--under-tabs'
       - else
         .activity-stream
diff --git a/app/views/admin/accounts/index.html.haml b/app/views/admin/accounts/index.html.haml
index 66808add7..7e9adb3ff 100644
--- a/app/views/admin/accounts/index.html.haml
+++ b/app/views/admin/accounts/index.html.haml
@@ -10,7 +10,7 @@
   .filter-subset
     %strong= t('admin.accounts.moderation.title')
     %ul
-      %li= filter_link_to t('admin.accounts.moderation.pending'), pending: '1', silenced: nil, suspended: nil
+      %li= link_to safe_join([t('admin.accounts.moderation.pending'), "(#{number_with_delimiter(User.pending.count)})"], ' '), admin_pending_accounts_path
       %li= filter_link_to t('admin.accounts.moderation.active'), silenced: nil, suspended: nil, pending: nil
       %li= filter_link_to t('admin.accounts.moderation.silenced'), silenced: '1', suspended: nil, pending: nil
       %li= filter_link_to t('admin.accounts.moderation.suspended'), suspended: '1', silenced: nil, pending: nil
diff --git a/app/views/admin/pending_accounts/_account.html.haml b/app/views/admin/pending_accounts/_account.html.haml
new file mode 100644
index 000000000..1ed5dafdd
--- /dev/null
+++ b/app/views/admin/pending_accounts/_account.html.haml
@@ -0,0 +1,14 @@
+.batch-table__row
+  %label.batch-table__row__select.batch-table__row__select--aligned.batch-checkbox
+    = f.check_box :account_ids, { multiple: true, include_hidden: false }, account.id
+  .batch-table__row__content.pending-account
+    .pending-account__header
+      = link_to admin_account_path(account.id) do
+        %strong= account.user_email
+        = "(@#{account.username})"
+      %br/
+      = account.user_current_sign_in_ip
+
+    - if account.user&.invite_request&.text&.present?
+      .pending-account__body
+        %p= account.user&.invite_request&.text
diff --git a/app/views/admin/pending_accounts/index.html.haml b/app/views/admin/pending_accounts/index.html.haml
new file mode 100644
index 000000000..171976e33
--- /dev/null
+++ b/app/views/admin/pending_accounts/index.html.haml
@@ -0,0 +1,30 @@
+- content_for :page_title do
+  = t('admin.pending_accounts.title', count: User.pending.count)
+
+= form_for(@form, url: batch_admin_pending_accounts_path) do |f|
+  = hidden_field_tag :page, params[:page] || 1
+
+  .batch-table
+    .batch-table__toolbar
+      %label.batch-table__toolbar__select.batch-checkbox-all
+        = check_box_tag :batch_checkbox_all, nil, false
+      .batch-table__toolbar__actions
+        = f.button safe_join([fa_icon('check'), t('admin.accounts.approve')]), name: :approve, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
+
+        = f.button safe_join([fa_icon('times'), t('admin.accounts.reject')]), name: :reject, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
+    .batch-table__body
+      - if @accounts.empty?
+        = nothing_here 'nothing-here--under-tabs'
+      - else
+        = render partial: 'account', collection: @accounts, locals: { f: f }
+
+= paginate @accounts
+
+%hr.spacer/
+
+%div{ style: 'overflow: hidden' }
+  %div{ style: 'float: right' }
+    = link_to t('admin.accounts.reject_all'), reject_all_admin_pending_accounts_path, method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button button--destructive'
+
+  %div
+    = link_to t('admin.accounts.approve_all'), approve_all_admin_pending_accounts_path, method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button'
diff --git a/app/views/admin_mailer/new_pending_account.text.erb b/app/views/admin_mailer/new_pending_account.text.erb
index ed31ae2eb..a466ee2de 100644
--- a/app/views/admin_mailer/new_pending_account.text.erb
+++ b/app/views/admin_mailer/new_pending_account.text.erb
@@ -2,7 +2,11 @@
 
 <%= raw t('admin_mailer.new_pending_account.body') %>
 
-<%= raw t('admin.accounts.email') %>: <%= @account.user_email %>
-<%= raw t('admin.accounts.most_recent_ip') %>: <%= @account.user_current_sign_in_ip %>
+<%= @account.user_email %> (@<%= @account.username %>)
+<%= @account.user_current_sign_in_ip %>
+<% if @account.user&.invite_request&.text.present? %>
 
-<%= raw t('application_mailer.view')%> <%= admin_account_url(@account.id) %>
+<%= quote_wrap(@account.user&.invite_request&.text) %>
+<% end %>
+
+<%= raw t('application_mailer.view')%> <%= admin_pending_accounts_url %>
diff --git a/app/views/auth/registrations/new.html.haml b/app/views/auth/registrations/new.html.haml
index 1caf2b401..bd6e3a13f 100644
--- a/app/views/auth/registrations/new.html.haml
+++ b/app/views/auth/registrations/new.html.haml
@@ -21,12 +21,19 @@
 
   .fields-group
     = f.input :password, wrapper: :with_label, label: t('simple_form.labels.defaults.password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.password'), :autocomplete => 'off' }
+
   .fields-group
     = f.input :password_confirmation, wrapper: :with_label, label: t('simple_form.labels.defaults.confirm_password'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.confirm_password'), :autocomplete => 'off' }
 
+  - if approved_registrations? && !@invite.present?
+    .fields-group
+      = f.simple_fields_for :invite_request do |invite_request_fields|
+        = invite_request_fields.input :text, as: :text, wrapper: :with_block_label, required: false
+
   = f.input :invite_code, as: :hidden
 
-  %p.hint= t('auth.agreement_html', rules_path: about_more_path, terms_path: terms_path)
+  .fields-group
+    = f.input :agreement, as: :boolean, wrapper: :with_label, label: t('auth.checkbox_agreement_html', rules_path: about_more_path, terms_path: terms_path)
 
   .actions
     = f.button :button, sign_up_message, type: :submit
diff --git a/app/views/follower_accounts/index.html.haml b/app/views/follower_accounts/index.html.haml
index 31dab68bf..645dd2de1 100644
--- a/app/views/follower_accounts/index.html.haml
+++ b/app/views/follower_accounts/index.html.haml
@@ -9,6 +9,8 @@
 
 - if @account.user_hides_network?
   .nothing-here= t('accounts.network_hidden')
+- elsif user_signed_in? && @account.blocking?(current_account)
+  .nothing-here= t('accounts.unavailable')
 - elsif @follows.empty?
   = nothing_here
 - else
diff --git a/app/views/following_accounts/index.html.haml b/app/views/following_accounts/index.html.haml
index 8b49b529b..17fe79018 100644
--- a/app/views/following_accounts/index.html.haml
+++ b/app/views/following_accounts/index.html.haml
@@ -9,6 +9,8 @@
 
 - if @account.user_hides_network?
   .nothing-here= t('accounts.network_hidden')
+- elsif user_signed_in? && @account.blocking?(current_account)
+  .nothing-here= t('accounts.unavailable')
 - elsif @follows.empty?
   = nothing_here
 - else
diff --git a/app/views/settings/notifications/show.html.haml b/app/views/settings/notifications/show.html.haml
index 8aaac043b..6ec57b502 100644
--- a/app/views/settings/notifications/show.html.haml
+++ b/app/views/settings/notifications/show.html.haml
@@ -14,6 +14,7 @@
 
       - if current_user.staff?
         = ff.input :report, as: :boolean, wrapper: :with_label
+        = ff.input :pending_account, as: :boolean, wrapper: :with_label
 
   .fields-group
     = f.simple_fields_for :notification_emails, hash_to_object(current_user.settings.notification_emails) do |ff|
diff --git a/app/views/settings/preferences/show.html.haml b/app/views/settings/preferences/show.html.haml
index c666bafb5..a50f33517 100644
--- a/app/views/settings/preferences/show.html.haml
+++ b/app/views/settings/preferences/show.html.haml
@@ -6,6 +6,7 @@
   %li= link_to t('preferences.publishing'), '#settings_publishing'
   %li= link_to t('preferences.other'), '#settings_other'
   %li= link_to t('preferences.web'), '#settings_web'
+  %li= link_to t('settings.notifications'), settings_notifications_path
 
 = simple_form_for current_user, url: settings_preferences_path, html: { method: :put } do |f|
   = render 'shared/error_messages', object: current_user
diff --git a/app/workers/import/relationship_worker.rb b/app/workers/import/relationship_worker.rb
index e9db20a46..616da6da9 100644
--- a/app/workers/import/relationship_worker.rb
+++ b/app/workers/import/relationship_worker.rb
@@ -5,15 +5,16 @@ class Import::RelationshipWorker
 
   sidekiq_options queue: 'pull', retry: 8, dead: false
 
-  def perform(account_id, target_account_uri, relationship)
+  def perform(account_id, target_account_uri, relationship, options = {})
     from_account   = Account.find(account_id)
     target_account = ResolveAccountService.new.call(target_account_uri)
+    options.symbolize_keys!
 
     return if target_account.nil?
 
     case relationship
     when 'follow'
-      FollowService.new.call(from_account, target_account)
+      FollowService.new.call(from_account, target_account, options)
     when 'unfollow'
       UnfollowService.new.call(from_account, target_account)
     when 'block'
@@ -21,7 +22,7 @@ class Import::RelationshipWorker
     when 'unblock'
       UnblockService.new.call(from_account, target_account)
     when 'mute'
-      MuteService.new.call(from_account, target_account)
+      MuteService.new.call(from_account, target_account, options)
     when 'unmute'
       UnmuteService.new.call(from_account, target_account)
     end