about summary refs log tree commit diff
path: root/app
diff options
context:
space:
mode:
authorStarfall <us@starfall.systems>2022-04-26 10:41:24 -0500
committerStarfall <us@starfall.systems>2022-04-26 10:41:24 -0500
commitfd98fd86128a5cea302b8496b6c7d5464ec1958a (patch)
treef3e304a32bed75cb8ab6b1f38652192bff71c5f1 /app
parent8da73d2e57284c765b232bfc6842a7ac0f0a702b (diff)
parenta481af15a9b2a7829c2a849906aa4b475ccdbd98 (diff)
Merge remote-tracking branch 'glitch/main'
Diffstat (limited to 'app')
-rw-r--r--app/chewy/statuses_index.rb5
-rw-r--r--app/controllers/api/v1/admin/accounts_controller.rb3
-rw-r--r--app/controllers/api/v1/statuses_controller.rb6
-rw-r--r--app/controllers/api/v1/trends/links_controller.rb6
-rw-r--r--app/controllers/api/v1/trends/statuses_controller.rb6
-rw-r--r--app/controllers/api/v1/trends/tags_controller.rb6
-rw-r--r--app/controllers/api/v2/search_controller.rb4
-rw-r--r--app/controllers/settings/preferences_controller.rb3
-rw-r--r--app/javascript/flavours/glitch/actions/streaming.js17
-rw-r--r--app/javascript/flavours/glitch/actions/timelines.js22
-rw-r--r--app/javascript/flavours/glitch/components/status.js10
-rw-r--r--app/javascript/flavours/glitch/features/status/components/detailed_status.js9
-rw-r--r--app/javascript/flavours/glitch/reducers/timelines.js13
-rw-r--r--app/javascript/mastodon/actions/streaming.js17
-rw-r--r--app/javascript/mastodon/actions/timelines.js22
-rw-r--r--app/javascript/mastodon/locales/af.json1
-rw-r--r--app/javascript/mastodon/locales/ar.json45
-rw-r--r--app/javascript/mastodon/locales/ast.json7
-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/br.json7
-rw-r--r--app/javascript/mastodon/locales/ca.json31
-rw-r--r--app/javascript/mastodon/locales/ckb.json1
-rw-r--r--app/javascript/mastodon/locales/co.json1
-rw-r--r--app/javascript/mastodon/locales/cs.json95
-rw-r--r--app/javascript/mastodon/locales/cy.json1
-rw-r--r--app/javascript/mastodon/locales/da.json7
-rw-r--r--app/javascript/mastodon/locales/de.json25
-rw-r--r--app/javascript/mastodon/locales/defaultMessages.json4
-rw-r--r--app/javascript/mastodon/locales/el.json1
-rw-r--r--app/javascript/mastodon/locales/en.json1
-rw-r--r--app/javascript/mastodon/locales/eo.json35
-rw-r--r--app/javascript/mastodon/locales/es-AR.json1
-rw-r--r--app/javascript/mastodon/locales/es-MX.json1
-rw-r--r--app/javascript/mastodon/locales/es.json1
-rw-r--r--app/javascript/mastodon/locales/et.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.json3
-rw-r--r--app/javascript/mastodon/locales/ga.json177
-rw-r--r--app/javascript/mastodon/locales/gd.json1
-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/hi.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.json11
-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/is.json1
-rw-r--r--app/javascript/mastodon/locales/it.json9
-rw-r--r--app/javascript/mastodon/locales/ja.json1
-rw-r--r--app/javascript/mastodon/locales/ka.json1
-rw-r--r--app/javascript/mastodon/locales/kab.json1
-rw-r--r--app/javascript/mastodon/locales/kk.json1
-rw-r--r--app/javascript/mastodon/locales/kn.json1
-rw-r--r--app/javascript/mastodon/locales/ko.json9
-rw-r--r--app/javascript/mastodon/locales/ku.json1
-rw-r--r--app/javascript/mastodon/locales/kw.json1
-rw-r--r--app/javascript/mastodon/locales/lt.json1
-rw-r--r--app/javascript/mastodon/locales/lv.json1
-rw-r--r--app/javascript/mastodon/locales/mk.json1
-rw-r--r--app/javascript/mastodon/locales/ml.json1
-rw-r--r--app/javascript/mastodon/locales/mr.json1
-rw-r--r--app/javascript/mastodon/locales/ms.json1
-rw-r--r--app/javascript/mastodon/locales/nl.json1
-rw-r--r--app/javascript/mastodon/locales/nn.json1
-rw-r--r--app/javascript/mastodon/locales/no.json1
-rw-r--r--app/javascript/mastodon/locales/oc.json35
-rw-r--r--app/javascript/mastodon/locales/pa.json1
-rw-r--r--app/javascript/mastodon/locales/pl.json101
-rw-r--r--app/javascript/mastodon/locales/pt-BR.json1
-rw-r--r--app/javascript/mastodon/locales/pt-PT.json1
-rw-r--r--app/javascript/mastodon/locales/ro.json1
-rw-r--r--app/javascript/mastodon/locales/ru.json3
-rw-r--r--app/javascript/mastodon/locales/sa.json1
-rw-r--r--app/javascript/mastodon/locales/sc.json1
-rw-r--r--app/javascript/mastodon/locales/si.json1
-rw-r--r--app/javascript/mastodon/locales/sk.json1
-rw-r--r--app/javascript/mastodon/locales/sl.json7
-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/szl.json1
-rw-r--r--app/javascript/mastodon/locales/ta.json1
-rw-r--r--app/javascript/mastodon/locales/tai.json1
-rw-r--r--app/javascript/mastodon/locales/te.json1
-rw-r--r--app/javascript/mastodon/locales/th.json1
-rw-r--r--app/javascript/mastodon/locales/tr.json13
-rw-r--r--app/javascript/mastodon/locales/tt.json1
-rw-r--r--app/javascript/mastodon/locales/ug.json1
-rw-r--r--app/javascript/mastodon/locales/uk.json51
-rw-r--r--app/javascript/mastodon/locales/ur.json1
-rw-r--r--app/javascript/mastodon/locales/vi.json41
-rw-r--r--app/javascript/mastodon/locales/zgh.json1
-rw-r--r--app/javascript/mastodon/locales/zh-CN.json13
-rw-r--r--app/javascript/mastodon/locales/zh-HK.json1
-rw-r--r--app/javascript/mastodon/locales/zh-TW.json97
-rw-r--r--app/javascript/mastodon/reducers/timelines.js13
-rw-r--r--app/lib/feed_manager.rb2
-rw-r--r--app/lib/search_query_transformer.rb8
-rw-r--r--app/lib/user_settings_decorator.rb5
-rw-r--r--app/models/account_alias.rb5
-rw-r--r--app/models/status.rb2
-rw-r--r--app/models/trends/base.rb12
-rw-r--r--app/models/trends/links.rb5
-rw-r--r--app/models/trends/query.rb13
-rw-r--r--app/models/trends/statuses.rb31
-rw-r--r--app/models/user.rb2
-rw-r--r--app/serializers/web/notification_serializer.rb2
-rw-r--r--app/services/activitypub/fetch_featured_collection_service.rb2
-rw-r--r--app/services/notify_service.rb63
-rw-r--r--app/views/admin/trends/links/_preview_card.html.haml4
-rw-r--r--app/views/admin/trends/statuses/_status.html.haml4
-rw-r--r--app/views/settings/preferences/notifications/show.html.haml3
117 files changed, 720 insertions, 493 deletions
diff --git a/app/chewy/statuses_index.rb b/app/chewy/statuses_index.rb
index 1381a96ed..1304aeedb 100644
--- a/app/chewy/statuses_index.rb
+++ b/app/chewy/statuses_index.rb
@@ -55,6 +55,11 @@ class StatusesIndex < Chewy::Index
     data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
   end
 
+  crutch :votes do |collection|
+    data = ::PollVote.joins(:poll).where(poll: { status_id: collection.map(&:id) }).where(account: Account.local).pluck(:status_id, :account_id)
+    data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
+  end
+
   root date_detection: false do
     field :id, type: 'long'
     field :account_id, type: 'long'
diff --git a/app/controllers/api/v1/admin/accounts_controller.rb b/app/controllers/api/v1/admin/accounts_controller.rb
index dc9d3402f..65ed69f7b 100644
--- a/app/controllers/api/v1/admin/accounts_controller.rb
+++ b/app/controllers/api/v1/admin/accounts_controller.rb
@@ -65,8 +65,9 @@ class Api::V1::Admin::AccountsController < Api::BaseController
 
   def destroy
     authorize @account, :destroy?
+    json = render_to_body json: @account, serializer: REST::Admin::AccountSerializer
     Admin::AccountDeletionWorker.perform_async(@account.id)
-    render json: @account, serializer: REST::Admin::AccountSerializer
+    render json: json
   end
 
   def unsensitive
diff --git a/app/controllers/api/v1/statuses_controller.rb b/app/controllers/api/v1/statuses_controller.rb
index 7de446ac4..b2cee3e92 100644
--- a/app/controllers/api/v1/statuses_controller.rb
+++ b/app/controllers/api/v1/statuses_controller.rb
@@ -79,10 +79,12 @@ class Api::V1::StatusesController < Api::BaseController
     authorize @status, :destroy?
 
     @status.discard
-    RemovalWorker.perform_async(@status.id, { 'redraft' => true })
     @status.account.statuses_count = @status.account.statuses_count - 1
+    json = render_to_body json: @status, serializer: REST::StatusSerializer, source_requested: true
+
+    RemovalWorker.perform_async(@status.id, { 'redraft' => true })
 
-    render json: @status, serializer: REST::StatusSerializer, source_requested: true
+    render json: json
   end
 
   private
diff --git a/app/controllers/api/v1/trends/links_controller.rb b/app/controllers/api/v1/trends/links_controller.rb
index b1cde5a4b..2385fe438 100644
--- a/app/controllers/api/v1/trends/links_controller.rb
+++ b/app/controllers/api/v1/trends/links_controller.rb
@@ -36,13 +36,17 @@ class Api::V1::Trends::LinksController < Api::BaseController
   end
 
   def next_path
-    api_v1_trends_links_url pagination_params(offset: offset_param + limit_param(DEFAULT_LINKS_LIMIT))
+    api_v1_trends_links_url pagination_params(offset: offset_param + limit_param(DEFAULT_LINKS_LIMIT)) if records_continue?
   end
 
   def prev_path
     api_v1_trends_links_url pagination_params(offset: offset_param - limit_param(DEFAULT_LINKS_LIMIT)) if offset_param > limit_param(DEFAULT_LINKS_LIMIT)
   end
 
+  def records_continue?
+    @links.size == limit_param(DEFAULT_LINKS_LIMIT)
+  end
+
   def offset_param
     params[:offset].to_i
   end
diff --git a/app/controllers/api/v1/trends/statuses_controller.rb b/app/controllers/api/v1/trends/statuses_controller.rb
index 4977803fb..1f2fff582 100644
--- a/app/controllers/api/v1/trends/statuses_controller.rb
+++ b/app/controllers/api/v1/trends/statuses_controller.rb
@@ -36,7 +36,7 @@ class Api::V1::Trends::StatusesController < Api::BaseController
   end
 
   def next_path
-    api_v1_trends_statuses_url pagination_params(offset: offset_param + limit_param(DEFAULT_STATUSES_LIMIT))
+    api_v1_trends_statuses_url pagination_params(offset: offset_param + limit_param(DEFAULT_STATUSES_LIMIT)) if records_continue?
   end
 
   def prev_path
@@ -46,4 +46,8 @@ class Api::V1::Trends::StatusesController < Api::BaseController
   def offset_param
     params[:offset].to_i
   end
+
+  def records_continue?
+    @statuses.size == limit_param(DEFAULT_STATUSES_LIMIT)
+  end
 end
diff --git a/app/controllers/api/v1/trends/tags_controller.rb b/app/controllers/api/v1/trends/tags_controller.rb
index 329ef5ae7..38003f599 100644
--- a/app/controllers/api/v1/trends/tags_controller.rb
+++ b/app/controllers/api/v1/trends/tags_controller.rb
@@ -32,7 +32,7 @@ class Api::V1::Trends::TagsController < Api::BaseController
   end
 
   def next_path
-    api_v1_trends_tags_url pagination_params(offset: offset_param + limit_param(DEFAULT_TAGS_LIMIT))
+    api_v1_trends_tags_url pagination_params(offset: offset_param + limit_param(DEFAULT_TAGS_LIMIT)) if records_continue?
   end
 
   def prev_path
@@ -42,4 +42,8 @@ class Api::V1::Trends::TagsController < Api::BaseController
   def offset_param
     params[:offset].to_i
   end
+
+  def records_continue?
+    @tags.size == limit_param(DEFAULT_TAGS_LIMIT)
+  end
 end
diff --git a/app/controllers/api/v2/search_controller.rb b/app/controllers/api/v2/search_controller.rb
index ddcf92200..77eeab5b0 100644
--- a/app/controllers/api/v2/search_controller.rb
+++ b/app/controllers/api/v2/search_controller.rb
@@ -11,6 +11,10 @@ class Api::V2::SearchController < Api::BaseController
   def index
     @search = Search.new(search_results)
     render json: @search, serializer: REST::SearchSerializer
+  rescue Mastodon::SyntaxError
+    unprocessable_entity
+  rescue ActiveRecord::RecordNotFound
+    not_found
   end
 
   private
diff --git a/app/controllers/settings/preferences_controller.rb b/app/controllers/settings/preferences_controller.rb
index 1fddd087b..669ed00c6 100644
--- a/app/controllers/settings/preferences_controller.rb
+++ b/app/controllers/settings/preferences_controller.rb
@@ -57,7 +57,8 @@ class Settings::PreferencesController < Settings::BaseController
       :setting_use_pending_items,
       :setting_trends,
       :setting_crop_images,
-      notification_emails: %i(follow follow_request reblog favourite mention digest report pending_account trending_tag trending_link trending_status),
+      :setting_always_send_emails,
+      notification_emails: %i(follow follow_request reblog favourite mention digest report pending_account trending_tag trending_link trending_status appeal),
       interactions: %i(must_be_follower must_be_following must_be_following_dm)
     )
   end
diff --git a/app/javascript/flavours/glitch/actions/streaming.js b/app/javascript/flavours/glitch/actions/streaming.js
index 223924534..90d6a0231 100644
--- a/app/javascript/flavours/glitch/actions/streaming.js
+++ b/app/javascript/flavours/glitch/actions/streaming.js
@@ -7,6 +7,10 @@ import {
   expandHomeTimeline,
   connectTimeline,
   disconnectTimeline,
+  fillHomeTimelineGaps,
+  fillPublicTimelineGaps,
+  fillCommunityTimelineGaps,
+  fillListTimelineGaps,
 } from './timelines';
 import { updateNotifications, expandNotifications } from './notifications';
 import { updateConversations } from './conversations';
@@ -35,6 +39,7 @@ const randomUpTo = max =>
  * @param {Object.<string, string>} params
  * @param {Object} options
  * @param {function(Function, Function): void} [options.fallback]
+ * @param {function(): void} [options.fillGaps]
  * @param {function(object): boolean} [options.accept]
  * @return {function(): void}
  */
@@ -61,6 +66,10 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti
           clearTimeout(pollingId);
           pollingId = null;
         }
+
+        if (options.fillGaps) {
+          dispatch(options.fillGaps());
+        }
       },
 
       onDisconnect() {
@@ -119,7 +128,7 @@ const refreshHomeTimelineAndNotification = (dispatch, done) => {
  * @return {function(): void}
  */
 export const connectUserStream = () =>
-  connectTimelineStream('home', 'user', {}, { fallback: refreshHomeTimelineAndNotification });
+  connectTimelineStream('home', 'user', {}, { fallback: refreshHomeTimelineAndNotification, fillGaps: fillHomeTimelineGaps });
 
 /**
  * @param {Object} options
@@ -127,7 +136,7 @@ export const connectUserStream = () =>
  * @return {function(): void}
  */
 export const connectCommunityStream = ({ onlyMedia } = {}) =>
-  connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`);
+  connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`, {}, { fillGaps: () => (fillCommunityTimelineGaps({ onlyMedia })) });
 
 /**
  * @param {Object} options
@@ -137,7 +146,7 @@ export const connectCommunityStream = ({ onlyMedia } = {}) =>
  * @return {function(): void}
  */
 export const connectPublicStream = ({ onlyMedia, onlyRemote, allowLocalOnly } = {}) =>
-  connectTimelineStream(`public${onlyRemote ? ':remote' : (allowLocalOnly ? ':allow_local_only' : '')}${onlyMedia ? ':media' : ''}`, `public${onlyRemote ? ':remote' : (allowLocalOnly ? ':allow_local_only' : '')}${onlyMedia ? ':media' : ''}`);
+  connectTimelineStream(`public${onlyRemote ? ':remote' : (allowLocalOnly ? ':allow_local_only' : '')}${onlyMedia ? ':media' : ''}`, `public${onlyRemote ? ':remote' : (allowLocalOnly ? ':allow_local_only' : '')}${onlyMedia ? ':media' : ''}`, {}, { fillGaps: () => fillPublicTimelineGaps({ onlyMedia, onlyRemote, allowLocalOnly }) });
 
 /**
  * @param {string} columnId
@@ -160,4 +169,4 @@ export const connectDirectStream = () =>
  * @return {function(): void}
  */
 export const connectListStream = listId =>
-  connectTimelineStream(`list:${listId}`, 'list', { list: listId });
+  connectTimelineStream(`list:${listId}`, 'list', { list: listId }, { fillGaps: () => fillListTimelineGaps(listId) });
diff --git a/app/javascript/flavours/glitch/actions/timelines.js b/app/javascript/flavours/glitch/actions/timelines.js
index 24cc0d63f..0b36d8ac3 100644
--- a/app/javascript/flavours/glitch/actions/timelines.js
+++ b/app/javascript/flavours/glitch/actions/timelines.js
@@ -138,6 +138,22 @@ export function expandTimeline(timelineId, path, params = {}, done = noOp) {
   };
 };
 
+export function fillTimelineGaps(timelineId, path, params = {}, done = noOp) {
+  return (dispatch, getState) => {
+    const timeline = getState().getIn(['timelines', timelineId], ImmutableMap());
+    const items = timeline.get('items');
+    const nullIndexes = items.map((statusId, index) => statusId === null ? index : null);
+    const gaps = nullIndexes.map(index => index > 0 ? items.get(index - 1) : null);
+
+    // Only expand at most two gaps to avoid doing too many requests
+    done = gaps.take(2).reduce((done, maxId) => {
+      return (() => dispatch(expandTimeline(timelineId, path, { ...params, maxId }, done)));
+    }, done);
+
+    done();
+  };
+}
+
 export const expandHomeTimeline            = ({ maxId } = {}, done = noOp) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId }, done);
 export const expandPublicTimeline          = ({ maxId, onlyMedia, onlyRemote, allowLocalOnly } = {}, done = noOp) => expandTimeline(`public${onlyRemote ? ':remote' : (allowLocalOnly ? ':allow_local_only' : '')}${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { remote: !!onlyRemote, allow_local_only: !!allowLocalOnly, max_id: maxId, only_media: !!onlyMedia }, done);
 export const expandCommunityTimeline       = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, max_id: maxId, only_media: !!onlyMedia }, done);
@@ -156,6 +172,11 @@ export const expandHashtagTimeline         = (hashtag, { maxId, tags, local } =
   }, done);
 };
 
+export const fillHomeTimelineGaps      = (done = noOp) => fillTimelineGaps('home', '/api/v1/timelines/home', {}, done);
+export const fillPublicTimelineGaps    = ({ onlyMedia, onlyRemote, allowLocalOnly } = {}, done = noOp) => fillTimelineGaps(`public${onlyRemote ? ':remote' : (allowLocalOnly ? ':allow_local_only' : '')}${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { remote: !!onlyRemote, only_media: !!onlyMedia, allow_local_only: !!allowLocalOnly }, done);
+export const fillCommunityTimelineGaps = ({ onlyMedia } = {}, done = noOp) => fillTimelineGaps(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, only_media: !!onlyMedia }, done);
+export const fillListTimelineGaps      = (id, done = noOp) => fillTimelineGaps(`list:${id}`, `/api/v1/timelines/list/${id}`, {}, done);
+
 export function expandTimelineRequest(timeline, isLoadingMore) {
   return {
     type: TIMELINE_EXPAND_REQUEST,
@@ -199,6 +220,7 @@ export function connectTimeline(timeline) {
   return {
     type: TIMELINE_CONNECT,
     timeline,
+    usePendingItems: preferPendingItems,
   };
 };
 
diff --git a/app/javascript/flavours/glitch/components/status.js b/app/javascript/flavours/glitch/components/status.js
index 02ff9ab28..21f0e3a6f 100644
--- a/app/javascript/flavours/glitch/components/status.js
+++ b/app/javascript/flavours/glitch/components/status.js
@@ -581,10 +581,7 @@ class Status extends ImmutablePureComponent {
     //  backgrounds for collapsed statuses are enabled.
 
     attachments = status.get('media_attachments');
-    if (status.get('poll')) {
-      media.push(<PollContainer pollId={status.get('poll')} />);
-      mediaIcons.push('tasks');
-    }
+
     if (usingPiP) {
       media.push(<PictureInPicturePlaceholder width={this.props.cachedMediaWidth} />);
       mediaIcons.push('video-camera');
@@ -684,6 +681,11 @@ class Status extends ImmutablePureComponent {
       mediaIcons.push('link');
     }
 
+    if (status.get('poll')) {
+      media.push(<PollContainer pollId={status.get('poll')} />);
+      mediaIcons.push('tasks');
+    }
+
     //  Here we prepare extra data-* attributes for CSS selectors.
     //  Users can use those for theming, hiding avatars etc via UserStyle
     const selectorAttribs = {
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 528d2eb73..f4e6c24c5 100644
--- a/app/javascript/flavours/glitch/features/status/components/detailed_status.js
+++ b/app/javascript/flavours/glitch/features/status/components/detailed_status.js
@@ -134,10 +134,6 @@ class DetailedStatus extends ImmutablePureComponent {
       outerStyle.height = `${this.state.height}px`;
     }
 
-    if (status.get('poll')) {
-      media.push(<PollContainer pollId={status.get('poll')} />);
-      mediaIcons.push('tasks');
-    }
     if (usingPiP) {
       media.push(<PictureInPicturePlaceholder />);
       mediaIcons.push('video-camera');
@@ -202,6 +198,11 @@ class DetailedStatus extends ImmutablePureComponent {
       mediaIcons.push('link');
     }
 
+    if (status.get('poll')) {
+      media.push(<PollContainer pollId={status.get('poll')} />);
+      mediaIcons.push('tasks');
+    }
+
     if (status.get('application')) {
       applicationLink = <React.Fragment> · <a className='detailed-status__application' href={status.getIn(['application', 'website'])} target='_blank' rel='noopener noreferrer'>{status.getIn(['application', 'name'])}</a></React.Fragment>;
     }
diff --git a/app/javascript/flavours/glitch/reducers/timelines.js b/app/javascript/flavours/glitch/reducers/timelines.js
index 29e02a864..afd9d12cb 100644
--- a/app/javascript/flavours/glitch/reducers/timelines.js
+++ b/app/javascript/flavours/glitch/reducers/timelines.js
@@ -177,6 +177,17 @@ const updateTop = (state, timeline, top) => {
   }));
 };
 
+const reconnectTimeline = (state, usePendingItems) => {
+  if (state.get('online')) {
+    return state;
+  }
+
+  return state.withMutations(mMap => {
+    mMap.update(usePendingItems ? 'pendingItems' : 'items', items => items.first() ? items.unshift(null) : items);
+    mMap.set('online', true);
+  });
+};
+
 export default function timelines(state = initialState, action) {
   switch(action.type) {
   case TIMELINE_LOAD_PENDING:
@@ -202,7 +213,7 @@ export default function timelines(state = initialState, action) {
   case TIMELINE_SCROLL_TOP:
     return updateTop(state, action.timeline, action.top);
   case TIMELINE_CONNECT:
-    return state.update(action.timeline, initialTimeline, map => map.set('online', true));
+    return state.update(action.timeline, initialTimeline, map => reconnectTimeline(map, action.usePendingItems));
   case TIMELINE_DISCONNECT:
     return state.update(
       action.timeline,
diff --git a/app/javascript/mastodon/actions/streaming.js b/app/javascript/mastodon/actions/streaming.js
index 8fbb22271..d76f045c8 100644
--- a/app/javascript/mastodon/actions/streaming.js
+++ b/app/javascript/mastodon/actions/streaming.js
@@ -7,6 +7,10 @@ import {
   expandHomeTimeline,
   connectTimeline,
   disconnectTimeline,
+  fillHomeTimelineGaps,
+  fillPublicTimelineGaps,
+  fillCommunityTimelineGaps,
+  fillListTimelineGaps,
 } from './timelines';
 import { updateNotifications, expandNotifications } from './notifications';
 import { updateConversations } from './conversations';
@@ -35,6 +39,7 @@ const randomUpTo = max =>
  * @param {Object.<string, string>} params
  * @param {Object} options
  * @param {function(Function, Function): void} [options.fallback]
+ * @param {function(): void} [options.fillGaps]
  * @param {function(object): boolean} [options.accept]
  * @return {function(): void}
  */
@@ -61,6 +66,10 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti
           clearTimeout(pollingId);
           pollingId = null;
         }
+
+        if (options.fillGaps) {
+          dispatch(options.fillGaps());
+        }
       },
 
       onDisconnect() {
@@ -119,7 +128,7 @@ const refreshHomeTimelineAndNotification = (dispatch, done) => {
  * @return {function(): void}
  */
 export const connectUserStream = () =>
-  connectTimelineStream('home', 'user', {}, { fallback: refreshHomeTimelineAndNotification });
+  connectTimelineStream('home', 'user', {}, { fallback: refreshHomeTimelineAndNotification, fillGaps: fillHomeTimelineGaps });
 
 /**
  * @param {Object} options
@@ -127,7 +136,7 @@ export const connectUserStream = () =>
  * @return {function(): void}
  */
 export const connectCommunityStream = ({ onlyMedia } = {}) =>
-  connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`);
+  connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`, {}, { fillGaps: () => (fillCommunityTimelineGaps({ onlyMedia })) });
 
 /**
  * @param {Object} options
@@ -136,7 +145,7 @@ export const connectCommunityStream = ({ onlyMedia } = {}) =>
  * @return {function(): void}
  */
 export const connectPublicStream = ({ onlyMedia, onlyRemote } = {}) =>
-  connectTimelineStream(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, `public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`);
+  connectTimelineStream(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, `public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, {}, { fillGaps: () => fillPublicTimelineGaps({ onlyMedia, onlyRemote }) });
 
 /**
  * @param {string} columnId
@@ -159,4 +168,4 @@ export const connectDirectStream = () =>
  * @return {function(): void}
  */
 export const connectListStream = listId =>
-  connectTimelineStream(`list:${listId}`, 'list', { list: listId });
+  connectTimelineStream(`list:${listId}`, 'list', { list: listId }, { fillGaps: () => fillListTimelineGaps(listId) });
diff --git a/app/javascript/mastodon/actions/timelines.js b/app/javascript/mastodon/actions/timelines.js
index 31ae09e4a..44fedd5c2 100644
--- a/app/javascript/mastodon/actions/timelines.js
+++ b/app/javascript/mastodon/actions/timelines.js
@@ -124,6 +124,22 @@ export function expandTimeline(timelineId, path, params = {}, done = noOp) {
   };
 };
 
+export function fillTimelineGaps(timelineId, path, params = {}, done = noOp) {
+  return (dispatch, getState) => {
+    const timeline = getState().getIn(['timelines', timelineId], ImmutableMap());
+    const items = timeline.get('items');
+    const nullIndexes = items.map((statusId, index) => statusId === null ? index : null);
+    const gaps = nullIndexes.map(index => index > 0 ? items.get(index - 1) : null);
+
+    // Only expand at most two gaps to avoid doing too many requests
+    done = gaps.take(2).reduce((done, maxId) => {
+      return (() => dispatch(expandTimeline(timelineId, path, { ...params, maxId }, done)));
+    }, done);
+
+    done();
+  };
+}
+
 export const expandHomeTimeline            = ({ maxId } = {}, done = noOp) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId }, done);
 export const expandPublicTimeline          = ({ maxId, onlyMedia, onlyRemote } = {}, done = noOp) => expandTimeline(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { remote: !!onlyRemote, max_id: maxId, only_media: !!onlyMedia }, done);
 export const expandCommunityTimeline       = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, max_id: maxId, only_media: !!onlyMedia }, done);
@@ -141,6 +157,11 @@ export const expandHashtagTimeline         = (hashtag, { maxId, tags, local } =
   }, done);
 };
 
+export const fillHomeTimelineGaps      = (done = noOp) => fillTimelineGaps('home', '/api/v1/timelines/home', {}, done);
+export const fillPublicTimelineGaps    = ({ onlyMedia, onlyRemote } = {}, done = noOp) => fillTimelineGaps(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { remote: !!onlyRemote, only_media: !!onlyMedia }, done);
+export const fillCommunityTimelineGaps = ({ onlyMedia } = {}, done = noOp) => fillTimelineGaps(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, only_media: !!onlyMedia }, done);
+export const fillListTimelineGaps      = (id, done = noOp) => fillTimelineGaps(`list:${id}`, `/api/v1/timelines/list/${id}`, {}, done);
+
 export function expandTimelineRequest(timeline, isLoadingMore) {
   return {
     type: TIMELINE_EXPAND_REQUEST,
@@ -184,6 +205,7 @@ export function connectTimeline(timeline) {
   return {
     type: TIMELINE_CONNECT,
     timeline,
+    usePendingItems: preferPendingItems,
   };
 };
 
diff --git a/app/javascript/mastodon/locales/af.json b/app/javascript/mastodon/locales/af.json
index 088b5ff36..4373287dd 100644
--- a/app/javascript/mastodon/locales/af.json
+++ b/app/javascript/mastodon/locales/af.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "File upload not allowed with polls.",
   "upload_form.audio_description": "Describe for people with hearing loss",
   "upload_form.description": "Describe for the visually impaired",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Edit",
   "upload_form.thumbnail": "Change thumbnail",
   "upload_form.undo": "Delete",
diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json
index 6580f5d44..57d8376a9 100644
--- a/app/javascript/mastodon/locales/ar.json
+++ b/app/javascript/mastodon/locales/ar.json
@@ -2,8 +2,8 @@
   "account.account_note_header": "مُلاحظة",
   "account.add_or_remove_from_list": "الإضافة أو الإزالة من القائمة",
   "account.badges.bot": "روبوت",
-  "account.badges.group": "مجموعة",
-  "account.block": "حظر @{name}",
+  "account.badges.group": "فريق",
+  "account.block": "احجب @{name}",
   "account.block_domain": "حظر اسم النِّطاق {domain}",
   "account.blocked": "محظور",
   "account.browse_more_on_origin_server": "تصفح المزيد في الملف الشخصي الأصلي",
@@ -11,14 +11,14 @@
   "account.direct": "مراسلة @{name} بشكل مباشر",
   "account.disable_notifications": "توقف عن إشعاري عندما ينشر @{name}",
   "account.domain_blocked": "اسم النِّطاق محظور",
-  "account.edit_profile": "تحرير الملف الشخصي",
+  "account.edit_profile": "تعديل الملف الشخصي",
   "account.enable_notifications": "أشعرني عندما ينشر @{name}",
   "account.endorse": "أوصِ به على صفحتك الشخصية",
-  "account.follow": "المُتابعة",
-  "account.followers": "المُتابِعون",
-  "account.followers.empty": "لا أحدَ يُتابع هذا المُستخدم حتى الآن.",
+  "account.follow": "متابعة",
+  "account.followers": "مُتابِعون",
+  "account.followers.empty": "لا أحدَ يُتابع هذا المُستخدم إلى حد الآن.",
   "account.followers_counter": "{count, plural, zero{لا مُتابع} one {مُتابعٌ واحِد} two{مُتابعانِ اِثنان} few{{counter} مُتابِعين} many{{counter}  مُتابِعًا} other {{counter}  مُتابع}}",
-  "account.following": "Following",
+  "account.following": "الإشتراكات",
   "account.following_counter": "{count, plural, zero{لا يُتابِع} one {يُتابِعُ واحد} two{يُتابِعُ اِثنان} few{يُتابِعُ {counter}} many{يُتابِعُ {counter}} other {يُتابِعُ {counter}}}",
   "account.follows.empty": "لا يُتابع هذا المُستخدمُ أيَّ أحدٍ حتى الآن.",
   "account.follows_you": "يُتابِعُك",
@@ -35,18 +35,18 @@
   "account.posts": "منشورات",
   "account.posts_with_replies": "المنشورات والرُدود",
   "account.report": "الإبلاغ عن @{name}",
-  "account.requested": "في اِنتظر القُبول. اِنقُر لإلغاء طلب المُتابعة",
+  "account.requested": "في انتظار القبول. اضغط لإلغاء طلب المُتابعة",
   "account.share": "مُشاركة الملف الشخصي لـ @{name}",
   "account.show_reblogs": "عرض مشاركات @{name}",
-  "account.statuses_counter": "{count, plural, zero {لَا تَبويقات} one {تَبويقةٌ واحدة} two {تَبويقَتانِ اِثنتان} few {{counter} تَبويقات} many {{counter} تَبويقتًا} other {{counter} تَبويقة}}",
+  "account.statuses_counter": "{count, plural, zero {لَا منشورات} one {منشور واحد} two {منشوران إثنان} few {{counter} منشورات} many {{counter} منشورًا} other {{counter} منشور}}",
   "account.unblock": "إلغاء الحَظر عن @{name}",
   "account.unblock_domain": "إلغاء الحَظر عن النِّطاق {domain}",
-  "account.unblock_short": "Unblock",
+  "account.unblock_short": "ألغ الحجب",
   "account.unendorse": "لا تُرَوِّج لهُ في الملف الشخصي",
   "account.unfollow": "إلغاء المُتابعة",
   "account.unmute": "إلغاء الكَتم عن @{name}",
   "account.unmute_notifications": "إلغاء كَتم الإشعارات عن @{name}",
-  "account.unmute_short": "Unmute",
+  "account.unmute_short": "إلغاء الكتم",
   "account_note.placeholder": "اضغط لإضافة مُلاحظة",
   "admin.dashboard.daily_retention": "User retention rate by day after sign-up",
   "admin.dashboard.monthly_retention": "User retention rate by month after sign-up",
@@ -78,7 +78,7 @@
   "column.home": "الرئيسية",
   "column.lists": "القوائم",
   "column.mutes": "المُستَخدِمون المَكتومون",
-  "column.notifications": "الإشعارَات",
+  "column.notifications": "الإشعارات",
   "column.pins": "المنشورات المُثَبَّتَة",
   "column.public": "الخَطُّ الزَّمَنِيُّ المُوَحَّد",
   "column_back_button.label": "العودة",
@@ -294,7 +294,7 @@
   "navigation_bar.discover": "اكتشف",
   "navigation_bar.domain_blocks": "النطاقات المخفية",
   "navigation_bar.edit_profile": "عدّل الملف التعريفي",
-  "navigation_bar.explore": "Explore",
+  "navigation_bar.explore": "استكشف",
   "navigation_bar.favourites": "المفضلة",
   "navigation_bar.filters": "الكلمات المكتومة",
   "navigation_bar.follow_requests": "طلبات المتابعة",
@@ -309,16 +309,16 @@
   "navigation_bar.preferences": "التفضيلات",
   "navigation_bar.public_timeline": "الخيط العام الموحد",
   "navigation_bar.security": "الأمان",
-  "notification.admin.sign_up": "{name} signed up",
+  "notification.admin.sign_up": "أنشأ {name} حسابًا",
   "notification.favourite": "أُعجِب {name} بمنشورك",
   "notification.follow": "{name} يتابعك",
   "notification.follow_request": "لقد طلب {name} متابعتك",
   "notification.mention": "{name} ذكرك",
   "notification.own_poll": "انتهى استطلاعك للرأي",
-  "notification.poll": "لقد إنتها تصويت شاركت فيه",
+  "notification.poll": "لقد انتهى استطلاع رأي شاركتَ فيه",
   "notification.reblog": "قام {name} بمشاركة منشورك",
   "notification.status": "{name} نشر للتو",
-  "notification.update": "{name} edited a post",
+  "notification.update": "عدّلَ {name} منشورًا",
   "notifications.clear": "امسح الإخطارات",
   "notifications.clear_confirmation": "أمتأكد من أنك تود مسح جل الإخطارات الخاصة بك و المتلقاة إلى حد الآن ؟",
   "notifications.column_settings.admin.sign_up": "التسجيلات الجديدة:",
@@ -408,9 +408,9 @@
   "report.placeholder": "تعليقات إضافية",
   "report.reasons.dislike": "لايعجبني",
   "report.reasons.dislike_description": "ألا ترغب برؤيته",
-  "report.reasons.other": "It's something else",
-  "report.reasons.other_description": "The issue does not fit into other categories",
-  "report.reasons.spam": "It's spam",
+  "report.reasons.other": "شيء آخر",
+  "report.reasons.other_description": "لا تندرج هذه المشكلة ضمن فئات أخرى",
+  "report.reasons.spam": "إنها رسالة مزعجة",
   "report.reasons.spam_description": "Malicious links, fake engagement, or repetitive replies",
   "report.reasons.violation": "ينتهك قواعد الخادم",
   "report.reasons.violation_description": "You are aware that it breaks specific rules",
@@ -456,8 +456,8 @@
   "status.embed": "إدماج",
   "status.favourite": "أضف إلى المفضلة",
   "status.filtered": "مُصفّى",
-  "status.history.created": "{name} created {date}",
-  "status.history.edited": "{name} edited {date}",
+  "status.history.created": "أنشأه {name} {date}",
+  "status.history.edited": "عدله {name} {date}",
   "status.load_more": "حمّل المزيد",
   "status.media_hidden": "الصورة مستترة",
   "status.mention": "أذكُر @{name}",
@@ -470,7 +470,7 @@
   "status.read_more": "اقرأ المزيد",
   "status.reblog": "رَقِّي",
   "status.reblog_private": "القيام بالترقية إلى الجمهور الأصلي",
-  "status.reblogged_by": "رقّاه {name}",
+  "status.reblogged_by": "شارَكَه {name}",
   "status.reblogs.empty": "لم يقم أي أحد بمشاركة هذا المنشور بعد. عندما يقوم أحدهم بذلك سوف يظهر هنا.",
   "status.redraft": "إزالة و إعادة الصياغة",
   "status.remove_bookmark": "احذفه مِن الفواصل المرجعية",
@@ -515,6 +515,7 @@
   "upload_error.poll": "لا يمكن إدراج ملفات في استطلاعات الرأي.",
   "upload_form.audio_description": "وصف للأشخاص ذي قِصر السمع",
   "upload_form.description": "وصف للمعاقين بصريا",
+  "upload_form.description_missing": "لم يُضف وصف",
   "upload_form.edit": "تعديل",
   "upload_form.thumbnail": "غيّر الصورة المصغرة",
   "upload_form.undo": "حذف",
diff --git a/app/javascript/mastodon/locales/ast.json b/app/javascript/mastodon/locales/ast.json
index 14e46e458..e7f7248e1 100644
--- a/app/javascript/mastodon/locales/ast.json
+++ b/app/javascript/mastodon/locales/ast.json
@@ -404,7 +404,7 @@
   "report.forward_hint": "La cuenta ye d'otru sirvidor. ¿Quies unviar ellí tamién una copia anónima del informe?",
   "report.mute": "Mute",
   "report.mute_explanation": "You will not see their posts. They can still follow you and see your posts and will not know that they are muted.",
-  "report.next": "Next",
+  "report.next": "Siguiente",
   "report.placeholder": "Comentarios adicionales",
   "report.reasons.dislike": "I don't like it",
   "report.reasons.dislike_description": "It is not something you want to see",
@@ -412,7 +412,7 @@
   "report.reasons.other_description": "The issue does not fit into other categories",
   "report.reasons.spam": "It's spam",
   "report.reasons.spam_description": "Malicious links, fake engagement, or repetitive replies",
-  "report.reasons.violation": "It violates server rules",
+  "report.reasons.violation": "Incumple les regles del sirvidor",
   "report.reasons.violation_description": "You are aware that it breaks specific rules",
   "report.rules.subtitle": "Select all that apply",
   "report.rules.title": "Which rules are being violated?",
@@ -420,7 +420,7 @@
   "report.statuses.title": "Are there any posts that back up this report?",
   "report.submit": "Unviar",
   "report.target": "Report {target}",
-  "report.thanks.take_action": "Here are your options for controlling what you see on Mastodon:",
+  "report.thanks.take_action": "Equí tan les opciones pa controlar qué ver en Mastodon:",
   "report.thanks.take_action_actionable": "While we review this, you can take action against @{name}:",
   "report.thanks.title": "Don't want to see this?",
   "report.thanks.title_actionable": "Thanks for reporting, we'll look into this.",
@@ -515,6 +515,7 @@
   "upload_error.poll": "La xuba de ficheros nun ta permitida con encuestes.",
   "upload_form.audio_description": "Descripción pa persones con perda auditiva",
   "upload_form.description": "Descripción pa discapacitaos visuales",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Editar",
   "upload_form.thumbnail": "Change thumbnail",
   "upload_form.undo": "Desaniciar",
diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json
index e65681394..3efde0381 100644
--- a/app/javascript/mastodon/locales/bg.json
+++ b/app/javascript/mastodon/locales/bg.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Качването на файлове не е позволено с анкети.",
   "upload_form.audio_description": "Опишете за хора със загуба на слуха",
   "upload_form.description": "Опишете за хора със зрителни увреждания",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Редакция",
   "upload_form.thumbnail": "Промяна на миниизображението",
   "upload_form.undo": "Отмяна",
diff --git a/app/javascript/mastodon/locales/bn.json b/app/javascript/mastodon/locales/bn.json
index 3542c4e46..75e0fbb77 100644
--- a/app/javascript/mastodon/locales/bn.json
+++ b/app/javascript/mastodon/locales/bn.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "নির্বাচনক্ষেত্রে কোনো ফাইল যুক্ত করা যাবেনা।",
   "upload_form.audio_description": "শ্রবণশক্তি লোকদের জন্য বর্ণনা করুন",
   "upload_form.description": "যারা দেখতে পায়না তাদের জন্য এটা বর্ণনা করতে",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "সম্পাদন",
   "upload_form.thumbnail": "থাম্বনেল পরিবর্তন করুন",
   "upload_form.undo": "মুছে ফেলতে",
diff --git a/app/javascript/mastodon/locales/br.json b/app/javascript/mastodon/locales/br.json
index 51b78f777..8b86cd62a 100644
--- a/app/javascript/mastodon/locales/br.json
+++ b/app/javascript/mastodon/locales/br.json
@@ -187,12 +187,12 @@
   "error.unexpected_crash.next_steps_addons": "Klaskit azbevaat ar bajenn. Ma n'ez a ket en-dro e c'hallit klask ober gant Mastodon dre ur merdeer disheñvel pe dre an arload genidik.",
   "errors.unexpected_crash.copy_stacktrace": "Eilañ ar roudoù diveugañ er golver",
   "errors.unexpected_crash.report_issue": "Danevellañ ur fazi",
-  "explore.search_results": "Search results",
+  "explore.search_results": "Disoc'hoù an enklask",
   "explore.suggested_follows": "For you",
-  "explore.title": "Explore",
+  "explore.title": "Ergerzhit",
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
-  "explore.trending_tags": "Hashtags",
+  "explore.trending_tags": "Gerioù-klik",
   "follow_recommendations.done": "Graet",
   "follow_recommendations.heading": "Heuliit tud e plijfe deoc'h lenn toudoù! Setu un tamm alioù.",
   "follow_recommendations.lead": "Toudoù eus tud heuliet ganeoc'h a zeuio war wel en un urzh amzeroniezhel war ho red degemer. N'ho peus ket aon ober fazioù, gallout a rit paouez heuliañ tud ken aes n'eus forzh pegoulz!",
@@ -515,6 +515,7 @@
   "upload_error.poll": "Pellgargañ restroù n'eo ket aotreet gant sontadegoù.",
   "upload_form.audio_description": "Diskrivañ evit tud a zo kollet o c'hlev",
   "upload_form.description": "Diskrivañ evit tud a zo kollet o gweled",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Aozañ",
   "upload_form.thumbnail": "Kemmañ ar velvenn",
   "upload_form.undo": "Dilemel",
diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json
index 055732cfd..a325426c3 100644
--- a/app/javascript/mastodon/locales/ca.json
+++ b/app/javascript/mastodon/locales/ca.json
@@ -8,10 +8,10 @@
   "account.blocked": "Bloquejat",
   "account.browse_more_on_origin_server": "Navega més en el perfil original",
   "account.cancel_follow_request": "Anul·la la sol·licitud de seguiment",
-  "account.direct": "Missatge directe @{name}",
+  "account.direct": "Enviar missatge directe a @{name}",
   "account.disable_notifications": "Deixa de notificar-me les publicacions de @{name}",
   "account.domain_blocked": "Domini bloquejat",
-  "account.edit_profile": "Edita el perfil",
+  "account.edit_profile": "Editar el perfil",
   "account.enable_notifications": "Notifica’m les publicacions de @{name}",
   "account.endorse": "Recomana en el teu perfil",
   "account.follow": "Segueix",
@@ -38,7 +38,7 @@
   "account.requested": "Esperant aprovació. Clic per a cancel·lar la petició de seguiment",
   "account.share": "Comparteix el perfil de @{name}",
   "account.show_reblogs": "Mostra els impulsos de @{name}",
-  "account.statuses_counter": "{count, plural, one {{counter} Tut} other {{counter} Tuts}}",
+  "account.statuses_counter": "{count, plural, one {{counter} Publicació} other {{counter} Publicacions}}",
   "account.unblock": "Desbloqueja @{name}",
   "account.unblock_domain": "Desbloqueja el domini {domain}",
   "account.unblock_short": "Desbloqueja",
@@ -48,10 +48,10 @@
   "account.unmute_notifications": "Activar notificacions de @{name}",
   "account.unmute_short": "Deixa de silenciar",
   "account_note.placeholder": "Fes clic per afegir una nota",
-  "admin.dashboard.daily_retention": "Ràtio de retenció per dia després del registre",
-  "admin.dashboard.monthly_retention": "Ràtio de retenció per mes després del registre",
+  "admin.dashboard.daily_retention": "Ràtio de retenció d'usuaris nous, per dia, després del registre",
+  "admin.dashboard.monthly_retention": "Ràtio de retenció d'usuaris nous, per mes, després del registre",
   "admin.dashboard.retention.average": "Mitjana",
-  "admin.dashboard.retention.cohort": "Registres mes",
+  "admin.dashboard.retention.cohort": "Mes del registre",
   "admin.dashboard.retention.cohort_size": "Nous usuaris",
   "alert.rate_limited.message": "Si us plau prova-ho després de {retry_time, time, medium}.",
   "alert.rate_limited.title": "Límit de freqüència",
@@ -144,7 +144,7 @@
   "directory.local": "Només de {domain}",
   "directory.new_arrivals": "Arribades noves",
   "directory.recently_active": "Recentment actius",
-  "embed.instructions": "Incrusta aquest tut al lloc web copiant el codi a continuació.",
+  "embed.instructions": "Incrusta aquesta publicació a la teva pàgina web copiant el codi següent.",
   "embed.preview": "Aquí està quin aspecte tindrà:",
   "emoji_button.activity": "Activitat",
   "emoji_button.custom": "Personalitzat",
@@ -204,7 +204,7 @@
   "getting_started.directory": "Directori de perfils",
   "getting_started.documentation": "Documentació",
   "getting_started.heading": "Primeres passes",
-  "getting_started.invite": "Convida gent",
+  "getting_started.invite": "Convidar gent",
   "getting_started.open_source_notice": "Mastodon és un programari de codi obert. Pots contribuir-hi o informar de problemes a GitHub a {github}.",
   "getting_started.security": "Configuració del compte",
   "getting_started.terms": "Termes del servei",
@@ -233,7 +233,7 @@
   "keyboard_shortcuts.description": "Descripció",
   "keyboard_shortcuts.direct": "Obre la columna de missatges directes",
   "keyboard_shortcuts.down": "Baixar en la llista",
-  "keyboard_shortcuts.enter": "Obre publicació",
+  "keyboard_shortcuts.enter": "Obrir publicació",
   "keyboard_shortcuts.favourite": "Afavorir publicació",
   "keyboard_shortcuts.favourites": "Obre la llista de favorits",
   "keyboard_shortcuts.federated": "Obre la línia de temps federada",
@@ -247,7 +247,7 @@
   "keyboard_shortcuts.my_profile": "Obre el teu perfil",
   "keyboard_shortcuts.notifications": "Obre la columna de notificacions",
   "keyboard_shortcuts.open_media": "Obre mèdia",
-  "keyboard_shortcuts.pinned": "Obre la llista de publicacions fixades",
+  "keyboard_shortcuts.pinned": "Obrir la llista de publicacions fixades",
   "keyboard_shortcuts.profile": "Obre el perfil de l'autor",
   "keyboard_shortcuts.reply": "Respon publicació",
   "keyboard_shortcuts.requests": "Obre la llista de sol·licituds de seguiment",
@@ -256,7 +256,7 @@
   "keyboard_shortcuts.start": "Obre la columna \"Primeres passes\"",
   "keyboard_shortcuts.toggle_hidden": "Mostra/oculta el text marcat com a sensible",
   "keyboard_shortcuts.toggle_sensitivity": "Mostra/amaga contingut multimèdia",
-  "keyboard_shortcuts.toot": "per a començar un tut nou de trinca",
+  "keyboard_shortcuts.toot": "Iniciar una nova publicació",
   "keyboard_shortcuts.unfocus": "Descentra l'àrea de composició de text/cerca",
   "keyboard_shortcuts.up": "Moure amunt en la llista",
   "lightbox.close": "Tanca",
@@ -289,7 +289,7 @@
   "navigation_bar.blocks": "Usuaris bloquejats",
   "navigation_bar.bookmarks": "Marcadors",
   "navigation_bar.community_timeline": "Línia de temps Local",
-  "navigation_bar.compose": "Redacta una nova publicació",
+  "navigation_bar.compose": "Redactar una nova publicació",
   "navigation_bar.direct": "Missatges directes",
   "navigation_bar.discover": "Descobrir",
   "navigation_bar.domain_blocks": "Dominis bloquejats",
@@ -411,7 +411,7 @@
   "report.reasons.other": "Això és una altre cosa",
   "report.reasons.other_description": "El problema no encaixa en altres categories",
   "report.reasons.spam": "Això és contingut brossa",
-  "report.reasons.spam_description": "Enllaços maliciosos, compromís falç o respostes repetitives",
+  "report.reasons.spam_description": "Enllaços maliciosos, falç compromís o respostes repetitives",
   "report.reasons.violation": "Viola les regles del servidor",
   "report.reasons.violation_description": "Ets conscient que trenca regles especifiques",
   "report.rules.subtitle": "Selecciona totes les aplicables",
@@ -441,7 +441,7 @@
   "search_results.statuses_fts_disabled": "La cerca de publicacions pel seu contingut no està habilitada en aquest servidor Mastodon.",
   "search_results.total": "{count, number} {count, plural, one {resultat} other {resultats}}",
   "status.admin_account": "Obre l'interfície de moderació per a @{name}",
-  "status.admin_status": "Obre aquesta publicació a la interfície de moderació",
+  "status.admin_status": "Obrir aquesta publicació a la interfície de moderació",
   "status.block": "Bloqueja @{name}",
   "status.bookmark": "Marcador",
   "status.cancel_reblog_private": "Desfer l'impuls",
@@ -502,7 +502,7 @@
   "timeline_hint.remote_resource_not_displayed": "{resource} dels altres servidors no son mostrats.",
   "timeline_hint.resources.followers": "Seguidors",
   "timeline_hint.resources.follows": "Seguiments",
-  "timeline_hint.resources.statuses": "Tuts més antics",
+  "timeline_hint.resources.statuses": "Publicacions més antigues",
   "trends.counter_by_accounts": "{count, plural, one {{counter} persona} other {{counter} persones}} parlant-hi",
   "trends.trending_now": "Ara en tendència",
   "ui.beforeunload": "El teu esborrany es perdrà si surts de Mastodon.",
@@ -515,6 +515,7 @@
   "upload_error.poll": "No es permet l'enviament de fitxers en les enquestes.",
   "upload_form.audio_description": "Descriviu per a les persones amb pèrdua auditiva",
   "upload_form.description": "Descriure per els que tenen problemes visuals",
+  "upload_form.description_missing": "Cap descripció afegida",
   "upload_form.edit": "Edita",
   "upload_form.thumbnail": "Canvia la miniatura",
   "upload_form.undo": "Esborra",
diff --git a/app/javascript/mastodon/locales/ckb.json b/app/javascript/mastodon/locales/ckb.json
index 7209633ad..09058276f 100644
--- a/app/javascript/mastodon/locales/ckb.json
+++ b/app/javascript/mastodon/locales/ckb.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "پەڕگەکە ڕێی پێنەدراوە بە ڕاپرسی باربکرێت.",
   "upload_form.audio_description": "بۆ ئەو کەسانەی کە گوێ بیستیان هەیە وەسف دەکات",
   "upload_form.description": "وەسف بکە بۆ کەمبینایان",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "دەستکاری",
   "upload_form.thumbnail": "گۆڕانی وینۆچکە",
   "upload_form.undo": "سڕینەوە",
diff --git a/app/javascript/mastodon/locales/co.json b/app/javascript/mastodon/locales/co.json
index 21240bc3b..453aa9653 100644
--- a/app/javascript/mastodon/locales/co.json
+++ b/app/javascript/mastodon/locales/co.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Ùn si pò micca caricà fugliali cù i scandagli.",
   "upload_form.audio_description": "Discrizzione per i ciochi",
   "upload_form.description": "Discrizzione per i malvistosi",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Mudificà",
   "upload_form.thumbnail": "Cambià vignetta",
   "upload_form.undo": "Sguassà",
diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json
index c6ffaa6f2..0b49c3f77 100644
--- a/app/javascript/mastodon/locales/cs.json
+++ b/app/javascript/mastodon/locales/cs.json
@@ -5,7 +5,7 @@
   "account.badges.group": "Skupina",
   "account.block": "Zablokovat @{name}",
   "account.block_domain": "Blokovat doménu {domain}",
-  "account.blocked": "Blokováno",
+  "account.blocked": "Blokován",
   "account.browse_more_on_origin_server": "Více na původním profilu",
   "account.cancel_follow_request": "Zrušit žádost o sledování",
   "account.direct": "Poslat @{name} přímou zprávu",
@@ -18,7 +18,7 @@
   "account.followers": "Sledující",
   "account.followers.empty": "Tohoto uživatele ještě nikdo nesleduje.",
   "account.followers_counter": "{count, plural, one {{counter} Sledující} few {{counter} Sledující} many {{counter} Sledujících} other {{counter} Sledujících}}",
-  "account.following": "Following",
+  "account.following": "Sledujete",
   "account.following_counter": "{count, plural, one {{counter} Sledovaný} few {{counter} Sledovaní} many {{counter} Sledovaných} other {{counter} Sledovaných}}",
   "account.follows.empty": "Tento uživatel ještě nikoho nesleduje.",
   "account.follows_you": "Sleduje vás",
@@ -41,15 +41,15 @@
   "account.statuses_counter": "{count, plural, one {{counter} Příspěvek} few {{counter} Příspěvky} many {{counter} Příspěvků} other {{counter} Příspěvků}}",
   "account.unblock": "Odblokovat @{name}",
   "account.unblock_domain": "Odblokovat doménu {domain}",
-  "account.unblock_short": "Unblock",
+  "account.unblock_short": "Odblokovat",
   "account.unendorse": "Nezvýrazňovat na profilu",
   "account.unfollow": "Přestat sledovat",
-  "account.unmute": "Zrušit skrytí @{name}",
-  "account.unmute_notifications": "Zrušit skrytí oznámení od @{name}",
-  "account.unmute_short": "Unmute",
+  "account.unmute": "Odkrýt @{name}",
+  "account.unmute_notifications": "Odkrýt oznámení od @{name}",
+  "account.unmute_short": "Odkrýt",
   "account_note.placeholder": "Klikněte pro přidání poznámky",
-  "admin.dashboard.daily_retention": "User retention rate by day after sign-up",
-  "admin.dashboard.monthly_retention": "User retention rate by month after sign-up",
+  "admin.dashboard.daily_retention": "Míra udržení uživatelů podle dne po registraci",
+  "admin.dashboard.monthly_retention": "Míra udržení uživatelů podle měsíce po registraci",
   "admin.dashboard.retention.average": "Průměr",
   "admin.dashboard.retention.cohort": "Měsíc registrace",
   "admin.dashboard.retention.cohort_size": "Noví uživatelé",
@@ -106,7 +106,7 @@
   "compose_form.poll.switch_to_single": "Povolit u ankety výběr jediné možnosti",
   "compose_form.publish": "Odeslat",
   "compose_form.publish_loud": "{publish}!",
-  "compose_form.save_changes": "Save changes",
+  "compose_form.save_changes": "Uložit změny",
   "compose_form.sensitive.hide": "{count, plural, one {Označit média za citlivá} few {Označit média za citlivá} many {Označit média za citlivá} other {Označit média za citlivá}}",
   "compose_form.sensitive.marked": "{count, plural, one {Média jsou označena za citlivá} few {Média jsou označena za citlivá} many {Média jsou označena za citlivá} other {Média jsou označena za citlivá}}",
   "compose_form.sensitive.unmarked": "{count, plural, one {Média nejsou označena za citlivá} few {Média nejsou označena za citlivá} many {Média nejsou označena za citlivá} other {Média nejsou označena za citlivá}}",
@@ -168,7 +168,7 @@
   "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.",
   "empty_column.domain_blocks": "Ještě nemáte žádné blokované domény.",
-  "empty_column.explore_statuses": "Nothing is trending right now. Check back later!",
+  "empty_column.explore_statuses": "Momentálně není nic populární. Vraťte se později!",
   "empty_column.favourited_statuses": "Ještě nemáte žádné oblíbené příspěvky. Pokud si nějaký oblíbíte, zobrazí se zde.",
   "empty_column.favourites": "Tento příspěvek si ještě nikdo neoblíbil. Pokud to někdo udělá, zobrazí se zde.",
   "empty_column.follow_recommendations": "Zdá se, že pro vás nelze vygenerovat žádné návrhy. Můžete zkusit přes vyhledávání naleznout lidi, které znáte, nebo prozkoumat populární hashtagy.",
@@ -187,18 +187,18 @@
   "error.unexpected_crash.next_steps_addons": "Zkuste je vypnout a stránku obnovit. Pokud to nepomůže, zkuste otevřít Mastodon v jiném prohlížeči nebo nativní aplikaci.",
   "errors.unexpected_crash.copy_stacktrace": "Zkopírovat stacktrace do schránky",
   "errors.unexpected_crash.report_issue": "Nahlásit problém",
-  "explore.search_results": "Search results",
-  "explore.suggested_follows": "For you",
-  "explore.title": "Explore",
-  "explore.trending_links": "News",
-  "explore.trending_statuses": "Posts",
-  "explore.trending_tags": "Hashtags",
+  "explore.search_results": "Výsledky hledání",
+  "explore.suggested_follows": "Pro vás",
+  "explore.title": "Objevování",
+  "explore.trending_links": "Zprávy",
+  "explore.trending_statuses": "Příspěvky",
+  "explore.trending_tags": "Hashtagy",
   "follow_recommendations.done": "Hotovo",
   "follow_recommendations.heading": "Sledujte lidi, jejichž příspěvky chcete vidět! Tady jsou nějaké návrhy.",
   "follow_recommendations.lead": "Příspěvky od lidí, které sledujete, se budou objevovat v chronologickém pořadí ve vaší domovské ose. Nebojte se, že uděláte chybu, můžete lidi stejně snadno kdykoliv přestat sledovat!",
   "follow_request.authorize": "Autorizovat",
   "follow_request.reject": "Odmítnout",
-  "follow_requests.unlocked_explanation": "Přestože váš účet není uzamčen, {domain} si myslí, že budete chtít následující požadavky na sledování zkontrolovat ručně.",
+  "follow_requests.unlocked_explanation": "Přestože váš účet není uzamčen, personál {domain} usoudil, že byste mohli chtít tyto požadavky na sledování zkontrolovat ručně.",
   "generic.saved": "Uloženo",
   "getting_started.developers": "Vývojáři",
   "getting_started.directory": "Adresář profilů",
@@ -309,7 +309,7 @@
   "navigation_bar.preferences": "Předvolby",
   "navigation_bar.public_timeline": "Federovaná časová osa",
   "navigation_bar.security": "Zabezpečení",
-  "notification.admin.sign_up": "{name} signed up",
+  "notification.admin.sign_up": "Uživatel {name} se zaregistroval",
   "notification.favourite": "Uživatel {name} si oblíbil váš příspěvek",
   "notification.follow": "Uživatel {name} vás začal sledovat",
   "notification.follow_request": "Uživatel {name} požádal o povolení vás sledovat",
@@ -318,10 +318,10 @@
   "notification.poll": "Anketa, ve které jste hlasovali, skončila",
   "notification.reblog": "Uživatel {name} boostnul váš příspěvek",
   "notification.status": "Nový příspěvek od {name}",
-  "notification.update": "uživatel {name} upravil příspěvek",
-  "notifications.clear": "Smazat oznámení",
+  "notification.update": "Uživatel {name} upravil příspěvek",
+  "notifications.clear": "Vymazat oznámení",
   "notifications.clear_confirmation": "Opravdu chcete trvale smazat všechna vaše oznámení?",
-  "notifications.column_settings.admin.sign_up": "New sign-ups:",
+  "notifications.column_settings.admin.sign_up": "Nové registrace:",
   "notifications.column_settings.alert": "Oznámení na počítači",
   "notifications.column_settings.favourite": "Oblíbení:",
   "notifications.column_settings.filter_bar.advanced": "Zobrazit všechny kategorie",
@@ -378,32 +378,32 @@
   "regeneration_indicator.label": "Načítání…",
   "regeneration_indicator.sublabel": "Váš domovský kanál se připravuje!",
   "relative_time.days": "{number} d",
-  "relative_time.full.days": "{number, plural, one {# day} other {# days}} ago",
-  "relative_time.full.hours": "{number, plural, one {# hour} other {# hours}} ago",
+  "relative_time.full.days": "před {number, plural, one {# dnem} few {# dny} many {# dny} other {# dny}}",
+  "relative_time.full.hours": "před {number, plural, one {# hodinou} few {# hodinami} many {# hodinami} other {# hodinami}}",
   "relative_time.full.just_now": "právě teď",
-  "relative_time.full.minutes": "{number, plural, one {# minute} other {# minutes}} ago",
-  "relative_time.full.seconds": "{number, plural, one {# second} other {# seconds}} ago",
+  "relative_time.full.minutes": "před {number, plural, one {# minutou} few {# minutami} many {# minutami} other {# minutami}}",
+  "relative_time.full.seconds": "před {number, plural, one {# sekundou} few {# sekundami} many {# sekundami} other {# sekundami}}",
   "relative_time.hours": "{number} h",
   "relative_time.just_now": "teď",
   "relative_time.minutes": "{number} m",
   "relative_time.seconds": "{number} s",
   "relative_time.today": "dnes",
   "reply_indicator.cancel": "Zrušit",
-  "report.block": "Block",
-  "report.block_explanation": "You will not see their posts. They will not be able to see your posts or follow you. They will be able to tell that they are blocked.",
+  "report.block": "Zablokovat",
+  "report.block_explanation": "Neuvidíte jejich příspěvky. Oni neuvidí vaše příspěvky ani vás nebudou moci sledovat. Poznají, že jsou blokováni.",
   "report.categories.other": "Ostatní",
   "report.categories.spam": "Spam",
   "report.categories.violation": "Obsah porušuje jedno nebo více pravidel serveru",
   "report.category.subtitle": "Vyberte nejbližší možnost",
   "report.category.title": "Povězte nám, proč chcete {type} nahlásit",
-  "report.category.title_account": "profile",
-  "report.category.title_status": "post",
-  "report.close": "Done",
-  "report.comment.title": "Is there anything else you think we should know?",
+  "report.category.title_account": "profil",
+  "report.category.title_status": "příspěvek",
+  "report.close": "Hotovo",
+  "report.comment.title": "Ještě něco jiného, co myslíte, že bychom měli vědět?",
   "report.forward": "Přeposlat na {target}",
   "report.forward_hint": "Tento účet je z jiného serveru. Chcete na něj také poslat anonymizovanou kopii hlášení?",
-  "report.mute": "Mute",
-  "report.mute_explanation": "You will not see their posts. They can still follow you and see your posts and will not know that they are muted.",
+  "report.mute": "Skrýt",
+  "report.mute_explanation": "Neuvidíte jejich příspěvky. Oni vás mohou nadále sledovat i vidět vaše příspěvky a nebudou vědět, že jsou skryti.",
   "report.next": "Dále",
   "report.placeholder": "Dodatečné komentáře",
   "report.reasons.dislike": "Nelíbí se mi",
@@ -420,12 +420,12 @@
   "report.statuses.title": "Existují příspěvky dokládající toto hlášení?",
   "report.submit": "Odeslat",
   "report.target": "Nahlášení uživatele {target}",
-  "report.thanks.take_action": "Here are your options for controlling what you see on Mastodon:",
-  "report.thanks.take_action_actionable": "While we review this, you can take action against @{name}:",
-  "report.thanks.title": "Don't want to see this?",
-  "report.thanks.title_actionable": "Thanks for reporting, we'll look into this.",
-  "report.unfollow": "Unfollow @{name}",
-  "report.unfollow_explanation": "You are following this account. To not see their posts in your home feed anymore, unfollow them.",
+  "report.thanks.take_action": "Tady jsou vaše možnosti pro řízení toho, co na Mastodonu vidíte:",
+  "report.thanks.take_action_actionable": "Zatímco to posuzujeme, můžete podniknout kroky proti @{name}:",
+  "report.thanks.title": "Nechcete tohle vidět?",
+  "report.thanks.title_actionable": "Děkujeme za nahlášení, podíváme se na to.",
+  "report.unfollow": "Přestat sledovat @{name}",
+  "report.unfollow_explanation": "Tento účet sledujete. Abyste už neviděli jejich příspěvky ve své domácí časové ose, přestaňte je sledovat.",
   "search.placeholder": "Hledat",
   "search_popout.search_format": "Pokročilé hledání",
   "search_popout.tips.full_text": "Jednoduchý text vrací příspěvky, které jste napsali, oblíbili si, boostnuli, nebo vás v nich někdo zmínil, a také odpovídající přezdívky, zobrazovaná jména a hashtagy.",
@@ -434,9 +434,9 @@
   "search_popout.tips.text": "Jednoduchý text vrací odpovídající zobrazovaná jména, přezdívky a hashtagy",
   "search_popout.tips.user": "uživatel",
   "search_results.accounts": "Lidé",
-  "search_results.all": "All",
+  "search_results.all": "Vše",
   "search_results.hashtags": "Hashtagy",
-  "search_results.nothing_found": "Could not find anything for these search terms",
+  "search_results.nothing_found": "Pro tyto hledané výrazy nebylo nic nenalezeno",
   "search_results.statuses": "Příspěvky",
   "search_results.statuses_fts_disabled": "Vyhledávání příspěvků podle jejich obsahu není na tomto Mastodon serveru povoleno.",
   "search_results.total": "{count, number} {count, plural, one {výsledek} few {výsledky} many {výsledků} other {výsledků}}",
@@ -450,14 +450,14 @@
   "status.delete": "Smazat",
   "status.detailed_status": "Podrobné zobrazení konverzace",
   "status.direct": "Poslat @{name} přímou zprávu",
-  "status.edit": "Edit",
-  "status.edited": "Edited {date}",
-  "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
+  "status.edit": "Upravit",
+  "status.edited": "Upraven {date}",
+  "status.edited_x_times": "Upraven {count, plural, one {{count}krát} few {{count}krát} many {{count}krát} other {{count}krát}}",
   "status.embed": "Vložit na web",
   "status.favourite": "Oblíbit",
   "status.filtered": "Filtrováno",
-  "status.history.created": "{name} created {date}",
-  "status.history.edited": "{name} edited {date}",
+  "status.history.created": "Uživatel {name} vytvořil {date}",
+  "status.history.edited": "Uživatel {name} upravil {date}",
   "status.load_more": "Zobrazit více",
   "status.media_hidden": "Média skryta",
   "status.mention": "Zmínit @{name}",
@@ -501,7 +501,7 @@
   "time_remaining.seconds": "{number, plural, one {Zbývá # sekunda} few {Zbývají # sekundy} many {Zbývá # sekund} other {Zbývá # sekund}}",
   "timeline_hint.remote_resource_not_displayed": "{resource} z jiných serveru se nezobrazuje.",
   "timeline_hint.resources.followers": "Sledující",
-  "timeline_hint.resources.follows": "Sleduje",
+  "timeline_hint.resources.follows": "Sledovaní",
   "timeline_hint.resources.statuses": "Starší příspěvky",
   "trends.counter_by_accounts": "zmiňuje {count, plural, one {{counter} člověk} few {{counter} lidé} many {{counter} lidí} other {{counter} lidí}}",
   "trends.trending_now": "Právě populární",
@@ -515,6 +515,7 @@
   "upload_error.poll": "U anket není nahrávání souborů povoleno.",
   "upload_form.audio_description": "Popis pro sluchově postižené",
   "upload_form.description": "Popis pro zrakově postižené",
+  "upload_form.description_missing": "Nebyl přidán popis",
   "upload_form.edit": "Upravit",
   "upload_form.thumbnail": "Změnit miniaturu",
   "upload_form.undo": "Smazat",
diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json
index d3ac8d806..b220db1c5 100644
--- a/app/javascript/mastodon/locales/cy.json
+++ b/app/javascript/mastodon/locales/cy.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Nid oes modd uwchlwytho ffeiliau â phleidleisiau.",
   "upload_form.audio_description": "Disgrifio ar gyfer pobl sydd â cholled clyw",
   "upload_form.description": "Disgrifio i'r rheini a nam ar ei golwg",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Golygu",
   "upload_form.thumbnail": "Newid mân-lun",
   "upload_form.undo": "Dileu",
diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json
index 12023bfb0..d029e6244 100644
--- a/app/javascript/mastodon/locales/da.json
+++ b/app/javascript/mastodon/locales/da.json
@@ -506,15 +506,16 @@
   "trends.counter_by_accounts": "{count, plural, one {{counter} person} other {{counter} personer}} taler",
   "trends.trending_now": "Hot lige nu",
   "ui.beforeunload": "Dit udkast går tabt, hvis du lukker Mastodon.",
-  "units.short.billion": "{count} MIA",
-  "units.short.million": "{count} M",
-  "units.short.thousand": "{count} K",
+  "units.short.billion": "{count} mia.",
+  "units.short.million": "{count} mio.",
+  "units.short.thousand": "{count} tusind",
   "upload_area.title": "Træk og slip for at uploade",
   "upload_button.label": "Tilføj billed-, video- eller lydfil(er)",
   "upload_error.limit": "Grænse for filupload nået.",
   "upload_error.poll": "Filupload ikke tilladt for afstemninger.",
   "upload_form.audio_description": "Beskrivelse til hørehæmmede",
   "upload_form.description": "Beskrivelse til svagtseende",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Redigér",
   "upload_form.thumbnail": "Skift miniature",
   "upload_form.undo": "Slet",
diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json
index 1178c0260..706cc087e 100644
--- a/app/javascript/mastodon/locales/de.json
+++ b/app/javascript/mastodon/locales/de.json
@@ -13,22 +13,22 @@
   "account.domain_blocked": "Domain versteckt",
   "account.edit_profile": "Profil bearbeiten",
   "account.enable_notifications": "Benachrichtige mich wenn @{name} etwas postet",
-  "account.endorse": "Auf Profil hervorheben",
+  "account.endorse": "Im Profil anzeigen",
   "account.follow": "Folgen",
   "account.followers": "Follower",
-  "account.followers.empty": "Diesem Profil folgt noch niemand.",
+  "account.followers.empty": "Diesem Profil folgt bislang niemand.",
   "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Follower}}",
   "account.following": "Folgt",
-  "account.following_counter": "{count, plural, one {{counter} Folgender} other {{counter} Folgende}}",
+  "account.following_counter": "{count, plural, one {{counter} Folgt} other {{counter} Folgt}}",
   "account.follows.empty": "Dieses Profil folgt noch niemandem.",
   "account.follows_you": "Folgt dir",
   "account.hide_reblogs": "Geteilte Beiträge von @{name} verbergen",
   "account.joined": "Beigetreten am {date}",
   "account.link_verified_on": "Besitz dieses Links wurde geprüft am {date}",
-  "account.locked_info": "Der Privatsphärenstatus dieses Accounts wurde auf gesperrt gesetzt. Die Person bestimmt manuell wer ihm/ihr folgen darf.",
+  "account.locked_info": "Der Privatsphärenstatus dieses Accounts wurde auf „gesperrt“ gesetzt. Die Person bestimmt manuell, wer ihm/ihr folgen darf.",
   "account.media": "Medien",
   "account.mention": "@{name} erwähnen",
-  "account.moved_to": "{name} ist umgezogen auf:",
+  "account.moved_to": "{name} ist umgezogen nach:",
   "account.mute": "@{name} stummschalten",
   "account.mute_notifications": "Benachrichtigungen von @{name} stummschalten",
   "account.muted": "Stummgeschaltet",
@@ -39,26 +39,26 @@
   "account.share": "Profil von @{name} teilen",
   "account.show_reblogs": "Von @{name} geteilte Beiträge anzeigen",
   "account.statuses_counter": "{count, plural, one {{counter} Beitrag} other {{counter} Beiträge}}",
-  "account.unblock": "@{name} entblocken",
+  "account.unblock": "Blockierung von @{name} aufheben",
   "account.unblock_domain": "{domain} wieder anzeigen",
   "account.unblock_short": "Blockierung aufheben",
-  "account.unendorse": "Nicht auf Profil hervorheben",
+  "account.unendorse": "Nicht mehr im Profil anzeigen",
   "account.unfollow": "Entfolgen",
-  "account.unmute": "@{name} nicht mehr stummschalten",
+  "account.unmute": "Stummschaltung von @{name} aufheben",
   "account.unmute_notifications": "Benachrichtigungen von @{name} einschalten",
-  "account.unmute_short": "Nicht mehr stummschalten",
+  "account.unmute_short": "Stummschaltung aufheben",
   "account_note.placeholder": "Notiz durch Klicken hinzufügen",
   "admin.dashboard.daily_retention": "Benutzerverbleibrate nach Tag nach Anmeldung",
   "admin.dashboard.monthly_retention": "Benutzerverbleibrate nach Monat nach Anmeldung",
   "admin.dashboard.retention.average": "Durchschnitt",
-  "admin.dashboard.retention.cohort": "Anmeldemonat",
+  "admin.dashboard.retention.cohort": "Monat der Anmeldung",
   "admin.dashboard.retention.cohort_size": "Neue Benutzer",
-  "alert.rate_limited.message": "Bitte versuche es nach {retry_time, time, medium}.",
+  "alert.rate_limited.message": "Bitte versuche es nach {retry_time, time, medium} erneut.",
   "alert.rate_limited.title": "Anfragelimit überschritten",
   "alert.unexpected.message": "Ein unerwarteter Fehler ist aufgetreten.",
   "alert.unexpected.title": "Hoppla!",
   "announcement.announcement": "Ankündigung",
-  "attachments_list.unprocessed": "(unverarbeitet)",
+  "attachments_list.unprocessed": "(ausstehend)",
   "autosuggest_hashtag.per_week": "{count} pro Woche",
   "boost_modal.combo": "Drücke {combo}, um dieses Fenster zu überspringen",
   "bundle_column_error.body": "Etwas ist beim Laden schiefgelaufen.",
@@ -515,6 +515,7 @@
   "upload_error.poll": "Dateiuploads sind in Kombination mit Umfragen nicht erlaubt.",
   "upload_form.audio_description": "Beschreibe die Audiodatei für Menschen mit Hörschädigungen",
   "upload_form.description": "Für Menschen mit Sehbehinderung beschreiben",
+  "upload_form.description_missing": "Keine Beschreibung hinzugefügt",
   "upload_form.edit": "Beschreiben",
   "upload_form.thumbnail": "Miniaturansicht ändern",
   "upload_form.undo": "Löschen",
diff --git a/app/javascript/mastodon/locales/defaultMessages.json b/app/javascript/mastodon/locales/defaultMessages.json
index 4b6aef7b0..555aa5898 100644
--- a/app/javascript/mastodon/locales/defaultMessages.json
+++ b/app/javascript/mastodon/locales/defaultMessages.json
@@ -1442,6 +1442,10 @@
       {
         "defaultMessage": "Describe",
         "id": "upload_form.edit"
+      },
+      {
+        "defaultMessage": "No description added",
+        "id": "upload_form.description_missing"
       }
     ],
     "path": "app/javascript/mastodon/features/compose/components/upload.json"
diff --git a/app/javascript/mastodon/locales/el.json b/app/javascript/mastodon/locales/el.json
index 3c797d47d..8b4a9c168 100644
--- a/app/javascript/mastodon/locales/el.json
+++ b/app/javascript/mastodon/locales/el.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Στις δημοσκοπήσεις δεν επιτρέπεται η μεταφόρτωση αρχείου.",
   "upload_form.audio_description": "Περιγραφή για άτομα με προβλήματα ακοής",
   "upload_form.description": "Περιέγραψε για όσους & όσες έχουν προβλήματα όρασης",
+  "upload_form.description_missing": "Δεν προστέθηκε περιγραφή",
   "upload_form.edit": "Ενημέρωση",
   "upload_form.thumbnail": "Αλλαγή μικρογραφίας",
   "upload_form.undo": "Διαγραφή",
diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json
index 6b638c3ae..467d041ee 100644
--- a/app/javascript/mastodon/locales/en.json
+++ b/app/javascript/mastodon/locales/en.json
@@ -520,6 +520,7 @@
   "upload_error.poll": "File upload not allowed with polls.",
   "upload_form.audio_description": "Describe for people with hearing loss",
   "upload_form.description": "Describe for the visually impaired",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Describe",
   "upload_form.thumbnail": "Change thumbnail",
   "upload_form.undo": "Delete",
diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json
index 7f999c34f..f72bb7244 100644
--- a/app/javascript/mastodon/locales/eo.json
+++ b/app/javascript/mastodon/locales/eo.json
@@ -168,10 +168,10 @@
   "empty_column.community": "La loka templinio 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.",
   "empty_column.domain_blocks": "Ankoraŭ neniu domajno estas blokita.",
-  "empty_column.explore_statuses": "Nothing is trending right now. Check back later!",
+  "empty_column.explore_statuses": "Nenio tendencas nun. Rekontrolu poste!",
   "empty_column.favourited_statuses": "Vi ankoraŭ ne stelumis mesaĝon. Kiam vi stelumos iun, tiu aperos ĉi tie.",
   "empty_column.favourites": "Ankoraŭ neniu stelumis tiun mesaĝon. Kiam iu faros tion, tiu aperos ĉi tie.",
-  "empty_column.follow_recommendations": "Looks like no suggestions could be generated for you. You can try using search to look for people you might know or explore trending hashtags.",
+  "empty_column.follow_recommendations": "Ŝajnas, ke neniuj sugestoj povis esti generitaj por vi. Vi povas provi uzi serĉon por serĉi homojn, kiujn vi eble konas, aŭ esplori tendencajn kradvortojn.",
   "empty_column.follow_requests": "Vi ne ankoraŭ havas iun peton de sekvado. Kiam vi ricevos unu, ĝi aperos ĉi tie.",
   "empty_column.hashtag": "Ankoraŭ estas nenio per ĉi tiu kradvorto.",
   "empty_column.home": "Via hejma tempolinio estas malplena! Vizitu {public} aŭ uzu la serĉilon por renkonti aliajn uzantojn.",
@@ -294,7 +294,7 @@
   "navigation_bar.discover": "Esplori",
   "navigation_bar.domain_blocks": "Blokitaj domajnoj",
   "navigation_bar.edit_profile": "Redakti profilon",
-  "navigation_bar.explore": "Explore",
+  "navigation_bar.explore": "Esplori",
   "navigation_bar.favourites": "Stelumoj",
   "navigation_bar.filters": "Silentigitaj vortoj",
   "navigation_bar.follow_requests": "Petoj de sekvado",
@@ -321,7 +321,7 @@
   "notification.update": "{name} redaktis afiŝon",
   "notifications.clear": "Forviŝi sciigojn",
   "notifications.clear_confirmation": "Ĉu vi certas, ke vi volas porĉiame forviŝi ĉiujn viajn sciigojn?",
-  "notifications.column_settings.admin.sign_up": "New sign-ups:",
+  "notifications.column_settings.admin.sign_up": "Novaj registriĝoj:",
   "notifications.column_settings.alert": "Retumilaj sciigoj",
   "notifications.column_settings.favourite": "Stelumoj:",
   "notifications.column_settings.filter_bar.advanced": "Montri ĉiujn kategoriojn",
@@ -337,7 +337,7 @@
   "notifications.column_settings.sound": "Eligi sonon",
   "notifications.column_settings.status": "Novaj mesaĝoj:",
   "notifications.column_settings.unread_notifications.category": "Nelegitaj sciigoj",
-  "notifications.column_settings.unread_notifications.highlight": "Highlight unread notifications",
+  "notifications.column_settings.unread_notifications.highlight": "Marki nelegitajn sciigojn",
   "notifications.column_settings.update": "Redaktoj:",
   "notifications.filter.all": "Ĉiuj",
   "notifications.filter.boosts": "Diskonigoj",
@@ -394,8 +394,8 @@
   "report.categories.other": "Aliaj",
   "report.categories.spam": "Spamo",
   "report.categories.violation": "Content violates one or more server rules",
-  "report.category.subtitle": "Choose the best match",
-  "report.category.title": "Tell us what's going on with this {type}",
+  "report.category.subtitle": "Elektu la plej bonan kongruon",
+  "report.category.title": "Diru al ni kio okazas pri ĉi tiu {type}",
   "report.category.title_account": "profilo",
   "report.category.title_status": "afiŝo",
   "report.close": "Farita",
@@ -407,25 +407,25 @@
   "report.next": "Sekva",
   "report.placeholder": "Pliaj komentoj",
   "report.reasons.dislike": "Mi ne ŝatas ĝin",
-  "report.reasons.dislike_description": "It is not something you want to see",
-  "report.reasons.other": "It's something else",
-  "report.reasons.other_description": "The issue does not fit into other categories",
-  "report.reasons.spam": "It's spam",
+  "report.reasons.dislike_description": "Ĝi ne estas io, kiun vi volas vidi",
+  "report.reasons.other": "Io alia",
+  "report.reasons.other_description": "La problemo ne taŭgas en aliaj kategorioj",
+  "report.reasons.spam": "Ĝi estas trudaĵo",
   "report.reasons.spam_description": "Malicious links, fake engagement, or repetitive replies",
   "report.reasons.violation": "Ĝi malrespektas servilajn regulojn",
   "report.reasons.violation_description": "You are aware that it breaks specific rules",
-  "report.rules.subtitle": "Select all that apply",
+  "report.rules.subtitle": "Elektu ĉiujn, kiuj validas",
   "report.rules.title": "Which rules are being violated?",
-  "report.statuses.subtitle": "Select all that apply",
+  "report.statuses.subtitle": "Elektu ĉiujn, kiuj validas",
   "report.statuses.title": "Are there any posts that back up this report?",
   "report.submit": "Sendi",
   "report.target": "Signali {target}",
   "report.thanks.take_action": "Here are your options for controlling what you see on Mastodon:",
   "report.thanks.take_action_actionable": "While we review this, you can take action against @{name}:",
-  "report.thanks.title": "Don't want to see this?",
-  "report.thanks.title_actionable": "Thanks for reporting, we'll look into this.",
+  "report.thanks.title": "Ĉu vi ne volas vidi ĉi tion?",
+  "report.thanks.title_actionable": "Dankon pro raporti, ni esploros ĉi tion.",
   "report.unfollow": "Malsekvi @{name}",
-  "report.unfollow_explanation": "You are following this account. To not see their posts in your home feed anymore, unfollow them.",
+  "report.unfollow_explanation": "Vi estas sekvanta ĉi tiun konton. Por ne plu vidi ties afiŝojn en via hejma templinio, malsekvu ilin.",
   "search.placeholder": "Serĉi",
   "search_popout.search_format": "Detala serĉo",
   "search_popout.tips.full_text": "Simplaj tekstoj montras la mesaĝojn, kiujn vi skribis, stelumis, diskonigis, aŭ en kiuj vi estis menciita, sed ankaŭ kongruajn uzantnomojn, montratajn nomojn, kaj kradvortojn.",
@@ -436,7 +436,7 @@
   "search_results.accounts": "Homoj",
   "search_results.all": "Ĉiuj",
   "search_results.hashtags": "Kradvortoj",
-  "search_results.nothing_found": "Could not find anything for these search terms",
+  "search_results.nothing_found": "Povis trovi nenion por ĉi tiuj serĉaj terminoj",
   "search_results.statuses": "Mesaĝoj",
   "search_results.statuses_fts_disabled": "Serĉi mesaĝojn laŭ enhavo ne estas ebligita en ĉi tiu Mastodon-servilo.",
   "search_results.total": "{count, number} {count, plural, one {rezulto} other {rezultoj}}",
@@ -515,6 +515,7 @@
   "upload_error.poll": "Alŝuto de dosiero ne permesita kun balotenketo.",
   "upload_form.audio_description": "Priskribi por homoj kiuj malfacile aŭdi",
   "upload_form.description": "Priskribi por misvidantaj homoj",
+  "upload_form.description_missing": "Neniu priskribo aldonita",
   "upload_form.edit": "Redakti",
   "upload_form.thumbnail": "Ŝanĝi etigita bildo",
   "upload_form.undo": "Forigi",
diff --git a/app/javascript/mastodon/locales/es-AR.json b/app/javascript/mastodon/locales/es-AR.json
index b239c69e6..233794b84 100644
--- a/app/javascript/mastodon/locales/es-AR.json
+++ b/app/javascript/mastodon/locales/es-AR.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "No se permite la subida de archivos en encuestas.",
   "upload_form.audio_description": "Agregá una descripción para personas con dificultades auditivas",
   "upload_form.description": "Agregá una descripción para personas con dificultades visuales",
+  "upload_form.description_missing": "No se agregó descripción",
   "upload_form.edit": "Editar",
   "upload_form.thumbnail": "Cambiar miniatura",
   "upload_form.undo": "Eliminar",
diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json
index ccdca8d9c..4ad7249be 100644
--- a/app/javascript/mastodon/locales/es-MX.json
+++ b/app/javascript/mastodon/locales/es-MX.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Subida de archivos no permitida con encuestas.",
   "upload_form.audio_description": "Describir para personas con problemas auditivos",
   "upload_form.description": "Describir para los usuarios con dificultad visual",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Editar",
   "upload_form.thumbnail": "Cambiar miniatura",
   "upload_form.undo": "Borrar",
diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json
index 9215c65d1..d80e2f43f 100644
--- a/app/javascript/mastodon/locales/es.json
+++ b/app/javascript/mastodon/locales/es.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Subida de archivos no permitida con encuestas.",
   "upload_form.audio_description": "Describir para personas con problemas auditivos",
   "upload_form.description": "Describir para los usuarios con dificultad visual",
+  "upload_form.description_missing": "Ninguna descripción añadida",
   "upload_form.edit": "Describir",
   "upload_form.thumbnail": "Cambiar miniatura",
   "upload_form.undo": "Borrar",
diff --git a/app/javascript/mastodon/locales/et.json b/app/javascript/mastodon/locales/et.json
index e3bcdb521..bb10fd504 100644
--- a/app/javascript/mastodon/locales/et.json
+++ b/app/javascript/mastodon/locales/et.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Küsitlustes pole faili üleslaadimine lubatud.",
   "upload_form.audio_description": "Kirjelda kuulmispuudega inimeste jaoks",
   "upload_form.description": "Kirjelda vaegnägijatele",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Redigeeri",
   "upload_form.thumbnail": "Change thumbnail",
   "upload_form.undo": "Kustuta",
diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json
index a5cbf5128..6aca056d0 100644
--- a/app/javascript/mastodon/locales/eu.json
+++ b/app/javascript/mastodon/locales/eu.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Ez da inkestetan fitxategiak igotzea onartzen.",
   "upload_form.audio_description": "Deskribatu entzumen galera duten pertsonentzat",
   "upload_form.description": "Deskribatu ikusmen arazoak dituztenentzat",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Editatu",
   "upload_form.thumbnail": "Aldatu koadro txikia",
   "upload_form.undo": "Ezabatu",
diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json
index 73a65ed78..17399a01f 100644
--- a/app/javascript/mastodon/locales/fa.json
+++ b/app/javascript/mastodon/locales/fa.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "بارگذاری پرونده در نظرسنجی‌ها مجاز نیست.",
   "upload_form.audio_description": "برای ناشنوایان توصیفش کنید",
   "upload_form.description": "برای کم‌بینایان توصیفش کنید",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "ویرایش",
   "upload_form.thumbnail": "تغییر بندانگشتی",
   "upload_form.undo": "حذف",
diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json
index b1ad55088..dfed86fa5 100644
--- a/app/javascript/mastodon/locales/fi.json
+++ b/app/javascript/mastodon/locales/fi.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Tiedon lataaminen ei ole sallittua kyselyissä.",
   "upload_form.audio_description": "Kuvaile kuulovammaisille",
   "upload_form.description": "Anna kuvaus näkörajoitteisia varten",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Kuvaile",
   "upload_form.thumbnail": "Vaihda pikkukuva",
   "upload_form.undo": "Peru",
diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json
index caef22ee9..2ebfbce58 100644
--- a/app/javascript/mastodon/locales/fr.json
+++ b/app/javascript/mastodon/locales/fr.json
@@ -279,7 +279,7 @@
   "lists.subheading": "Vos listes",
   "load_pending": "{count, plural, one {# nouvel élément} other {# nouveaux éléments}}",
   "loading_indicator.label": "Chargement…",
-  "media_gallery.toggle_visible": "Intervertir la visibilité",
+  "media_gallery.toggle_visible": "{number, plural, one {Cacher l’image} other {Cacher les images}}",
   "missing_indicator.label": "Non trouvé",
   "missing_indicator.sublabel": "Ressource introuvable",
   "mute_modal.duration": "Durée",
@@ -515,6 +515,7 @@
   "upload_error.poll": "L’envoi de fichiers n’est pas autorisé avec les sondages.",
   "upload_form.audio_description": "Décrire pour les personnes ayant des difficultés d’audition",
   "upload_form.description": "Décrire pour les malvoyant·e·s",
+  "upload_form.description_missing": "Description manquante",
   "upload_form.edit": "Décrire",
   "upload_form.thumbnail": "Changer la vignette",
   "upload_form.undo": "Supprimer",
diff --git a/app/javascript/mastodon/locales/ga.json b/app/javascript/mastodon/locales/ga.json
index 5bf1681a8..0f59bea92 100644
--- a/app/javascript/mastodon/locales/ga.json
+++ b/app/javascript/mastodon/locales/ga.json
@@ -1,54 +1,54 @@
 {
-  "account.account_note_header": "Your note for @{name}",
-  "account.add_or_remove_from_list": "Add or Remove from lists",
-  "account.badges.bot": "Bot",
-  "account.badges.group": "Group",
-  "account.block": "Block @{name}",
-  "account.block_domain": "Hide everything from {domain}",
-  "account.blocked": "Blocked",
-  "account.browse_more_on_origin_server": "Browse more on the original profile",
-  "account.cancel_follow_request": "Cancel follow request",
-  "account.direct": "Direct message @{name}",
-  "account.disable_notifications": "Stop notifying me when @{name} posts",
-  "account.domain_blocked": "Domain hidden",
-  "account.edit_profile": "Edit profile",
-  "account.enable_notifications": "Notify me when @{name} posts",
-  "account.endorse": "Feature on profile",
-  "account.follow": "Follow",
-  "account.followers": "Followers",
-  "account.followers.empty": "No one follows this user yet.",
-  "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}",
-  "account.following": "Following",
-  "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}",
-  "account.follows.empty": "This user doesn't follow anyone yet.",
-  "account.follows_you": "Follows you",
-  "account.hide_reblogs": "Hide boosts from @{name}",
-  "account.joined": "Joined {date}",
+  "account.account_note_header": "Nóta",
+  "account.add_or_remove_from_list": "Cuir Le nó Bain De na liostaí",
+  "account.badges.bot": "Bota",
+  "account.badges.group": "Grúpa",
+  "account.block": "Bac @{name}",
+  "account.block_domain": "Bac ainm fearainn {domain}",
+  "account.blocked": "Bactha",
+  "account.browse_more_on_origin_server": "Brabhsáil níos mó ar an phróifíl bhunaidh",
+  "account.cancel_follow_request": "Cealaigh iarratas leanúnaí",
+  "account.direct": "Cuir teachtaireacht dhíreach ar @{name}",
+  "account.disable_notifications": "Éirigh as ag cuir mé in eol nuair bpostálann @{name}",
+  "account.domain_blocked": "Ainm fearainn bactha",
+  "account.edit_profile": "Cuir an phróifíl in eagar",
+  "account.enable_notifications": "Cuir mé in eol nuair bpostálann @{name}",
+  "account.endorse": "Cuir ar an phróifíl mar ghné",
+  "account.follow": "Lean",
+  "account.followers": "Leantóirí",
+  "account.followers.empty": "Ní leanann éinne an t-úsáideoir seo fós.",
+  "account.followers_counter": "{count, plural, one {Leantóir amháin} other {{counter} Leantóir}}",
+  "account.following": "Ag leanúint",
+  "account.following_counter": "{count, plural, one {Ag leanúint cúntas amháin} other {Ag leanúint {counter} cúntas}}",
+  "account.follows.empty": "Ní leanann an t-úsáideoir seo duine ar bith fós.",
+  "account.follows_you": "Do do leanúint",
+  "account.hide_reblogs": "Folaigh athphostálacha ó @{name}",
+  "account.joined": "Ina bhall ó {date}",
   "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.media": "Media",
-  "account.mention": "Mention @{name}",
-  "account.moved_to": "{name} has moved to:",
-  "account.mute": "Mute @{name}",
-  "account.mute_notifications": "Mute notifications from @{name}",
-  "account.muted": "Muted",
-  "account.posts": "Toots",
-  "account.posts_with_replies": "Toots and replies",
-  "account.report": "Report @{name}",
-  "account.requested": "Awaiting approval",
-  "account.share": "Share @{name}'s profile",
-  "account.show_reblogs": "Show boosts from @{name}",
-  "account.statuses_counter": "{count, plural, one {{counter} Toot} other {{counter} Toots}}",
-  "account.unblock": "Unblock @{name}",
-  "account.unblock_domain": "Unhide {domain}",
-  "account.unblock_short": "Unblock",
-  "account.unendorse": "Don't feature on profile",
-  "account.unfollow": "Unfollow",
-  "account.unmute": "Unmute @{name}",
-  "account.unmute_notifications": "Unmute notifications from @{name}",
-  "account.unmute_short": "Unmute",
-  "account_note.placeholder": "No comment provided",
-  "admin.dashboard.daily_retention": "User retention rate by day after sign-up",
+  "account.locked_info": "Tá an socrú príobháideachais don cuntas seo curtha go 'faoi ghlas'. Déanann an t-úinéir léirmheas ar cén daoine atá ceadaithe an cuntas leanúint.",
+  "account.media": "Ábhair",
+  "account.mention": "Luaigh @{name}",
+  "account.moved_to": "Tá {name} bogtha go:",
+  "account.mute": "Ciúnaigh @{name}",
+  "account.mute_notifications": "Ciúnaigh fógraí ó @{name}",
+  "account.muted": "Ciúnaithe",
+  "account.posts": "Postálacha",
+  "account.posts_with_replies": "Postálacha agus freagraí",
+  "account.report": "Gearán @{name}",
+  "account.requested": "Ag fanacht le ceadú. Cliceáil chun an iarratas leanúnaí a chealú",
+  "account.share": "Roinn próifíl @{name}",
+  "account.show_reblogs": "Taispeáin athphostálacha ó @{name}",
+  "account.statuses_counter": "{count, plural, one {Postáil amháin} other {{counter} Postáil}}",
+  "account.unblock": "Bain bac de @{name}",
+  "account.unblock_domain": "Bain bac den ainm fearainn {domain}",
+  "account.unblock_short": "Bain bac de",
+  "account.unendorse": "Ná chuir ar an phróifíl mar ghné",
+  "account.unfollow": "Ná lean a thuilleadh",
+  "account.unmute": "Díchiúnaigh @{name}",
+  "account.unmute_notifications": "Díchiúnaigh fógraí ó @{name}",
+  "account.unmute_short": "Díchiúnaigh",
+  "account_note.placeholder": "Cliceáil chun nóta a chuir leis",
+  "admin.dashboard.daily_retention": "Ráta coinneála an úsáideora de réir an lae tar éis clárú",
   "admin.dashboard.monthly_retention": "User retention rate by month after sign-up",
   "admin.dashboard.retention.average": "Average",
   "admin.dashboard.retention.cohort": "Sign-up month",
@@ -72,7 +72,7 @@
   "column.community": "Local timeline",
   "column.direct": "Direct messages",
   "column.directory": "Browse profiles",
-  "column.domain_blocks": "Hidden domains",
+  "column.domain_blocks": "Blocked domains",
   "column.favourites": "Favourites",
   "column.follow_requests": "Follow requests",
   "column.home": "Home",
@@ -121,8 +121,8 @@
   "confirmations.delete.message": "Are you sure you want to delete this status?",
   "confirmations.delete_list.confirm": "Delete",
   "confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
-  "confirmations.discard_edit_media.confirm": "Discard",
-  "confirmations.discard_edit_media.message": "You have unsaved changes to the media description or preview, discard them anyway?",
+  "confirmations.discard_edit_media.confirm": "Faigh réidh de",
+  "confirmations.discard_edit_media.message": "Tá athruithe neamhshlánaithe don tuarascáil gné nó réamhamharc agat, faigh réidh dóibh ar aon nós?",
   "confirmations.domain_block.confirm": "Hide entire domain",
   "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. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.",
   "confirmations.logout.confirm": "Log out",
@@ -152,7 +152,7 @@
   "emoji_button.food": "Food & Drink",
   "emoji_button.label": "Insert emoji",
   "emoji_button.nature": "Nature",
-  "emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
+  "emoji_button.not_found": "No matching emojis found",
   "emoji_button.objects": "Objects",
   "emoji_button.people": "People",
   "emoji_button.recent": "Frequently used",
@@ -167,19 +167,19 @@
   "empty_column.bookmarked_statuses": "You don't have any bookmarked toots yet. When you bookmark one, it will show up here.",
   "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.",
-  "empty_column.domain_blocks": "There are no hidden domains yet.",
+  "empty_column.domain_blocks": "There are no blocked domains yet.",
   "empty_column.explore_statuses": "Nothing is trending right now. Check back later!",
   "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_recommendations": "Looks like no suggestions could be generated for you. You can try using search to look for people you might know or explore trending hashtags.",
   "empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.",
   "empty_column.hashtag": "There is nothing in this hashtag yet.",
-  "empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.",
+  "empty_column.home": "Your home timeline is empty! Follow more people to fill it up. {suggestions}",
   "empty_column.home.suggestions": "See some suggestions",
   "empty_column.list": "There is nothing in this list yet. When members of this list post new statuses, they will appear here.",
   "empty_column.lists": "You don't have any lists yet. When you create one, it will show up here.",
   "empty_column.mutes": "You haven't muted any users yet.",
-  "empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.",
+  "empty_column.notifications": "You don't have any notifications yet. When other people interact with you, you will see it here.",
   "empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other servers to fill it up",
   "error.unexpected_crash.explanation": "Due to a bug in our code or a browser compatibility issue, this page could not be displayed correctly.",
   "error.unexpected_crash.explanation_addons": "This page could not be displayed correctly. This error is likely caused by a browser add-on or automatic translation tools.",
@@ -267,8 +267,8 @@
   "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.edit": "Cuir an liosta in eagar",
+  "lists.edit.submit": "Athraigh teideal",
   "lists.new.create": "Add list",
   "lists.new.title_placeholder": "New list title",
   "lists.replies_policy.followed": "Any followed user",
@@ -279,7 +279,7 @@
   "lists.subheading": "Your lists",
   "load_pending": "{count, plural, one {# new item} other {# new items}}",
   "loading_indicator.label": "Loading...",
-  "media_gallery.toggle_visible": "Hide media",
+  "media_gallery.toggle_visible": "{number, plural, one {Hide image} other {Hide images}}",
   "missing_indicator.label": "Not found",
   "missing_indicator.sublabel": "This resource could not be found",
   "mute_modal.duration": "Duration",
@@ -293,12 +293,12 @@
   "navigation_bar.direct": "Direct messages",
   "navigation_bar.discover": "Discover",
   "navigation_bar.domain_blocks": "Hidden domains",
-  "navigation_bar.edit_profile": "Edit profile",
+  "navigation_bar.edit_profile": "Cuir an phróifíl in eagar",
   "navigation_bar.explore": "Explore",
   "navigation_bar.favourites": "Favourites",
   "navigation_bar.filters": "Muted words",
   "navigation_bar.follow_requests": "Follow requests",
-  "navigation_bar.follows_and_followers": "Follows and followers",
+  "navigation_bar.follows_and_followers": "Ag leanúint agus do do leanúint",
   "navigation_bar.info": "About this server",
   "navigation_bar.keyboard_shortcuts": "Hotkeys",
   "navigation_bar.lists": "Lists",
@@ -311,14 +311,14 @@
   "navigation_bar.security": "Security",
   "notification.admin.sign_up": "{name} signed up",
   "notification.favourite": "{name} favourited your status",
-  "notification.follow": "{name} followed you",
-  "notification.follow_request": "{name} has requested to follow you",
+  "notification.follow": "Lean {name} thú",
+  "notification.follow_request": "D'iarr {name} ort do chuntas a leanúint",
   "notification.mention": "{name} mentioned you",
   "notification.own_poll": "Your poll has ended",
   "notification.poll": "A poll you have voted in has ended",
   "notification.reblog": "{name} boosted your status",
   "notification.status": "{name} just posted",
-  "notification.update": "{name} edited a post",
+  "notification.update": "Chuir {name} postáil in eagar",
   "notifications.clear": "Clear notifications",
   "notifications.clear_confirmation": "Are you sure you want to permanently clear all your notifications?",
   "notifications.column_settings.admin.sign_up": "New sign-ups:",
@@ -327,8 +327,8 @@
   "notifications.column_settings.filter_bar.advanced": "Display all categories",
   "notifications.column_settings.filter_bar.category": "Quick filter bar",
   "notifications.column_settings.filter_bar.show_bar": "Show filter bar",
-  "notifications.column_settings.follow": "New followers:",
-  "notifications.column_settings.follow_request": "New follow requests:",
+  "notifications.column_settings.follow": "Leantóirí nua:",
+  "notifications.column_settings.follow_request": "Iarratais leanúnaí nua:",
   "notifications.column_settings.mention": "Mentions:",
   "notifications.column_settings.poll": "Poll results:",
   "notifications.column_settings.push": "Push notifications",
@@ -338,7 +338,7 @@
   "notifications.column_settings.status": "New toots:",
   "notifications.column_settings.unread_notifications.category": "Unread notifications",
   "notifications.column_settings.unread_notifications.highlight": "Highlight unread notifications",
-  "notifications.column_settings.update": "Edits:",
+  "notifications.column_settings.update": "Eagair:",
   "notifications.filter.all": "All",
   "notifications.filter.boosts": "Boosts",
   "notifications.filter.favourites": "Favourites",
@@ -366,13 +366,13 @@
   "poll_button.add_poll": "Add a poll",
   "poll_button.remove_poll": "Remove poll",
   "privacy.change": "Adjust status privacy",
-  "privacy.direct.long": "Post to mentioned users only",
+  "privacy.direct.long": "Visible for mentioned users only",
   "privacy.direct.short": "Direct",
-  "privacy.private.long": "Post to followers only",
-  "privacy.private.short": "Followers-only",
-  "privacy.public.long": "Post to public timelines",
+  "privacy.private.long": "Sofheicthe do Leantóirí amháin",
+  "privacy.private.short": "Leantóirí amháin",
+  "privacy.public.long": "Visible for all, shown in public timelines",
   "privacy.public.short": "Public",
-  "privacy.unlisted.long": "Do not show in public timelines",
+  "privacy.unlisted.long": "Visible for all, but not in public timelines",
   "privacy.unlisted.short": "Unlisted",
   "refresh": "Refresh",
   "regeneration_indicator.label": "Loading…",
@@ -405,20 +405,20 @@
   "report.mute": "Mute",
   "report.mute_explanation": "You will not see their posts. They can still follow you and see your posts and will not know that they are muted.",
   "report.next": "Next",
-  "report.placeholder": "Additional comments",
+  "report.placeholder": "Type or paste additional comments",
   "report.reasons.dislike": "I don't like it",
   "report.reasons.dislike_description": "It is not something you want to see",
   "report.reasons.other": "It's something else",
   "report.reasons.other_description": "The issue does not fit into other categories",
   "report.reasons.spam": "It's spam",
-  "report.reasons.spam_description": "Malicious links, fake engagement, or repetetive replies",
+  "report.reasons.spam_description": "Malicious links, fake engagement, or repetitive replies",
   "report.reasons.violation": "It violates server rules",
   "report.reasons.violation_description": "You are aware that it breaks specific rules",
   "report.rules.subtitle": "Select all that apply",
   "report.rules.title": "Which rules are being violated?",
   "report.statuses.subtitle": "Select all that apply",
   "report.statuses.title": "Are there any posts that back up this report?",
-  "report.submit": "Submit",
+  "report.submit": "Submit report",
   "report.target": "Report {target}",
   "report.thanks.take_action": "Here are your options for controlling what you see on Mastodon:",
   "report.thanks.take_action_actionable": "While we review this, you can take action against @{name}:",
@@ -450,14 +450,14 @@
   "status.delete": "Delete",
   "status.detailed_status": "Detailed conversation view",
   "status.direct": "Direct message @{name}",
-  "status.edit": "Edit",
-  "status.edited": "Edited {date}",
-  "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
+  "status.edit": "Cuir in eagar",
+  "status.edited": "Curtha in eagar in {date}",
+  "status.edited_x_times": "Curtha in eagar {count, plural, one {{count} uair amháin} two {{count} uair} few {{count} uair} many {{count} uair} other {{count} uair}}",
   "status.embed": "Embed",
   "status.favourite": "Favourite",
   "status.filtered": "Filtered",
   "status.history.created": "{name} created {date}",
-  "status.history.edited": "{name} edited {date}",
+  "status.history.edited": "Curtha in eagar ag {name} in {date}",
   "status.load_more": "Load more",
   "status.media_hidden": "Media hidden",
   "status.mention": "Mention @{name}",
@@ -500,7 +500,7 @@
   "time_remaining.moments": "Moments remaining",
   "time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left",
   "timeline_hint.remote_resource_not_displayed": "{resource} from other servers are not displayed.",
-  "timeline_hint.resources.followers": "Followers",
+  "timeline_hint.resources.followers": "Leantóirí",
   "timeline_hint.resources.follows": "Follows",
   "timeline_hint.resources.statuses": "Older toots",
   "trends.counter_by_accounts": "{count, plural, one {{counter} person} other {{counter} people}} talking",
@@ -510,12 +510,13 @@
   "units.short.million": "{count}M",
   "units.short.thousand": "{count}K",
   "upload_area.title": "Drag & drop to upload",
-  "upload_button.label": "Add media ({formats})",
+  "upload_button.label": "Add images, a video or an audio file",
   "upload_error.limit": "File upload limit exceeded.",
   "upload_error.poll": "File upload not allowed with polls.",
   "upload_form.audio_description": "Describe for people with hearing loss",
   "upload_form.description": "Describe for the visually impaired",
-  "upload_form.edit": "Edit",
+  "upload_form.description_missing": "No description added",
+  "upload_form.edit": "Cuir in eagar",
   "upload_form.thumbnail": "Change thumbnail",
   "upload_form.undo": "Delete",
   "upload_form.video_description": "Describe for people with hearing loss or visual impairment",
@@ -525,19 +526,19 @@
   "upload_modal.choose_image": "Choose image",
   "upload_modal.description_placeholder": "A quick brown fox jumps over the lazy dog",
   "upload_modal.detect_text": "Detect text from picture",
-  "upload_modal.edit_media": "Edit media",
+  "upload_modal.edit_media": "Cuir gné in eagar",
   "upload_modal.hint": "Click or drag the circle on the preview to choose the focal point which will always be in view on all thumbnails.",
   "upload_modal.preparing_ocr": "Preparing OCR…",
   "upload_modal.preview_label": "Preview ({ratio})",
-  "upload_progress.label": "Uploading...",
+  "upload_progress.label": "Uploading…",
   "video.close": "Close video",
   "video.download": "Download file",
   "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.mute": "Ciúnaigh fuaim",
+  "video.pause": "Cuir ar sos",
+  "video.play": "Cuir ar siúl",
+  "video.unmute": "Díchiúnaigh fuaim"
 }
diff --git a/app/javascript/mastodon/locales/gd.json b/app/javascript/mastodon/locales/gd.json
index 9ca41b2f6..becbbaf04 100644
--- a/app/javascript/mastodon/locales/gd.json
+++ b/app/javascript/mastodon/locales/gd.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Chan fhaod thu faidhle a luchdadh suas an cois cunntais-bheachd.",
   "upload_form.audio_description": "Mìnich e dhan fheadhainn le èisteachd bheag",
   "upload_form.description": "Mìnich e dhan fheadhainn le cion-lèirsinne",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Deasaich",
   "upload_form.thumbnail": "Atharraich an dealbhag",
   "upload_form.undo": "Sguab às",
diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json
index 56fd5ca7f..3d145e272 100644
--- a/app/javascript/mastodon/locales/gl.json
+++ b/app/javascript/mastodon/locales/gl.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Non se poden subir ficheiros nas enquisas.",
   "upload_form.audio_description": "Describir para persoas con problemas auditivos",
   "upload_form.description": "Describir para persoas con problemas visuais",
+  "upload_form.description_missing": "Sen descrición",
   "upload_form.edit": "Editar",
   "upload_form.thumbnail": "Cambiar a miniatura",
   "upload_form.undo": "Eliminar",
diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json
index db25a33fd..db192fa53 100644
--- a/app/javascript/mastodon/locales/he.json
+++ b/app/javascript/mastodon/locales/he.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "File upload not allowed with polls.",
   "upload_form.audio_description": "Describe for people with hearing loss",
   "upload_form.description": "תיאור לכבדי ראיה",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Edit",
   "upload_form.thumbnail": "Change thumbnail",
   "upload_form.undo": "ביטול",
diff --git a/app/javascript/mastodon/locales/hi.json b/app/javascript/mastodon/locales/hi.json
index 8a464f7ec..ecc6898c3 100644
--- a/app/javascript/mastodon/locales/hi.json
+++ b/app/javascript/mastodon/locales/hi.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "File upload not allowed with polls.",
   "upload_form.audio_description": "Describe for people with hearing loss",
   "upload_form.description": "Describe for the visually impaired",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "संशोधन करें",
   "upload_form.thumbnail": "Change thumbnail",
   "upload_form.undo": "मिटाए",
diff --git a/app/javascript/mastodon/locales/hr.json b/app/javascript/mastodon/locales/hr.json
index bbe62cf38..25bd26c8e 100644
--- a/app/javascript/mastodon/locales/hr.json
+++ b/app/javascript/mastodon/locales/hr.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Prijenos datoteka nije dopušten kod anketa.",
   "upload_form.audio_description": "Opišite za ljude sa slabim sluhom",
   "upload_form.description": "Opišite za ljude sa slabim vidom",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Uredi",
   "upload_form.thumbnail": "Promijeni pretpregled",
   "upload_form.undo": "Obriši",
diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json
index d121d6573..2f747f591 100644
--- a/app/javascript/mastodon/locales/hu.json
+++ b/app/javascript/mastodon/locales/hu.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Szavazásnál nem lehet fájlt feltölteni.",
   "upload_form.audio_description": "Írja le a hallássérültek számára",
   "upload_form.description": "Leírás látáskorlátozottak számára",
+  "upload_form.description_missing": "Nincs leírás megadva",
   "upload_form.edit": "Szerkesztés",
   "upload_form.thumbnail": "Előnézet megváltoztatása",
   "upload_form.undo": "Törlés",
diff --git a/app/javascript/mastodon/locales/hy.json b/app/javascript/mastodon/locales/hy.json
index 2b7cdf5ac..dc6234766 100644
--- a/app/javascript/mastodon/locales/hy.json
+++ b/app/javascript/mastodon/locales/hy.json
@@ -187,12 +187,12 @@
   "error.unexpected_crash.next_steps_addons": "Փորձիր անջատել յաւելուածները եւ թարմացնել էջը։ Եթե դա չօգնի, կարող ես օգտուել Մաստադոնից այլ դիտարկիչով կամ յաւելուածով։",
   "errors.unexpected_crash.copy_stacktrace": "Պատճենել սթաքթրեյսը սեղմատախտակին",
   "errors.unexpected_crash.report_issue": "Զեկուցել խնդրի մասին",
-  "explore.search_results": "Search results",
-  "explore.suggested_follows": "For you",
+  "explore.search_results": "Որոնման արդիւնքներ",
+  "explore.suggested_follows": "Ձեզ համար",
   "explore.title": "Explore",
-  "explore.trending_links": "News",
-  "explore.trending_statuses": "Posts",
-  "explore.trending_tags": "Hashtags",
+  "explore.trending_links": "Նորութիւններ",
+  "explore.trending_statuses": "Գրառումներ",
+  "explore.trending_tags": "Պիտակներ",
   "follow_recommendations.done": "Աւարտուած է",
   "follow_recommendations.heading": "Հետեւիր այն մարդկանց, որոնց գրառումները կը ցանկանաս տեսնել։ Ահա մի քանի առաջարկ։",
   "follow_recommendations.lead": "Քո հոսքում, ժամանակագրական դասաւորութեամբ կը տեսնես այն մարդկանց գրառումները, որոնց հետեւում ես։ Մի վախեցիր սխալուել, դու միշտ կարող ես հեշտութեամբ ապահետեւել մարդկանց։",
@@ -515,6 +515,7 @@
   "upload_error.poll": "Հարցումների հետ նիշք կցել հնարաւոր չէ։",
   "upload_form.audio_description": "Նկարագրիր ձայնագրութեան բովանդակութիւնը լսողական խնդիրներով անձանց համար",
   "upload_form.description": "Նկարագիր՝ տեսողական խնդիրներ ունեցողների համար",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Խմբագրել",
   "upload_form.thumbnail": "Փոխել պատկերակը",
   "upload_form.undo": "Յետարկել",
diff --git a/app/javascript/mastodon/locales/id.json b/app/javascript/mastodon/locales/id.json
index ee7810379..04366f1f8 100644
--- a/app/javascript/mastodon/locales/id.json
+++ b/app/javascript/mastodon/locales/id.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Unggah berkas tak diizinkan di japat ini.",
   "upload_form.audio_description": "Penjelasan untuk orang dengan gangguan pendengaran",
   "upload_form.description": "Deskripsikan untuk mereka yang tidak bisa melihat dengan jelas",
+  "upload_form.description_missing": "Tidak ada deskripsi yang ditambahkan",
   "upload_form.edit": "Sunting",
   "upload_form.thumbnail": "Ubah gambar kecil",
   "upload_form.undo": "Undo",
diff --git a/app/javascript/mastodon/locales/io.json b/app/javascript/mastodon/locales/io.json
index 77c6871a4..2ffee1eb2 100644
--- a/app/javascript/mastodon/locales/io.json
+++ b/app/javascript/mastodon/locales/io.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "File upload not allowed with polls.",
   "upload_form.audio_description": "Describe for people with hearing loss",
   "upload_form.description": "Describe for the visually impaired",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Edit",
   "upload_form.thumbnail": "Change thumbnail",
   "upload_form.undo": "Desfacar",
diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json
index bf1b892e6..e7cceedf7 100644
--- a/app/javascript/mastodon/locales/is.json
+++ b/app/javascript/mastodon/locales/is.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Innsending skráa er ekki leyfð í könnunum.",
   "upload_form.audio_description": "Lýstu þessu fyrir heyrnarskerta",
   "upload_form.description": "Lýstu þessu fyrir sjónskerta",
+  "upload_form.description_missing": "Engri lýsingu bætt við",
   "upload_form.edit": "Breyta",
   "upload_form.thumbnail": "Skipta um smámynd",
   "upload_form.undo": "Eyða",
diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json
index 1985450a5..f64ca1b5c 100644
--- a/app/javascript/mastodon/locales/it.json
+++ b/app/javascript/mastodon/locales/it.json
@@ -148,7 +148,7 @@
   "embed.preview": "Ecco come apparirà:",
   "emoji_button.activity": "Attività",
   "emoji_button.custom": "Personalizzato",
-  "emoji_button.flags": "Segnalazioni",
+  "emoji_button.flags": "Bandiere",
   "emoji_button.food": "Cibo & Bevande",
   "emoji_button.label": "Inserisci emoji",
   "emoji_button.nature": "Natura",
@@ -460,7 +460,7 @@
   "status.history.edited": "{name} ha modificato {date}",
   "status.load_more": "Mostra di più",
   "status.media_hidden": "Allegato nascosto",
-  "status.mention": "Nomina @{name}",
+  "status.mention": "Menziona @{name}",
   "status.more": "Altro",
   "status.mute": "Silenzia @{name}",
   "status.mute_conversation": "Silenzia conversazione",
@@ -483,7 +483,7 @@
   "status.show_less_all": "Mostra meno per tutti",
   "status.show_more": "Mostra di più",
   "status.show_more_all": "Mostra di più per tutti",
-  "status.show_thread": "Mostra thread",
+  "status.show_thread": "Mostra conversazione",
   "status.uncached_media_warning": "Non disponibile",
   "status.unmute_conversation": "Annulla silenzia conversazione",
   "status.unpin": "Non fissare in cima al profilo",
@@ -503,7 +503,7 @@
   "timeline_hint.resources.followers": "Follower",
   "timeline_hint.resources.follows": "Segue",
   "timeline_hint.resources.statuses": "Post meno recenti",
-  "trends.counter_by_accounts": "{count, plural, one {{counter} persona} other {{counter} persone}} ne parla·no",
+  "trends.counter_by_accounts": "{count, plural, one {{counter} persona} other {{counter} persone}} ne parlano",
   "trends.trending_now": "Di tendenza ora",
   "ui.beforeunload": "La bozza andrà persa se esci da Mastodon.",
   "units.short.billion": "{count}G",
@@ -515,6 +515,7 @@
   "upload_error.poll": "Caricamento file non consentito nei sondaggi.",
   "upload_form.audio_description": "Descrizione per persone con difetti uditivi",
   "upload_form.description": "Descrizione per utenti con disabilità visive",
+  "upload_form.description_missing": "Nessuna descrizione inserita",
   "upload_form.edit": "Modifica",
   "upload_form.thumbnail": "Cambia miniatura",
   "upload_form.undo": "Cancella",
diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json
index 8f6fe61d4..549e3c813 100644
--- a/app/javascript/mastodon/locales/ja.json
+++ b/app/javascript/mastodon/locales/ja.json
@@ -520,6 +520,7 @@
   "upload_error.poll": "アンケートではファイルをアップロードできません。",
   "upload_form.audio_description": "聴取が難しいユーザーへの説明",
   "upload_form.description": "閲覧が難しいユーザーへの説明",
+  "upload_form.description_missing": "説明を追加していません",
   "upload_form.edit": "説明",
   "upload_form.thumbnail": "サムネイルを変更",
   "upload_form.undo": "削除",
diff --git a/app/javascript/mastodon/locales/ka.json b/app/javascript/mastodon/locales/ka.json
index f6f3f1e10..a0a2b821d 100644
--- a/app/javascript/mastodon/locales/ka.json
+++ b/app/javascript/mastodon/locales/ka.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "File upload not allowed with polls.",
   "upload_form.audio_description": "Describe for people with hearing loss",
   "upload_form.description": "აღწერილობა ვიზუალურად უფასურისთვის",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Edit",
   "upload_form.thumbnail": "Change thumbnail",
   "upload_form.undo": "გაუქმება",
diff --git a/app/javascript/mastodon/locales/kab.json b/app/javascript/mastodon/locales/kab.json
index d6fcc2c7b..b6628332e 100644
--- a/app/javascript/mastodon/locales/kab.json
+++ b/app/javascript/mastodon/locales/kab.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Ur ittusireg ara usali n ufaylu s tefranin.",
   "upload_form.audio_description": "Glem-d i yemdanen i yesɛan ugur deg tmesliwt",
   "upload_form.description": "Glem-d i yemdaneni yesɛan ugur deg yiẓri",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Ẓreg",
   "upload_form.thumbnail": "Beddel tugna",
   "upload_form.undo": "Kkes",
diff --git a/app/javascript/mastodon/locales/kk.json b/app/javascript/mastodon/locales/kk.json
index 28156f956..f8185fe95 100644
--- a/app/javascript/mastodon/locales/kk.json
+++ b/app/javascript/mastodon/locales/kk.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Сауалнамамен бірге файл жүктеуге болмайды.",
   "upload_form.audio_description": "Есту қабілеті нашар адамдарға сипаттама беріңіз",
   "upload_form.description": "Көру қабілеті нашар адамдар үшін сипаттаңыз",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Түзету",
   "upload_form.thumbnail": "Суретті өзгерту",
   "upload_form.undo": "Өшіру",
diff --git a/app/javascript/mastodon/locales/kn.json b/app/javascript/mastodon/locales/kn.json
index 450944dca..74b3992c7 100644
--- a/app/javascript/mastodon/locales/kn.json
+++ b/app/javascript/mastodon/locales/kn.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "File upload not allowed with polls.",
   "upload_form.audio_description": "Describe for people with hearing loss",
   "upload_form.description": "Describe for the visually impaired",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Edit",
   "upload_form.thumbnail": "Change thumbnail",
   "upload_form.undo": "Delete",
diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json
index 454b3977a..b149c5879 100644
--- a/app/javascript/mastodon/locales/ko.json
+++ b/app/javascript/mastodon/locales/ko.json
@@ -131,7 +131,7 @@
   "confirmations.mute.explanation": "이 동작은 그의 게시물, 그를 멘션하는 게시물을 숨깁니다, 하지만 여전히 그가 당신의 게시물을 보고 팔로우 할 수 있습니다.",
   "confirmations.mute.message": "정말로 {name}를 뮤트하시겠습니까?",
   "confirmations.redraft.confirm": "삭제하고 다시 쓰기",
-  "confirmations.redraft.message": "정말로 이 게시물을 삭제하고 다시 쓰시겠습니까? 해당 포스트에 대한 부스트와 즐겨찾기를 잃게 되고 원본에 대한 답장은 연결 되지 않습니다.",
+  "confirmations.redraft.message": "정말로 이 게시물을 삭제하고 다시 쓰시겠습니까? 해당 게시물에 대한 부스트와 즐겨찾기를 잃게 되고 원본에 대한 답장은 연결 되지 않습니다.",
   "confirmations.reply.confirm": "답글",
   "confirmations.reply.message": "답글을 달기 위해 현재 작성 중인 메시지가 덮어 씌워집니다. 진행하시겠습니까?",
   "confirmations.unfollow.confirm": "팔로우 해제",
@@ -140,7 +140,7 @@
   "conversation.mark_as_read": "읽은 상태로 표시",
   "conversation.open": "대화 보기",
   "conversation.with": "{names} 님과",
-  "directory.federated": "알려진 별무리로부터",
+  "directory.federated": "알려진 연합우주로부터",
   "directory.local": "{domain}에서만",
   "directory.new_arrivals": "새로운 사람들",
   "directory.recently_active": "최근 활동",
@@ -365,7 +365,7 @@
   "poll.votes": "{votes} 표",
   "poll_button.add_poll": "투표 추가",
   "poll_button.remove_poll": "투표 삭제",
-  "privacy.change": "포스트의 프라이버시 설정을 변경",
+  "privacy.change": "게시물의 프라이버시 설정을 변경",
   "privacy.direct.long": "멘션한 사용자에게만 공개",
   "privacy.direct.short": "다이렉트",
   "privacy.private.long": "팔로워에게만 공개",
@@ -445,7 +445,7 @@
   "status.block": "@{name} 차단",
   "status.bookmark": "보관",
   "status.cancel_reblog_private": "부스트 취소",
-  "status.cannot_reblog": "이 포스트는 부스트 할 수 없습니다",
+  "status.cannot_reblog": "이 게시물은 부스트 할 수 없습니다",
   "status.copy": "게시물 링크 복사",
   "status.delete": "삭제",
   "status.detailed_status": "대화 자세히 보기",
@@ -515,6 +515,7 @@
   "upload_error.poll": "파일 업로드는 투표와 함께 첨부할 수 없습니다.",
   "upload_form.audio_description": "청각 장애인을 위한 설명",
   "upload_form.description": "시각장애인을 위한 설명",
+  "upload_form.description_missing": "설명이 추가되지 않음",
   "upload_form.edit": "편집",
   "upload_form.thumbnail": "썸네일 변경",
   "upload_form.undo": "삭제",
diff --git a/app/javascript/mastodon/locales/ku.json b/app/javascript/mastodon/locales/ku.json
index 2bf8fc520..642ec5fba 100644
--- a/app/javascript/mastodon/locales/ku.json
+++ b/app/javascript/mastodon/locales/ku.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Di rapirsîyan de mafê barkirina pelan nayê dayîn.",
   "upload_form.audio_description": "Ji bona kesên kêm dibihîsin re pênase bike",
   "upload_form.description": "Ji bona astengdarên dîtinê re vebêje",
+  "upload_form.description_missing": "Ti danasîn nehatiye tevlîkirin",
   "upload_form.edit": "Serrast bike",
   "upload_form.thumbnail": "Wêneyê biçûk biguherîne",
   "upload_form.undo": "Jê bibe",
diff --git a/app/javascript/mastodon/locales/kw.json b/app/javascript/mastodon/locales/kw.json
index ca6eed5c1..8ca7c68c1 100644
--- a/app/javascript/mastodon/locales/kw.json
+++ b/app/javascript/mastodon/locales/kw.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Nyns yw gesys ughkarga restrennow gans sondyansow.",
   "upload_form.audio_description": "Deskrifewgh rag tus vodharek",
   "upload_form.description": "Deskrifewgh rag tus dhallek",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Golegi",
   "upload_form.thumbnail": "Chanjya avenik",
   "upload_form.undo": "Dilea",
diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json
index bb432a8af..d54fc64f0 100644
--- a/app/javascript/mastodon/locales/lt.json
+++ b/app/javascript/mastodon/locales/lt.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "File upload not allowed with polls.",
   "upload_form.audio_description": "Describe for people with hearing loss",
   "upload_form.description": "Describe for the visually impaired",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Edit",
   "upload_form.thumbnail": "Change thumbnail",
   "upload_form.undo": "Delete",
diff --git a/app/javascript/mastodon/locales/lv.json b/app/javascript/mastodon/locales/lv.json
index f16df5423..559d06f98 100644
--- a/app/javascript/mastodon/locales/lv.json
+++ b/app/javascript/mastodon/locales/lv.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Datņu augšupielādes aptaujās nav atļautas.",
   "upload_form.audio_description": "Aprakstiet cilvēkiem ar dzirdes zudumu",
   "upload_form.description": "Aprakstiet vājredzīgajiem",
+  "upload_form.description_missing": "Apraksts nav pievienots",
   "upload_form.edit": "Rediģēt",
   "upload_form.thumbnail": "Nomainīt sīktēlu",
   "upload_form.undo": "Dzēst",
diff --git a/app/javascript/mastodon/locales/mk.json b/app/javascript/mastodon/locales/mk.json
index c6f097134..def8e718b 100644
--- a/app/javascript/mastodon/locales/mk.json
+++ b/app/javascript/mastodon/locales/mk.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "File upload not allowed with polls.",
   "upload_form.audio_description": "Describe for people with hearing loss",
   "upload_form.description": "Describe for the visually impaired",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Edit",
   "upload_form.thumbnail": "Change thumbnail",
   "upload_form.undo": "Delete",
diff --git a/app/javascript/mastodon/locales/ml.json b/app/javascript/mastodon/locales/ml.json
index 1a0f4ac38..adca25974 100644
--- a/app/javascript/mastodon/locales/ml.json
+++ b/app/javascript/mastodon/locales/ml.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "File upload not allowed with polls.",
   "upload_form.audio_description": "കേൾവിശക്തി ഇല്ലാത്തവർക്ക് വേണ്ടി വിവരണം നൽകൂ",
   "upload_form.description": "കാഴ്ചശക്തി ഇല്ലാത്തവർക്ക് വേണ്ടി വിവരണം നൽകൂ",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "തിരുത്തുക",
   "upload_form.thumbnail": "ലഘുചിത്രം മാറ്റുക",
   "upload_form.undo": "ഇല്ലാതാക്കുക",
diff --git a/app/javascript/mastodon/locales/mr.json b/app/javascript/mastodon/locales/mr.json
index a731ff87b..373b8b026 100644
--- a/app/javascript/mastodon/locales/mr.json
+++ b/app/javascript/mastodon/locales/mr.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "File upload not allowed with polls.",
   "upload_form.audio_description": "Describe for people with hearing loss",
   "upload_form.description": "Describe for the visually impaired",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Edit",
   "upload_form.thumbnail": "Change thumbnail",
   "upload_form.undo": "Delete",
diff --git a/app/javascript/mastodon/locales/ms.json b/app/javascript/mastodon/locales/ms.json
index 96d300492..f4cc1c7ba 100644
--- a/app/javascript/mastodon/locales/ms.json
+++ b/app/javascript/mastodon/locales/ms.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Tidak boleh memuat naik fail bersama undian.",
   "upload_form.audio_description": "Jelaskan untuk orang yang ada masalah pendengaran",
   "upload_form.description": "Jelaskan untuk orang yang ada masalah penglihatan",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Sunting",
   "upload_form.thumbnail": "Ubah gambar kecil",
   "upload_form.undo": "Padam",
diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json
index 604589b06..905c61e63 100644
--- a/app/javascript/mastodon/locales/nl.json
+++ b/app/javascript/mastodon/locales/nl.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Het uploaden van bestanden is in polls niet toegestaan.",
   "upload_form.audio_description": "Omschrijf dit voor mensen met een auditieve beperking",
   "upload_form.description": "Omschrijf dit voor mensen met een visuele beperking",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Omschrijf",
   "upload_form.thumbnail": "Miniatuurafbeelding wijzigen",
   "upload_form.undo": "Verwijderen",
diff --git a/app/javascript/mastodon/locales/nn.json b/app/javascript/mastodon/locales/nn.json
index 40a961c5e..491b24a40 100644
--- a/app/javascript/mastodon/locales/nn.json
+++ b/app/javascript/mastodon/locales/nn.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Filopplasting ikkje tillate med meiningsmålingar.",
   "upload_form.audio_description": "Grei ut for folk med nedsett høyrsel",
   "upload_form.description": "Skildr for synshemja",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Rediger",
   "upload_form.thumbnail": "Bytt miniatyrbilete",
   "upload_form.undo": "Slett",
diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json
index e4474f6d9..0a1286f7b 100644
--- a/app/javascript/mastodon/locales/no.json
+++ b/app/javascript/mastodon/locales/no.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Filopplasting inni avstemninger er ikke tillatt.",
   "upload_form.audio_description": "Beskriv det for folk med hørselstap",
   "upload_form.description": "Beskriv for synshemmede",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Rediger",
   "upload_form.thumbnail": "Endre miniatyrbilde",
   "upload_form.undo": "Angre",
diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json
index ff819e0fd..83cd3a632 100644
--- a/app/javascript/mastodon/locales/oc.json
+++ b/app/javascript/mastodon/locales/oc.json
@@ -106,7 +106,7 @@
   "compose_form.poll.switch_to_single": "Cambiar lo sondatge per permetre una sola causida",
   "compose_form.publish": "Tut",
   "compose_form.publish_loud": "{publish} !",
-  "compose_form.save_changes": "Save changes",
+  "compose_form.save_changes": "Salvar los cambiaments",
   "compose_form.sensitive.hide": "Marcar coma sensible",
   "compose_form.sensitive.marked": "Lo mèdia es marcat coma sensible",
   "compose_form.sensitive.unmarked": "Lo mèdia es pas marcat coma sensible",
@@ -187,9 +187,9 @@
   "error.unexpected_crash.next_steps_addons": "Ensajatz de los desactivar o actualizatz la pagina. Se aquò ajuda pas, podètz ensajar d’utilizar Mastodon via un autre navigador o una aplicacion nativa.",
   "errors.unexpected_crash.copy_stacktrace": "Copiar las traças al quichapapièrs",
   "errors.unexpected_crash.report_issue": "Senhalar un problèma",
-  "explore.search_results": "Search results",
+  "explore.search_results": "Resultats de recèrca",
   "explore.suggested_follows": "For you",
-  "explore.title": "Explore",
+  "explore.title": "Explorar",
   "explore.trending_links": "News",
   "explore.trending_statuses": "Posts",
   "explore.trending_tags": "Hashtags",
@@ -362,7 +362,7 @@
   "poll.total_votes": "{count, plural, one {# vòte} other {# vòtes}}",
   "poll.vote": "Votar",
   "poll.voted": "Avètz votat per aquesta responsa",
-  "poll.votes": "{votes, plural, one {# vote} other {# votes}}",
+  "poll.votes": "{votes, plural, one {# vòte} other {# vòtes}}",
   "poll_button.add_poll": "Ajustar un sondatge",
   "poll_button.remove_poll": "Levar lo sondatge",
   "privacy.change": "Ajustar la confidencialitat del messatge",
@@ -378,35 +378,35 @@
   "regeneration_indicator.label": "Cargament…",
   "regeneration_indicator.sublabel": "Sèm a preparar vòstre flux d’acuèlh !",
   "relative_time.days": "fa {number}d",
-  "relative_time.full.days": "{number, plural, one {# day} other {# days}} ago",
-  "relative_time.full.hours": "{number, plural, one {# hour} other {# hours}} ago",
-  "relative_time.full.just_now": "just now",
-  "relative_time.full.minutes": "{number, plural, one {# minute} other {# minutes}} ago",
-  "relative_time.full.seconds": "{number, plural, one {# second} other {# seconds}} ago",
+  "relative_time.full.days": "{number, plural, one {# jorn} other {# jorns}} ago",
+  "relative_time.full.hours": "fa {number, plural, one {# ora} other {# oras}}",
+  "relative_time.full.just_now": "ara",
+  "relative_time.full.minutes": "fa {number, plural, one {# minuta} other {# minutas}}",
+  "relative_time.full.seconds": "fa {number, plural, one {# segonda} other {# segondas}}",
   "relative_time.hours": "fa {number}h",
   "relative_time.just_now": "ara",
   "relative_time.minutes": "fa {number} min",
   "relative_time.seconds": "fa {number}s",
   "relative_time.today": "uèi",
   "reply_indicator.cancel": "Anullar",
-  "report.block": "Block",
+  "report.block": "Blocar",
   "report.block_explanation": "You will not see their posts. They will not be able to see your posts or follow you. They will be able to tell that they are blocked.",
   "report.categories.other": "Other",
   "report.categories.spam": "Spam",
   "report.categories.violation": "Content violates one or more server rules",
   "report.category.subtitle": "Choose the best match",
   "report.category.title": "Tell us what's going on with this {type}",
-  "report.category.title_account": "profile",
-  "report.category.title_status": "post",
-  "report.close": "Done",
+  "report.category.title_account": "perfil",
+  "report.category.title_status": "publicacion",
+  "report.close": "Acabat",
   "report.comment.title": "Is there anything else you think we should know?",
   "report.forward": "Far sègre a {target}",
   "report.forward_hint": "Lo compte ven d’un autre servidor. Volètz mandar una còpia anonima del rapòrt enlai tanben ?",
-  "report.mute": "Mute",
+  "report.mute": "Amudir",
   "report.mute_explanation": "You will not see their posts. They can still follow you and see your posts and will not know that they are muted.",
-  "report.next": "Next",
+  "report.next": "Seguent",
   "report.placeholder": "Comentaris addicionals",
-  "report.reasons.dislike": "I don't like it",
+  "report.reasons.dislike": "M’agrada pas",
   "report.reasons.dislike_description": "It is not something you want to see",
   "report.reasons.other": "It's something else",
   "report.reasons.other_description": "The issue does not fit into other categories",
@@ -450,7 +450,7 @@
   "status.delete": "Escafar",
   "status.detailed_status": "Vista detalhada de la convèrsa",
   "status.direct": "Messatge per @{name}",
-  "status.edit": "Edit",
+  "status.edit": "Modificar",
   "status.edited": "Edited {date}",
   "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
   "status.embed": "Embarcar",
@@ -515,6 +515,7 @@
   "upload_error.poll": "Lo mandadís de fichièr es pas autorizat pels sondatges.",
   "upload_form.audio_description": "Descriure per las personas amb pèrdas auditivas",
   "upload_form.description": "Descripcion pels mal vesents",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Modificar",
   "upload_form.thumbnail": "Cambiar la vinheta",
   "upload_form.undo": "Suprimir",
diff --git a/app/javascript/mastodon/locales/pa.json b/app/javascript/mastodon/locales/pa.json
index 088b5ff36..4373287dd 100644
--- a/app/javascript/mastodon/locales/pa.json
+++ b/app/javascript/mastodon/locales/pa.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "File upload not allowed with polls.",
   "upload_form.audio_description": "Describe for people with hearing loss",
   "upload_form.description": "Describe for the visually impaired",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Edit",
   "upload_form.thumbnail": "Change thumbnail",
   "upload_form.undo": "Delete",
diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json
index 7ae2c8e53..be086c830 100644
--- a/app/javascript/mastodon/locales/pl.json
+++ b/app/javascript/mastodon/locales/pl.json
@@ -48,8 +48,8 @@
   "account.unmute_notifications": "Cofnij wyciszenie powiadomień od @{name}",
   "account.unmute_short": "Włącz dźwięki",
   "account_note.placeholder": "Naciśnij aby dodać notatkę",
-  "admin.dashboard.daily_retention": "User retention rate by day after sign-up",
-  "admin.dashboard.monthly_retention": "User retention rate by month after sign-up",
+  "admin.dashboard.daily_retention": "Wskaźnik utrzymania użytkowników po dniach od rejestracji",
+  "admin.dashboard.monthly_retention": "Wskaźnik utrzymania użytkowników po miesiącach od rejestracji",
   "admin.dashboard.retention.average": "Średnia",
   "admin.dashboard.retention.cohort": "Miesiąc rejestracji",
   "admin.dashboard.retention.cohort_size": "Nowi użytkownicy",
@@ -98,7 +98,7 @@
   "community.column_settings.remote_only": "Tylko Zdalne",
   "compose_form.direct_message_warning": "Ten wpis będzie widoczny tylko dla wszystkich wspomnianych użytkowników.",
   "compose_form.direct_message_warning_learn_more": "Dowiedz się więcej",
-  "compose_form.hashtag_warning": "Ten wpis nie będzie widoczny pod podanymi hashtagami, ponieważ jest oznaczony jako niewidoczny. Tylko publiczne wpisy mogą zostać znalezione z użyciem hashtagów.",
+  "compose_form.hashtag_warning": "Ten wpis nie będzie widoczny pod podanymi hasztagami, ponieważ jest oznaczony jako niewidoczny. Tylko publiczne wpisy mogą zostać znalezione z użyciem hasztagów.",
   "compose_form.lock_disclaimer": "Twoje konto nie jest {locked}. Każdy, kto Cię śledzi, może wyświetlać Twoje wpisy przeznaczone tylko dla śledzących.",
   "compose_form.lock_disclaimer.lock": "zablokowane",
   "compose_form.placeholder": "Co Ci chodzi po głowie?",
@@ -172,12 +172,12 @@
   "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.",
   "empty_column.domain_blocks": "Brak ukrytych domen.",
-  "empty_column.explore_statuses": "Nothing is trending right now. Check back later!",
+  "empty_column.explore_statuses": "Nic nie jest w tej chwili popularne. Sprawdź później!",
   "empty_column.favourited_statuses": "Nie dodałeś(-aś) żadnego wpisu do ulubionych. Kiedy to zrobisz, pojawi się on tutaj.",
   "empty_column.favourites": "Nikt nie dodał tego wpisu do ulubionych. Gdy ktoś to zrobi, pojawi się tutaj.",
-  "empty_column.follow_recommendations": "Wygląda na to, że nie można wygenerować dla Ciebie żadnych sugestii. Możesz spróbować wyszukać osoby, które znasz, lub przeglądać popularne hashtagi.",
+  "empty_column.follow_recommendations": "Wygląda na to, że nie można wygenerować dla Ciebie żadnych sugestii. Możesz spróbować wyszukać osoby, które znasz, lub przeglądać popularne hasztagi.",
   "empty_column.follow_requests": "Nie masz żadnych próśb o możliwość śledzenia. Kiedy ktoś utworzy ją, pojawi się tutaj.",
-  "empty_column.hashtag": "Nie ma wpisów oznaczonych tym hashtagiem. Możesz napisać pierwszy(-a)!",
+  "empty_column.hashtag": "Nie ma wpisów oznaczonych tym hasztagiem. Możesz napisać pierwszy(-a).",
   "empty_column.home": "Nie śledzisz nikogo. Odwiedź globalną oś czasu lub użyj wyszukiwarki, aby znaleźć interesujące Cię profile.",
   "empty_column.home.suggestions": "Zobacz kilka sugestii",
   "empty_column.list": "Nie ma nic na tej liście. Kiedy członkowie listy dodadzą nowe wpisy, pojawia się one tutaj.",
@@ -191,12 +191,12 @@
   "error.unexpected_crash.next_steps_addons": "Spróbuj je wyłączyć lub odświeżyć stronę. Jeśli to nie pomoże, możesz wciąż korzystać z Mastodona w innej przeglądarce lub natywnej aplikacji.",
   "errors.unexpected_crash.copy_stacktrace": "Skopiuj ślad stosu do schowka",
   "errors.unexpected_crash.report_issue": "Zgłoś problem",
-  "explore.search_results": "Search results",
-  "explore.suggested_follows": "For you",
-  "explore.title": "Explore",
-  "explore.trending_links": "News",
-  "explore.trending_statuses": "Posts",
-  "explore.trending_tags": "Hashtags",
+  "explore.search_results": "Wyniki wyszukiwania",
+  "explore.suggested_follows": "Dla ciebie",
+  "explore.title": "Odkrywaj",
+  "explore.trending_links": "Aktualności",
+  "explore.trending_statuses": "Posty",
+  "explore.trending_tags": "Hasztagi",
   "follow_recommendations.done": "Gotowe",
   "follow_recommendations.heading": "Śledź ludzi, których wpisy chcesz czytać. Oto kilka propozycji.",
   "follow_recommendations.lead": "Wpisy osób, które śledzisz będą pojawiać się w porządku chronologicznym na stronie głównej. Nie bój się popełniać błędów, możesz bez problemu przestać śledzić każdego w każdej chwili!",
@@ -216,7 +216,7 @@
   "hashtag.column_header.tag_mode.any": "lub {additional}",
   "hashtag.column_header.tag_mode.none": "bez {additional}",
   "hashtag.column_settings.select.no_options_message": "Nie odnaleziono sugestii",
-  "hashtag.column_settings.select.placeholder": "Wprowadź hashtagi…",
+  "hashtag.column_settings.select.placeholder": "Wprowadź hasztagi…",
   "hashtag.column_settings.tag_mode.all": "Wszystkie",
   "hashtag.column_settings.tag_mode.any": "Dowolne",
   "hashtag.column_settings.tag_mode.none": "Żadne",
@@ -298,7 +298,7 @@
   "navigation_bar.discover": "Odkrywaj",
   "navigation_bar.domain_blocks": "Ukryte domeny",
   "navigation_bar.edit_profile": "Edytuj profil",
-  "navigation_bar.explore": "Explore",
+  "navigation_bar.explore": "Odkrywaj",
   "navigation_bar.favourites": "Ulubione",
   "navigation_bar.filters": "Wyciszone słowa",
   "navigation_bar.follow_requests": "Prośby o śledzenie",
@@ -314,7 +314,7 @@
   "navigation_bar.preferences": "Preferencje",
   "navigation_bar.public_timeline": "Globalna oś czasu",
   "navigation_bar.security": "Bezpieczeństwo",
-  "notification.admin.sign_up": "{name} signed up",
+  "notification.admin.sign_up": "Użytkownik {name} zarejestrował się",
   "notification.favourite": "{name} dodał(a) Twój wpis do ulubionych",
   "notification.follow": "{name} zaczął(-ęła) Cię śledzić",
   "notification.follow_request": "{name} poprosił(a) o możliwość śledzenia Cię",
@@ -326,7 +326,7 @@
   "notification.update": "{name} edytował post",
   "notifications.clear": "Wyczyść powiadomienia",
   "notifications.clear_confirmation": "Czy na pewno chcesz bezpowrotnie usunąć wszystkie powiadomienia?",
-  "notifications.column_settings.admin.sign_up": "New sign-ups:",
+  "notifications.column_settings.admin.sign_up": "Nowe rejestracje:",
   "notifications.column_settings.alert": "Powiadomienia na pulpicie",
   "notifications.column_settings.favourite": "Dodanie do ulubionych:",
   "notifications.column_settings.filter_bar.advanced": "Wyświetl wszystkie kategorie",
@@ -394,54 +394,54 @@
   "relative_time.seconds": "{number} s.",
   "relative_time.today": "dzisiaj",
   "reply_indicator.cancel": "Anuluj",
-  "report.block": "Block",
-  "report.block_explanation": "You will not see their posts. They will not be able to see your posts or follow you. They will be able to tell that they are blocked.",
+  "report.block": "Zablokuj",
+  "report.block_explanation": "Nie zobaczysz ich postów. Nie będą mogli zobaczyć Twoich postów ani cię śledzić. Będą mogli domyślić się, że są zablokowani.",
   "report.categories.other": "Inne",
   "report.categories.spam": "Spam",
   "report.categories.violation": "Zawartość narusza co najmniej jedną zasadę serwera",
-  "report.category.subtitle": "Choose the best match",
-  "report.category.title": "Tell us what's going on with this {type}",
-  "report.category.title_account": "profile",
+  "report.category.subtitle": "Wybierz najbardziej pasującą opcję",
+  "report.category.title": "Powiedz, co się dzieje z tym {type}",
+  "report.category.title_account": "profil",
   "report.category.title_status": "post",
-  "report.close": "Done",
-  "report.comment.title": "Is there anything else you think we should know?",
+  "report.close": "Gotowe",
+  "report.comment.title": "Czy jest jeszcze coś, co uważasz, że powinniśmy wiedzieć?",
   "report.forward": "Przekaż na {target}",
   "report.forward_hint": "To konto znajduje się na innej instancji. Czy chcesz wysłać anonimową kopię zgłoszenia rnież na nią?",
-  "report.mute": "Mute",
-  "report.mute_explanation": "You will not see their posts. They can still follow you and see your posts and will not know that they are muted.",
-  "report.next": "Next",
+  "report.mute": "Wycisz",
+  "report.mute_explanation": "Nie zobaczysz ich wpisów. Mimo to będą mogli wciąż śledzić cię i widzieć twoje wpisy, ale nie będą widzieli, że są wyciszeni.",
+  "report.next": "Dalej",
   "report.placeholder": "Dodatkowe komentarze",
-  "report.reasons.dislike": "I don't like it",
-  "report.reasons.dislike_description": "It is not something you want to see",
-  "report.reasons.other": "It's something else",
-  "report.reasons.other_description": "The issue does not fit into other categories",
-  "report.reasons.spam": "It's spam",
+  "report.reasons.dislike": "Nie podoba mi się to",
+  "report.reasons.dislike_description": "Nie jest to coś, co chciałoby się zobaczyć",
+  "report.reasons.other": "Coś innego",
+  "report.reasons.other_description": "Zgłoszenie nie pasuje do żadnej z pozostałych kategorii",
+  "report.reasons.spam": "To spam",
   "report.reasons.spam_description": "Niebezpieczne linki, fałszywe zaangażowanie lub powtarzające się odpowiedzi",
-  "report.reasons.violation": "It violates server rules",
-  "report.reasons.violation_description": "You are aware that it breaks specific rules",
-  "report.rules.subtitle": "Select all that apply",
-  "report.rules.title": "Which rules are being violated?",
-  "report.statuses.subtitle": "Select all that apply",
-  "report.statuses.title": "Are there any posts that back up this report?",
+  "report.reasons.violation": "Narusza to zasady serwera",
+  "report.reasons.violation_description": "Zdajesz sobie sprawę, że narusza to szczególne zasady",
+  "report.rules.subtitle": "Wybierz wszystkie pasujące",
+  "report.rules.title": "Które zasady zostały złamane?",
+  "report.statuses.subtitle": "Wybierz wszystkie pasujące",
+  "report.statuses.title": "Czy są jakieś wpisy, które obrazują opisany w zgłoszeniu problem?",
   "report.submit": "Wyślij",
   "report.target": "Zgłaszanie {target}",
-  "report.thanks.take_action": "Here are your options for controlling what you see on Mastodon:",
-  "report.thanks.take_action_actionable": "While we review this, you can take action against @{name}:",
-  "report.thanks.title": "Don't want to see this?",
-  "report.thanks.title_actionable": "Thanks for reporting, we'll look into this.",
-  "report.unfollow": "Unfollow @{name}",
-  "report.unfollow_explanation": "You are following this account. To not see their posts in your home feed anymore, unfollow them.",
+  "report.thanks.take_action": "Oto opcje, dzięki którym możesz kontrolować, co widzisz na Mastodon:",
+  "report.thanks.take_action_actionable": "W trakcie jak będziemy się przyglądać tej sprawie, możesz podjąć akcje przeciwko @{name}:",
+  "report.thanks.title": "Nie chcesz tego widzieć?",
+  "report.thanks.title_actionable": "Dziękujemy za zgłoszenie. Przyjrzymy się tej sprawie.",
+  "report.unfollow": "Przestań śledzić @{name}",
+  "report.unfollow_explanation": "Śledzisz to konto. Jeśli nie chcesz już widzieć postów z tego konta w swojej głównej osi czasu, przestań je śledzić.",
   "search.placeholder": "Szukaj",
   "search_popout.search_format": "Zaawansowane wyszukiwanie",
   "search_popout.tips.full_text": "Pozwala na wyszukiwanie wpisów które napisałeś(-aś), dodałeś(-aś) do ulubionych lub podbiłeś(-aś), w których o Tobie wspomniano, oraz pasujące nazwy użytkowników, pełne nazwy i hashtagi.",
   "search_popout.tips.hashtag": "hasztag",
   "search_popout.tips.status": "wpis",
-  "search_popout.tips.text": "Proste wyszukiwanie pasujących pseudonimów, nazw użytkowników i hashtagów",
+  "search_popout.tips.text": "Proste wyszukiwanie pasujących pseudonimów, nazw użytkowników i hasztagów",
   "search_popout.tips.user": "użytkownik",
   "search_results.accounts": "Ludzie",
-  "search_results.all": "All",
-  "search_results.hashtags": "Hashtagi",
-  "search_results.nothing_found": "Could not find anything for these search terms",
+  "search_results.all": "Wszystkie",
+  "search_results.hashtags": "Hasztagi",
+  "search_results.nothing_found": "Nie znaleziono innych wyników dla tego wyszukania",
   "search_results.statuses": "Wpisy",
   "search_results.statuses_fts_disabled": "Szukanie wpisów przy pomocy ich zawartości nie jest włączone na tym serwerze Mastodona.",
   "search_results.total": "{count, number} {count, plural, one {wynik} few {wyniki} many {wyników} more {wyników}}",
@@ -457,12 +457,12 @@
   "status.direct": "Wyślij wiadomość bezpośrednią do @{name}",
   "status.edit": "Edytuj",
   "status.edited": "Edytowano {date}",
-  "status.edited_x_times": "Edited {count, plural, one {{count} time} other {{count} times}}",
+  "status.edited_x_times": "Edytowano {count, plural, one {{count} raz} other {{count} razy}}",
   "status.embed": "Osadź",
   "status.favourite": "Dodaj do ulubionych",
   "status.filtered": "Filtrowany(-a)",
-  "status.history.created": "{name} created {date}",
-  "status.history.edited": "{name} edited {date}",
+  "status.history.created": "{name} utworzył(a) {date}",
+  "status.history.edited": "{name} edytował(a) {date}",
   "status.load_more": "Załaduj więcej",
   "status.media_hidden": "Zawartość multimedialna ukryta",
   "status.mention": "Wspomnij o @{name}",
@@ -520,6 +520,7 @@
   "upload_error.poll": "Dołączanie plików nie dozwolone z głosowaniami.",
   "upload_form.audio_description": "Opisz dla osób niesłyszących i niedosłyszących",
   "upload_form.description": "Wprowadź opis dla niewidomych i niedowidzących",
+  "upload_form.description_missing": "Nie dodano opisu",
   "upload_form.edit": "Opisz",
   "upload_form.thumbnail": "Zmień miniaturę",
   "upload_form.undo": "Usuń",
diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json
index f620e02b5..f33757945 100644
--- a/app/javascript/mastodon/locales/pt-BR.json
+++ b/app/javascript/mastodon/locales/pt-BR.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Mídias não podem ser anexadas em toots com enquetes.",
   "upload_form.audio_description": "Descrever para pessoas com deficiência auditiva",
   "upload_form.description": "Descreva para deficientes visuais",
+  "upload_form.description_missing": "Nenhuma descrição adicionada",
   "upload_form.edit": "Descreva",
   "upload_form.thumbnail": "Alterar miniatura",
   "upload_form.undo": "Excluir",
diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json
index 4e06401ec..01b9c4f65 100644
--- a/app/javascript/mastodon/locales/pt-PT.json
+++ b/app/javascript/mastodon/locales/pt-PT.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Carregamento de ficheiros não é permitido em votações.",
   "upload_form.audio_description": "Descreva para pessoas com diminuição da acuidade auditiva",
   "upload_form.description": "Descrição da imagem para pessoas com dificuldades visuais",
+  "upload_form.description_missing": "Nenhuma descrição adicionada",
   "upload_form.edit": "Editar",
   "upload_form.thumbnail": "Alterar miniatura",
   "upload_form.undo": "Eliminar",
diff --git a/app/javascript/mastodon/locales/ro.json b/app/javascript/mastodon/locales/ro.json
index bd91f19b9..49babba8b 100644
--- a/app/javascript/mastodon/locales/ro.json
+++ b/app/javascript/mastodon/locales/ro.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Încărcarea fișierului nu este permisă cu sondaje.",
   "upload_form.audio_description": "Descrie pentru persoanele cu deficiență a auzului",
   "upload_form.description": "Adaugă o descriere pentru persoanele cu deficiențe de vedere",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Modifică",
   "upload_form.thumbnail": "Schimbă miniatura",
   "upload_form.undo": "Șterge",
diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json
index 7267fc99d..8b17bde6c 100644
--- a/app/javascript/mastodon/locales/ru.json
+++ b/app/javascript/mastodon/locales/ru.json
@@ -436,7 +436,7 @@
   "search_results.accounts": "Люди",
   "search_results.all": "Все",
   "search_results.hashtags": "Хэштеги",
-  "search_results.nothing_found": "Could not find anything for these search terms",
+  "search_results.nothing_found": "Ничего не найдено по этому запросу",
   "search_results.statuses": "Посты",
   "search_results.statuses_fts_disabled": "Поиск постов по их содержанию не поддерживается данным сервером Mastodon.",
   "search_results.total": "{count, number} {count, plural, one {результат} few {результата} many {результатов} other {результатов}}",
@@ -515,6 +515,7 @@
   "upload_error.poll": "К опросам нельзя прикреплять файлы.",
   "upload_form.audio_description": "Опишите аудиофайл для людей с нарушением слуха",
   "upload_form.description": "Добавьте описание для людей с нарушениями зрения:",
+  "upload_form.description_missing": "Описание не добавлено",
   "upload_form.edit": "Опишите",
   "upload_form.thumbnail": "Изменить обложку",
   "upload_form.undo": "Отменить",
diff --git a/app/javascript/mastodon/locales/sa.json b/app/javascript/mastodon/locales/sa.json
index e1910d283..ef06ba0b1 100644
--- a/app/javascript/mastodon/locales/sa.json
+++ b/app/javascript/mastodon/locales/sa.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "File upload not allowed with polls.",
   "upload_form.audio_description": "Describe for people with hearing loss",
   "upload_form.description": "Describe for the visually impaired",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Edit",
   "upload_form.thumbnail": "Change thumbnail",
   "upload_form.undo": "Delete",
diff --git a/app/javascript/mastodon/locales/sc.json b/app/javascript/mastodon/locales/sc.json
index 1c29dfb79..1375f2fb6 100644
--- a/app/javascript/mastodon/locales/sc.json
+++ b/app/javascript/mastodon/locales/sc.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Non si permitit s'imbiu de archìvios in is sondàgios.",
   "upload_form.audio_description": "Descritzione pro persones cun pèrdida auditiva",
   "upload_form.description": "Descritzione pro persones cun problemas visuales",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Modìfica",
   "upload_form.thumbnail": "Càmbia sa miniadura",
   "upload_form.undo": "Cantzella",
diff --git a/app/javascript/mastodon/locales/si.json b/app/javascript/mastodon/locales/si.json
index a74105406..26c98ea35 100644
--- a/app/javascript/mastodon/locales/si.json
+++ b/app/javascript/mastodon/locales/si.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "File upload not allowed with polls.",
   "upload_form.audio_description": "Describe for people with hearing loss",
   "upload_form.description": "Describe for the visually impaired",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "සංස්කරණය",
   "upload_form.thumbnail": "Change thumbnail",
   "upload_form.undo": "Delete",
diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json
index 860e65413..9bdbf15c3 100644
--- a/app/javascript/mastodon/locales/sk.json
+++ b/app/javascript/mastodon/locales/sk.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Nahrávanie súborov pri anketách nieje možné.",
   "upload_form.audio_description": "Popíš, pre ľudí so stratou sluchu",
   "upload_form.description": "Opis pre slabo vidiacich",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Uprav",
   "upload_form.thumbnail": "Zmeniť miniatúru",
   "upload_form.undo": "Vymaž",
diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json
index 92a3ffcc9..f8bd9058b 100644
--- a/app/javascript/mastodon/locales/sl.json
+++ b/app/javascript/mastodon/locales/sl.json
@@ -46,10 +46,10 @@
   "account.unfollow": "Prenehaj slediti",
   "account.unmute": "Odtišaj @{name}",
   "account.unmute_notifications": "Vklopi obvestila od @{name}",
-  "account.unmute_short": "Unmute",
+  "account.unmute_short": "Odtišaj",
   "account_note.placeholder": "Click to add a note",
-  "admin.dashboard.daily_retention": "User retention rate by day after sign-up",
-  "admin.dashboard.monthly_retention": "User retention rate by month after sign-up",
+  "admin.dashboard.daily_retention": "Mera ohranjanja uporabnikov po dnevih od registracije",
+  "admin.dashboard.monthly_retention": "Mera ohranjanja uporabnikov po mesecih od registracije",
   "admin.dashboard.retention.average": "Povprečje",
   "admin.dashboard.retention.cohort": "Mesec prijave",
   "admin.dashboard.retention.cohort_size": "Novi uporabniki",
@@ -515,6 +515,7 @@
   "upload_error.poll": "Prenos datoteke z anketami ni dovoljen.",
   "upload_form.audio_description": "Opiši za osebe z okvaro sluha",
   "upload_form.description": "Opišite za slabovidne",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Uredi",
   "upload_form.thumbnail": "Spremeni sličico",
   "upload_form.undo": "Izbriši",
diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json
index ce3cdabd0..d0472db29 100644
--- a/app/javascript/mastodon/locales/sq.json
+++ b/app/javascript/mastodon/locales/sq.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Me pyetësorët s’lejohet ngarkim kartelash.",
   "upload_form.audio_description": "Përshkruajeni për persona me dëgjim të kufizuar",
   "upload_form.description": "Përshkruajeni për persona me probleme shikimi",
+  "upload_form.description_missing": "S’u shtua përshkrim",
   "upload_form.edit": "Përpunoni",
   "upload_form.thumbnail": "Ndryshoni miniaturën",
   "upload_form.undo": "Fshije",
diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json
index 332352cc1..7a0efa255 100644
--- a/app/javascript/mastodon/locales/sr-Latn.json
+++ b/app/javascript/mastodon/locales/sr-Latn.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "File upload not allowed with polls.",
   "upload_form.audio_description": "Describe for people with hearing loss",
   "upload_form.description": "Opiši za slabovide osobe",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Edit",
   "upload_form.thumbnail": "Change thumbnail",
   "upload_form.undo": "Opozovi",
diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json
index e7f1e54cc..ea6dbb5ab 100644
--- a/app/javascript/mastodon/locales/sr.json
+++ b/app/javascript/mastodon/locales/sr.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "File upload not allowed with polls.",
   "upload_form.audio_description": "Describe for people with hearing loss",
   "upload_form.description": "Опишите за особе са оштећеним видом",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Уреди",
   "upload_form.thumbnail": "Промени приказ слика",
   "upload_form.undo": "Обриши",
diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json
index 43c6decf8..d92379fcd 100644
--- a/app/javascript/mastodon/locales/sv.json
+++ b/app/javascript/mastodon/locales/sv.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "Filuppladdning tillåts inte med omröstningar.",
   "upload_form.audio_description": "Beskriv för personer med hörselnedsättning",
   "upload_form.description": "Beskriv för synskadade",
+  "upload_form.description_missing": "Beskrivning saknas",
   "upload_form.edit": "Beskriv",
   "upload_form.thumbnail": "Ändra miniatyr",
   "upload_form.undo": "Radera",
diff --git a/app/javascript/mastodon/locales/szl.json b/app/javascript/mastodon/locales/szl.json
index 088b5ff36..4373287dd 100644
--- a/app/javascript/mastodon/locales/szl.json
+++ b/app/javascript/mastodon/locales/szl.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "File upload not allowed with polls.",
   "upload_form.audio_description": "Describe for people with hearing loss",
   "upload_form.description": "Describe for the visually impaired",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Edit",
   "upload_form.thumbnail": "Change thumbnail",
   "upload_form.undo": "Delete",
diff --git a/app/javascript/mastodon/locales/ta.json b/app/javascript/mastodon/locales/ta.json
index 3c4bcb234..f79454e0b 100644
--- a/app/javascript/mastodon/locales/ta.json
+++ b/app/javascript/mastodon/locales/ta.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "கோப்பு பதிவேற்றம் அனுமதிக்கப்படவில்லை.",
   "upload_form.audio_description": "செவித்திறன் குறைபாடு உள்ளவர்களுக்காக விளக்குக‌",
   "upload_form.description": "பார்வையற்ற விவரிக்கவும்",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "தொகு",
   "upload_form.thumbnail": "சிறுபடத்தை மாற்ற",
   "upload_form.undo": "நீக்கு",
diff --git a/app/javascript/mastodon/locales/tai.json b/app/javascript/mastodon/locales/tai.json
index 2f8936a9c..888902b3f 100644
--- a/app/javascript/mastodon/locales/tai.json
+++ b/app/javascript/mastodon/locales/tai.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "File upload not allowed with polls.",
   "upload_form.audio_description": "Describe for people with hearing loss",
   "upload_form.description": "Describe for the visually impaired",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Edit",
   "upload_form.thumbnail": "Change thumbnail",
   "upload_form.undo": "Delete",
diff --git a/app/javascript/mastodon/locales/te.json b/app/javascript/mastodon/locales/te.json
index 05af59c6a..ce2fe0fda 100644
--- a/app/javascript/mastodon/locales/te.json
+++ b/app/javascript/mastodon/locales/te.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "File upload not allowed with polls.",
   "upload_form.audio_description": "Describe for people with hearing loss",
   "upload_form.description": "దృష్టి లోపమున్న వారి కోసం వివరించండి",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Edit",
   "upload_form.thumbnail": "Change thumbnail",
   "upload_form.undo": "తొలగించు",
diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json
index f8477e8fd..56cff648e 100644
--- a/app/javascript/mastodon/locales/th.json
+++ b/app/javascript/mastodon/locales/th.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "ไม่อนุญาตให้อัปโหลดไฟล์กับการลงคะแนน",
   "upload_form.audio_description": "อธิบายสำหรับผู้สูญเสียการได้ยิน",
   "upload_form.description": "อธิบายสำหรับผู้บกพร่องทางการมองเห็น",
+  "upload_form.description_missing": "ไม่มีการเพิ่มคำอธิบาย",
   "upload_form.edit": "แก้ไข",
   "upload_form.thumbnail": "เปลี่ยนภาพขนาดย่อ",
   "upload_form.undo": "ลบ",
diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json
index 96d6f83c3..01de2c8c8 100644
--- a/app/javascript/mastodon/locales/tr.json
+++ b/app/javascript/mastodon/locales/tr.json
@@ -9,11 +9,11 @@
   "account.browse_more_on_origin_server": "Orijinal profilde daha fazlasına göz atın",
   "account.cancel_follow_request": "Takip isteğini iptal et",
   "account.direct": "@{name} adlı kişiye mesaj gönder",
-  "account.disable_notifications": "@{name} gönderi atınca bana bildirmeyi durdur",
+  "account.disable_notifications": "@{name} kişisinin gönderi bildirimlerini kapat",
   "account.domain_blocked": "Alan adı engellendi",
   "account.edit_profile": "Profili düzenle",
-  "account.enable_notifications": "@{name} gönderi atınca bana bildir",
-  "account.endorse": "Profildeki özellik",
+  "account.enable_notifications": "@{name} kişisinin gönderi bildirimlerini aç",
+  "account.endorse": "Profilimde öne çıkar",
   "account.follow": "Takip et",
   "account.followers": "Takipçi",
   "account.followers.empty": "Henüz kimse bu kullanıcıyı takip etmiyor.",
@@ -42,7 +42,7 @@
   "account.unblock": "@{name} adlı kişinin engelini kaldır",
   "account.unblock_domain": "{domain} alan adının engelini kaldır",
   "account.unblock_short": "Engeli kaldır",
-  "account.unendorse": "Profilde gösterme",
+  "account.unendorse": "Profilimde öne çıkarma",
   "account.unfollow": "Takibi bırak",
   "account.unmute": "@{name} adlı kişinin sesini aç",
   "account.unmute_notifications": "@{name} adlı kişinin bildirimlerini aç",
@@ -507,14 +507,15 @@
   "trends.trending_now": "Şu an gündemde",
   "ui.beforeunload": "Mastodon'u terk ederseniz taslağınız kaybolacak.",
   "units.short.billion": "{count}Mr",
-  "units.short.million": "{count}Mn",
-  "units.short.thousand": "{count}Mn",
+  "units.short.million": "{count}M",
+  "units.short.thousand": "{count}Bin",
   "upload_area.title": "Karşıya yükleme için sürükle bırak yapınız",
   "upload_button.label": "Resim, video veya ses dosyası ekleyin",
   "upload_error.limit": "Dosya yükleme sınırı aşıldı.",
   "upload_error.poll": "Anketlerde dosya yüklemesine izin verilmez.",
   "upload_form.audio_description": "İşitme kaybı olan kişiler için tarif edin",
   "upload_form.description": "Görme engelliler için açıklama",
+  "upload_form.description_missing": "Açıklama eklenmedi",
   "upload_form.edit": "Düzenle",
   "upload_form.thumbnail": "Küçük resmi değiştir",
   "upload_form.undo": "Sil",
diff --git a/app/javascript/mastodon/locales/tt.json b/app/javascript/mastodon/locales/tt.json
index 06936f110..e44106844 100644
--- a/app/javascript/mastodon/locales/tt.json
+++ b/app/javascript/mastodon/locales/tt.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "File upload not allowed with polls.",
   "upload_form.audio_description": "Describe for people with hearing loss",
   "upload_form.description": "Describe for the visually impaired",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Үзгәртү",
   "upload_form.thumbnail": "Change thumbnail",
   "upload_form.undo": "Бетерү",
diff --git a/app/javascript/mastodon/locales/ug.json b/app/javascript/mastodon/locales/ug.json
index 088b5ff36..4373287dd 100644
--- a/app/javascript/mastodon/locales/ug.json
+++ b/app/javascript/mastodon/locales/ug.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "File upload not allowed with polls.",
   "upload_form.audio_description": "Describe for people with hearing loss",
   "upload_form.description": "Describe for the visually impaired",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Edit",
   "upload_form.thumbnail": "Change thumbnail",
   "upload_form.undo": "Delete",
diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json
index e2e1386e6..3aeb40209 100644
--- a/app/javascript/mastodon/locales/uk.json
+++ b/app/javascript/mastodon/locales/uk.json
@@ -29,9 +29,9 @@
   "account.media": "Медіа",
   "account.mention": "Згадати @{name}",
   "account.moved_to": "{name} переїхав на:",
-  "account.mute": "Заглушити @{name}",
+  "account.mute": "Нехтувати @{name}",
   "account.mute_notifications": "Не показувати сповіщення від @{name}",
-  "account.muted": "Заглушений",
+  "account.muted": "Нехтується",
   "account.posts": "Дмухи",
   "account.posts_with_replies": "Дмухи й відповіді",
   "account.report": "Поскаржитися на @{name}",
@@ -44,9 +44,9 @@
   "account.unblock_short": "Розблокувати",
   "account.unendorse": "Не публікувати у профілі",
   "account.unfollow": "Відписатися",
-  "account.unmute": "Зняти глушення з @{name}",
+  "account.unmute": "Не нехтувати @{name}",
   "account.unmute_notifications": "Показувати сповіщення від @{name}",
-  "account.unmute_short": "Unmute",
+  "account.unmute_short": "Не нехтувати",
   "account_note.placeholder": "Коментарі відсутні",
   "admin.dashboard.daily_retention": "User retention rate by day after sign-up",
   "admin.dashboard.monthly_retention": "User retention rate by month after sign-up",
@@ -77,7 +77,7 @@
   "column.follow_requests": "Запити на підписку",
   "column.home": "Головна",
   "column.lists": "Списки",
-  "column.mutes": "Заглушені користувачі",
+  "column.mutes": "Нехтувані користувачі",
   "column.notifications": "Сповіщення",
   "column.pins": "Закріплені дмухи",
   "column.public": "Глобальна стрічка",
@@ -124,12 +124,12 @@
   "confirmations.discard_edit_media.confirm": "Відкинути",
   "confirmations.discard_edit_media.message": "У вас є незбережені зміни в описі медіа або попереднього перегляду, все одно відкинути їх?",
   "confirmations.domain_block.confirm": "Сховати весь домен",
-  "confirmations.domain_block.message": "Ви точно, точно впевнені, що хочете заблокувати весь домен {domain}? У більшості випадків для нормальної роботи краще заблокувати/заглушити лише деяких користувачів. Ви не зможете бачити контент з цього домену у будь-яких стрічках або ваших сповіщеннях. Ваші підписники з цього домену будуть відписані від вас.",
+  "confirmations.domain_block.message": "Ви точно, точно впевнені, що хочете заблокувати весь домен {domain}? У більшості випадків для нормальної роботи краще заблокувати або нехтувати лише деяких користувачів. Ви не зможете бачити контент з цього домену у будь-яких стрічках або ваших сповіщеннях. Ваші підписники з цього домену будуть відписані від вас.",
   "confirmations.logout.confirm": "Вийти",
   "confirmations.logout.message": "Ви впевнені, що хочете вийти?",
-  "confirmations.mute.confirm": "Заглушити",
-  "confirmations.mute.explanation": "Це приховає пости від них і пости зі згадками про них, проте вони все одно матимуть змогу бачити ваші пости і підписуватися на вас.",
-  "confirmations.mute.message": "Ви впевнені, що хочете заглушити {name}?",
+  "confirmations.mute.confirm": "Нехтуавти",
+  "confirmations.mute.explanation": "Це сховає дописи від них і дописи зі згадками про них, проте вони все одно матимуть змогу бачити ваші дописи й підписуватися на вас.",
+  "confirmations.mute.message": "Ви впевнені, що хочете нехтувати {name}?",
   "confirmations.redraft.confirm": "Видалити та перестворити",
   "confirmations.redraft.message": "Ви впевнені, що хочете видалити допис і перестворити його? Ви втратите всі відповіді, передмухи та вподобайки допису.",
   "confirmations.reply.confirm": "Відповісти",
@@ -178,7 +178,7 @@
   "empty_column.home.suggestions": "Переглянути пропозиції",
   "empty_column.list": "Немає нічого в цьому списку. Коли його учасники дмухнуть нові статуси, вони з'являться тут.",
   "empty_column.lists": "У вас ще немає списків. Коли ви їх створите, вони з'являться тут.",
-  "empty_column.mutes": "Ви ще не заглушили жодного користувача.",
+  "empty_column.mutes": "Ви ще не нехтуєте жодного користувача.",
   "empty_column.notifications": "У вас ще немає сповіщень. Переписуйтесь з іншими користувачами, щоб почати розмову.",
   "empty_column.public": "Тут поки нічого немає! Опублікуйте щось, або вручну підпишіться на користувачів інших інстанцій, щоб заповнити стрічку",
   "error.unexpected_crash.explanation": "Ця сторінка не може бути коректно відображена через баґ у нашому коді або через проблему сумісності браузера.",
@@ -243,7 +243,7 @@
   "keyboard_shortcuts.legend": "показати підказку",
   "keyboard_shortcuts.local": "відкрити локальну стрічку",
   "keyboard_shortcuts.mention": "згадати автора",
-  "keyboard_shortcuts.muted": "відкрити список заглушених користувачів",
+  "keyboard_shortcuts.muted": "Відкрити список нехтуваних користувачів",
   "keyboard_shortcuts.my_profile": "відкрити ваш профіль",
   "keyboard_shortcuts.notifications": "відкрити колонку сповіщень",
   "keyboard_shortcuts.open_media": "відкрити медіа",
@@ -283,7 +283,7 @@
   "missing_indicator.label": "Не знайдено",
   "missing_indicator.sublabel": "Ресурс не знайдений",
   "mute_modal.duration": "Тривалість",
-  "mute_modal.hide_notifications": "Приховати сповіщення від користувача?",
+  "mute_modal.hide_notifications": "Сховати сповіщення від користувача?",
   "mute_modal.indefinite": "Не визначено",
   "navigation_bar.apps": "Мобільні додатки",
   "navigation_bar.blocks": "Заблоковані користувачі",
@@ -294,7 +294,7 @@
   "navigation_bar.discover": "Знайти",
   "navigation_bar.domain_blocks": "Приховані домени",
   "navigation_bar.edit_profile": "Редагувати профіль",
-  "navigation_bar.explore": "Explore",
+  "navigation_bar.explore": "Огляд",
   "navigation_bar.favourites": "Вподобане",
   "navigation_bar.filters": "Приховані слова",
   "navigation_bar.follow_requests": "Запити на підписку",
@@ -303,7 +303,7 @@
   "navigation_bar.keyboard_shortcuts": "Гарячі клавіші",
   "navigation_bar.lists": "Списки",
   "navigation_bar.logout": "Вийти",
-  "navigation_bar.mutes": "Заглушені користувачі",
+  "navigation_bar.mutes": "Нехтувані користувачі",
   "navigation_bar.personal": "Особисте",
   "navigation_bar.pins": "Закріплені дмухи",
   "navigation_bar.preferences": "Налаштування",
@@ -402,8 +402,8 @@
   "report.comment.title": "Is there anything else you think we should know?",
   "report.forward": "Надіслати до {target}",
   "report.forward_hint": "Це акаунт з іншого серверу. Відправити анонімізовану копію скарги і туди?",
-  "report.mute": "Заглушити",
-  "report.mute_explanation": "You will not see their posts. They can still follow you and see your posts and will not know that they are muted.",
+  "report.mute": "Нехтувати",
+  "report.mute_explanation": "Ви не побачите їхніх дописів. Вони все ще можуть стежити за вами, бачити ваші дописи та не знатимуть про нехтування.",
   "report.next": "Далі",
   "report.placeholder": "Додаткові коментарі",
   "report.reasons.dislike": "Мені це не подобається",
@@ -412,9 +412,9 @@
   "report.reasons.other_description": "The issue does not fit into other categories",
   "report.reasons.spam": "Це спам",
   "report.reasons.spam_description": "Malicious links, fake engagement, or repetitive replies",
-  "report.reasons.violation": "It violates server rules",
-  "report.reasons.violation_description": "You are aware that it breaks specific rules",
-  "report.rules.subtitle": "Select all that apply",
+  "report.reasons.violation": "Порушує правила сервера",
+  "report.reasons.violation_description": "Ви впевнені, що це порушує певні правила",
+  "report.rules.subtitle": "Виберіть усі варіанти, що підходять",
   "report.rules.title": "Які правила порушено?",
   "report.statuses.subtitle": "Виберіть усі варіанти, що підходять",
   "report.statuses.title": "Are there any posts that back up this report?",
@@ -422,8 +422,8 @@
   "report.target": "Скаржимося на {target}",
   "report.thanks.take_action": "Here are your options for controlling what you see on Mastodon:",
   "report.thanks.take_action_actionable": "While we review this, you can take action against @{name}:",
-  "report.thanks.title": "Don't want to see this?",
-  "report.thanks.title_actionable": "Thanks for reporting, we'll look into this.",
+  "report.thanks.title": "Не хочете це бачити?",
+  "report.thanks.title_actionable": "Дякуємо за скаргу, ми розглянемо її.",
   "report.unfollow": "Відписатися від @{name}",
   "report.unfollow_explanation": "You are following this account. To not see their posts in your home feed anymore, unfollow them.",
   "search.placeholder": "Пошук",
@@ -436,7 +436,7 @@
   "search_results.accounts": "Люди",
   "search_results.all": "Усе",
   "search_results.hashtags": "Хештеґи",
-  "search_results.nothing_found": "Could not find anything for these search terms",
+  "search_results.nothing_found": "Нічого не вдалося знайти за цими пошуковими термінами",
   "search_results.statuses": "Дмухів",
   "search_results.statuses_fts_disabled": "Пошук дмухів за вмістом недоступний на цьому сервері Mastodon.",
   "search_results.total": "{count, number} {count, plural, one {результат} few {результати} many {результатів} other {результатів}}",
@@ -462,8 +462,8 @@
   "status.media_hidden": "Медіа приховано",
   "status.mention": "Згадати @{name}",
   "status.more": "Більше",
-  "status.mute": "Заглушити @{name}",
-  "status.mute_conversation": "Заглушити діалог",
+  "status.mute": "Нехтувати @{name}",
+  "status.mute_conversation": "Нехтувати діалог",
   "status.open": "Розгорнути допис",
   "status.pin": "Закріпити у профілі",
   "status.pinned": "Закріплений дмух",
@@ -485,7 +485,7 @@
   "status.show_more_all": "Показувати більше для всіх",
   "status.show_thread": "Показати ланцюжок",
   "status.uncached_media_warning": "Недоступно",
-  "status.unmute_conversation": "Зняти глушення з діалогу",
+  "status.unmute_conversation": "Не нехтувати діалог",
   "status.unpin": "Відкріпити від профілю",
   "suggestions.dismiss": "Відхилити пропозицію",
   "suggestions.header": "Вас може зацікавити…",
@@ -515,6 +515,7 @@
   "upload_error.poll": "Не можна завантажувати файли до опитувань.",
   "upload_form.audio_description": "Опишіть для людей із вадами слуху",
   "upload_form.description": "Опишіть для людей з вадами зору",
+  "upload_form.description_missing": "Опису не додано",
   "upload_form.edit": "Змінити",
   "upload_form.thumbnail": "Змінити мініатюру",
   "upload_form.undo": "Видалити",
diff --git a/app/javascript/mastodon/locales/ur.json b/app/javascript/mastodon/locales/ur.json
index e5aad2355..47e06c3b2 100644
--- a/app/javascript/mastodon/locales/ur.json
+++ b/app/javascript/mastodon/locales/ur.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "File upload not allowed with polls.",
   "upload_form.audio_description": "Describe for people with hearing loss",
   "upload_form.description": "Describe for the visually impaired",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "Edit",
   "upload_form.thumbnail": "Change thumbnail",
   "upload_form.undo": "Delete",
diff --git a/app/javascript/mastodon/locales/vi.json b/app/javascript/mastodon/locales/vi.json
index d47033881..9ea6a1e44 100644
--- a/app/javascript/mastodon/locales/vi.json
+++ b/app/javascript/mastodon/locales/vi.json
@@ -1,7 +1,7 @@
 {
   "account.account_note_header": "Ghi chú",
   "account.add_or_remove_from_list": "Thêm hoặc Xóa khỏi danh sách",
-  "account.badges.bot": "Bot",
+  "account.badges.bot": "người máy",
   "account.badges.group": "Nhóm",
   "account.block": "Chặn @{name}",
   "account.block_domain": "Ẩn mọi thứ từ {domain}",
@@ -9,10 +9,10 @@
   "account.browse_more_on_origin_server": "Truy cập trang của người này",
   "account.cancel_follow_request": "Hủy yêu cầu theo dõi",
   "account.direct": "Nhắn riêng @{name}",
-  "account.disable_notifications": "Không thông báo khi @{name} đăng tút",
+  "account.disable_notifications": "Tắt thông báo khi @{name} đăng tút",
   "account.domain_blocked": "Người đã chặn",
-  "account.edit_profile": "Chỉnh sửa trang cá nhân",
-  "account.enable_notifications": "Thông báo khi @{name} đăng tút",
+  "account.edit_profile": "Sửa hồ sơ",
+  "account.enable_notifications": "Nhận thông báo khi @{name} đăng tút",
   "account.endorse": "Tôn vinh người này",
   "account.follow": "Theo dõi",
   "account.followers": "Người theo dõi",
@@ -22,7 +22,7 @@
   "account.following_counter": "{count, plural, one {{counter} Theo dõi} other {{counter} Theo dõi}}",
   "account.follows.empty": "Người này chưa theo dõi ai.",
   "account.follows_you": "Đang theo dõi bạn",
-  "account.hide_reblogs": "Ẩn tút do @{name} đăng lại",
+  "account.hide_reblogs": "Ẩn tút @{name} đăng lại",
   "account.joined": "Đã tham gia {date}",
   "account.link_verified_on": "Liên kết này đã được xác thực vào {date}",
   "account.locked_info": "Đây là tài khoản riêng tư. Họ sẽ tự mình xét duyệt các yêu cầu theo dõi.",
@@ -104,7 +104,7 @@
   "compose_form.poll.remove_option": "Xóa lựa chọn này",
   "compose_form.poll.switch_to_multiple": "Có thể chọn nhiều lựa chọn",
   "compose_form.poll.switch_to_single": "Chỉ cho phép chọn duy nhất một lựa chọn",
-  "compose_form.publish": "Đăng tút",
+  "compose_form.publish": "Đăng",
   "compose_form.publish_loud": "{publish}!",
   "compose_form.save_changes": "Lưu thay đổi",
   "compose_form.sensitive.hide": "{count, plural, other {Đánh dấu nội dung nhạy cảm}}",
@@ -112,7 +112,7 @@
   "compose_form.sensitive.unmarked": "{count, plural, other {Nội dung này bình thường}}",
   "compose_form.spoiler.marked": "Hủy nội dung ẩn",
   "compose_form.spoiler.unmarked": "Tạo nội dung ẩn",
-  "compose_form.spoiler_placeholder": "Viết nội dung ẩn của bạn ở đây",
+  "compose_form.spoiler_placeholder": "Lời dẫn cho nội dung ẩn",
   "confirmation_modal.cancel": "Hủy bỏ",
   "confirmations.block.block_and_report": "Chặn & Báo cáo",
   "confirmations.block.confirm": "Chặn",
@@ -227,7 +227,7 @@
   "intervals.full.minutes": "{number, plural, other {# phút}}",
   "keyboard_shortcuts.back": "trở lại",
   "keyboard_shortcuts.blocked": "mở danh sách người đã chặn",
-  "keyboard_shortcuts.boost": "Đăng lại",
+  "keyboard_shortcuts.boost": "đăng lại",
   "keyboard_shortcuts.column": "mở các mục",
   "keyboard_shortcuts.compose": "mở khung soạn tút",
   "keyboard_shortcuts.description": "Mô tả",
@@ -244,11 +244,11 @@
   "keyboard_shortcuts.local": "mở máy chủ của bạn",
   "keyboard_shortcuts.mention": "nhắc đến ai đó",
   "keyboard_shortcuts.muted": "mở danh sách người đã ẩn",
-  "keyboard_shortcuts.my_profile": "mở trang cá nhân của bạn",
+  "keyboard_shortcuts.my_profile": "mở hồ sơ của bạn",
   "keyboard_shortcuts.notifications": "mở mục thông báo",
   "keyboard_shortcuts.open_media": "mở ảnh hoặc video",
   "keyboard_shortcuts.pinned": "mở danh sách tút ghim",
-  "keyboard_shortcuts.profile": "mở trang cá nhân của người viết tút",
+  "keyboard_shortcuts.profile": "mở hồ sơ của người viết tút",
   "keyboard_shortcuts.reply": "trả lời",
   "keyboard_shortcuts.requests": "mở danh sách yêu cầu theo dõi",
   "keyboard_shortcuts.search": "mở tìm kiếm",
@@ -293,7 +293,7 @@
   "navigation_bar.direct": "Tin nhắn",
   "navigation_bar.discover": "Khám phá",
   "navigation_bar.domain_blocks": "Máy chủ đã ẩn",
-  "navigation_bar.edit_profile": "Trang cá nhân",
+  "navigation_bar.edit_profile": "Sửa hồ sơ",
   "navigation_bar.explore": "Xu hướng",
   "navigation_bar.favourites": "Thích",
   "navigation_bar.filters": "Bộ lọc từ ngữ",
@@ -378,11 +378,11 @@
   "regeneration_indicator.label": "Đang tải…",
   "regeneration_indicator.sublabel": "Bảng tin của bạn đang được cập nhật!",
   "relative_time.days": "{number} ngày",
-  "relative_time.full.days": "{number, plural, other {# ngày}} trước",
-  "relative_time.full.hours": "{number, plural, other {# giờ}} trước",
+  "relative_time.full.days": "{number, plural, other {# ngày}}",
+  "relative_time.full.hours": "{number, plural, other {# giờ}}",
   "relative_time.full.just_now": "vừa xong",
-  "relative_time.full.minutes": "{number, plural, other {# phút}} trước",
-  "relative_time.full.seconds": "{number, plural, other {# giây}} trước",
+  "relative_time.full.minutes": "{number, plural, other {# phút}}",
+  "relative_time.full.seconds": "{number, plural, other {#s}}",
   "relative_time.hours": "{number} giờ",
   "relative_time.just_now": "vừa xong",
   "relative_time.minutes": "{number} phút",
@@ -414,9 +414,9 @@
   "report.reasons.spam_description": "Liên kết độc hại, tạo tương tác giả hoặc trả lời lặp đi lặp lại",
   "report.reasons.violation": "Vi phạm quy tắc máy chủ",
   "report.reasons.violation_description": "Bạn nhận thấy nó vi phạm quy tắc máy chủ",
-  "report.rules.subtitle": "Chọn tất cả những áp dụng",
+  "report.rules.subtitle": "Chọn tất cả những gì phù hợp",
   "report.rules.title": "Vi phạm quy tắc nào?",
-  "report.statuses.subtitle": "Chọn tất cả những áp dụng",
+  "report.statuses.subtitle": "Chọn tất cả những gì phù hợp",
   "report.statuses.title": "Bạn muốn gửi tút nào kèm báo cáo này?",
   "report.submit": "Gửi đi",
   "report.target": "Báo cáo {target}",
@@ -458,14 +458,14 @@
   "status.filtered": "Bộ lọc",
   "status.history.created": "{name} tạo lúc {date}",
   "status.history.edited": "{name} sửa lúc {date}",
-  "status.load_more": "Xem thêm",
+  "status.load_more": "Tải thêm",
   "status.media_hidden": "Đã ẩn",
   "status.mention": "Nhắc đến @{name}",
   "status.more": "Thêm",
   "status.mute": "Ẩn @{name}",
   "status.mute_conversation": "Không quan tâm nữa",
   "status.open": "Xem nguyên văn",
-  "status.pin": "Ghim lên trang cá nhân",
+  "status.pin": "Ghim lên hồ sơ",
   "status.pinned": "Tút đã ghim",
   "status.read_more": "Đọc tiếp",
   "status.reblog": "Đăng lại",
@@ -486,7 +486,7 @@
   "status.show_thread": "Xem chuỗi tút này",
   "status.uncached_media_warning": "Uncached",
   "status.unmute_conversation": "Quan tâm",
-  "status.unpin": "Bỏ ghim trên trang cá nhân",
+  "status.unpin": "Bỏ ghim trên hồ sơ",
   "suggestions.dismiss": "Tắt đề xuất",
   "suggestions.header": "Có thể bạn quan tâm…",
   "tabs_bar.federated_timeline": "Thế giới",
@@ -515,6 +515,7 @@
   "upload_error.poll": "Không cho phép đính kèm tập tin.",
   "upload_form.audio_description": "Mô tả cho người mất thính giác",
   "upload_form.description": "Mô tả cho người khiếm thị",
+  "upload_form.description_missing": "Chưa thêm mô tả",
   "upload_form.edit": "Biên tập",
   "upload_form.thumbnail": "Đổi ảnh thumbnail",
   "upload_form.undo": "Xóa bỏ",
diff --git a/app/javascript/mastodon/locales/zgh.json b/app/javascript/mastodon/locales/zgh.json
index b321d1525..6e6b1cd86 100644
--- a/app/javascript/mastodon/locales/zgh.json
+++ b/app/javascript/mastodon/locales/zgh.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "File upload not allowed with polls.",
   "upload_form.audio_description": "Describe for people with hearing loss",
   "upload_form.description": "Describe for the visually impaired",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "ⵙⵏⴼⵍ",
   "upload_form.thumbnail": "Change thumbnail",
   "upload_form.undo": "ⴽⴽⵙ",
diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json
index 9e306688e..e479c63c6 100644
--- a/app/javascript/mastodon/locales/zh-CN.json
+++ b/app/javascript/mastodon/locales/zh-CN.json
@@ -41,12 +41,12 @@
   "account.statuses_counter": "{counter} 条嘟文",
   "account.unblock": "解除屏蔽 @{name}",
   "account.unblock_domain": "不再屏蔽 {domain} 实例",
-  "account.unblock_short": "移出黑名单",
+  "account.unblock_short": "解除屏蔽",
   "account.unendorse": "不在个人资料中推荐此用户",
   "account.unfollow": "取消关注",
   "account.unmute": "不再隐藏 @{name}",
   "account.unmute_notifications": "不再隐藏来自 @{name} 的通知",
-  "account.unmute_short": "恢复消息提醒",
+  "account.unmute_short": "取消静音",
   "account_note.placeholder": "点击添加备注",
   "admin.dashboard.daily_retention": "注册后用户留存率(按日计算)",
   "admin.dashboard.monthly_retention": "注册后用户留存率(按月计算)",
@@ -160,7 +160,7 @@
   "emoji_button.search_results": "搜索结果",
   "emoji_button.symbols": "符号",
   "emoji_button.travel": "旅行和地点",
-  "empty_column.account_suspended": "账户被封禁",
+  "empty_column.account_suspended": "账户已停用",
   "empty_column.account_timeline": "这里没有嘟文!",
   "empty_column.account_unavailable": "个人资料不可用",
   "empty_column.blocks": "你目前没有屏蔽任何用户。",
@@ -198,7 +198,7 @@
   "follow_recommendations.lead": "你关注的人的嘟文将按时间顺序在你的主页上显示。 别担心,你可以随时取消关注!",
   "follow_request.authorize": "同意",
   "follow_request.reject": "拒绝",
-  "follow_requests.unlocked_explanation": "虽说你没有锁嘟,但是 {domain} 的工作人员觉得你可能想手工审核关注请求。",
+  "follow_requests.unlocked_explanation": "虽说你没有锁嘟,但是 {domain} 的工作人员觉得你可能想手工审核这些账号的关注请求。",
   "generic.saved": "已保存",
   "getting_started.developers": "开发",
   "getting_started.directory": "用户目录",
@@ -206,7 +206,7 @@
   "getting_started.heading": "开始使用",
   "getting_started.invite": "邀请用户",
   "getting_started.open_source_notice": "Mastodon 是开源软件。欢迎前往 GitHub({github})贡献代码或反馈问题。",
-  "getting_started.security": "帐户安全",
+  "getting_started.security": "账户安全设置",
   "getting_started.terms": "使用条款",
   "hashtag.column_header.tag_mode.all": "以及 {additional}",
   "hashtag.column_header.tag_mode.any": "或是 {additional}",
@@ -308,7 +308,7 @@
   "navigation_bar.pins": "置顶嘟文",
   "navigation_bar.preferences": "首选项",
   "navigation_bar.public_timeline": "跨站公共时间轴",
-  "navigation_bar.security": "安全",
+  "navigation_bar.security": "安全性",
   "notification.admin.sign_up": "{name} 注册了",
   "notification.favourite": "{name} 喜欢了你的嘟文",
   "notification.follow": "{name} 开始关注你",
@@ -515,6 +515,7 @@
   "upload_error.poll": "投票中不允许上传文件。",
   "upload_form.audio_description": "为听障人士添加文字描述",
   "upload_form.description": "为视觉障碍人士添加文字说明",
+  "upload_form.description_missing": "没有添加描述",
   "upload_form.edit": "编辑",
   "upload_form.thumbnail": "更改缩略图",
   "upload_form.undo": "删除",
diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json
index b60560cd1..462c05447 100644
--- a/app/javascript/mastodon/locales/zh-HK.json
+++ b/app/javascript/mastodon/locales/zh-HK.json
@@ -515,6 +515,7 @@
   "upload_error.poll": "不允許在投票上傳檔案。",
   "upload_form.audio_description": "簡單描述內容給聽障人士",
   "upload_form.description": "為視覺障礙人士添加文字說明",
+  "upload_form.description_missing": "No description added",
   "upload_form.edit": "編輯",
   "upload_form.thumbnail": "更改預覽圖",
   "upload_form.undo": "刪除",
diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json
index f9366fe17..d08d49af5 100644
--- a/app/javascript/mastodon/locales/zh-TW.json
+++ b/app/javascript/mastodon/locales/zh-TW.json
@@ -1,12 +1,12 @@
 {
   "account.account_note_header": "備註",
-  "account.add_or_remove_from_list": "從名單中新增或移除",
+  "account.add_or_remove_from_list": "從列表中新增或移除",
   "account.badges.bot": "機器人",
   "account.badges.group": "群組",
   "account.block": "封鎖 @{name}",
   "account.block_domain": "封鎖來自 {domain} 網域的所有內容",
   "account.blocked": "已封鎖",
-  "account.browse_more_on_origin_server": "在該伺服器的個人檔案頁上瀏覽更多",
+  "account.browse_more_on_origin_server": "於該伺服器的個人檔案頁上瀏覽更多",
   "account.cancel_follow_request": "取消跟隨請求",
   "account.direct": "傳私訊給 @{name}",
   "account.disable_notifications": "取消來自 @{name} 嘟文的通知",
@@ -53,7 +53,7 @@
   "admin.dashboard.retention.average": "平均",
   "admin.dashboard.retention.cohort": "註冊月份",
   "admin.dashboard.retention.cohort_size": "新使用者",
-  "alert.rate_limited.message": "請在 {retry_time, time, medium} 後重試",
+  "alert.rate_limited.message": "請在 {retry_time, time, medium} 後重試。",
   "alert.rate_limited.title": "已限速",
   "alert.unexpected.message": "發生了非預期的錯誤。",
   "alert.unexpected.title": "哎呀!",
@@ -76,7 +76,7 @@
   "column.favourites": "最愛",
   "column.follow_requests": "跟隨請求",
   "column.home": "首頁",
-  "column.lists": "名單",
+  "column.lists": "列表",
   "column.mutes": "已靜音的使用者",
   "column.notifications": "通知",
   "column.pins": "釘選的嘟文",
@@ -95,7 +95,7 @@
   "compose_form.direct_message_warning": "這條嘟文只有被提及的使用者才看得到。",
   "compose_form.direct_message_warning_learn_more": "了解更多",
   "compose_form.hashtag_warning": "由於這則嘟文設定為「不公開」,它將不會被列於任何主題標籤下。只有公開的嘟文才能藉由主題標籤找到。",
-  "compose_form.lock_disclaimer": "您的帳戶尚未{locked}。任何人都能關注您並看到您設定成只有跟隨者能看的嘟文。",
+  "compose_form.lock_disclaimer": "您的帳戶尚未 {locked}。任何人都能關注您並看到您設定成只有跟隨者能看的嘟文。",
   "compose_form.lock_disclaimer.lock": "上鎖",
   "compose_form.placeholder": "正在想些什麼嗎?",
   "compose_form.poll.add_option": "新增選項",
@@ -116,26 +116,26 @@
   "confirmation_modal.cancel": "取消",
   "confirmations.block.block_and_report": "封鎖並檢舉",
   "confirmations.block.confirm": "封鎖",
-  "confirmations.block.message": "確定要封鎖 {name} 嗎?",
+  "confirmations.block.message": "您確定要封鎖 {name} ?",
   "confirmations.delete.confirm": "刪除",
   "confirmations.delete.message": "您確定要刪除這則嘟文?",
   "confirmations.delete_list.confirm": "刪除",
-  "confirmations.delete_list.message": "確定永久刪除此名單?",
+  "confirmations.delete_list.message": "您確定要永久刪除此列表?",
   "confirmations.discard_edit_media.confirm": "捨棄",
   "confirmations.discard_edit_media.message": "您在媒體描述或預覽區塊有未儲存的變更。是否要捨棄這些變更?",
   "confirmations.domain_block.confirm": "隱藏整個域名",
   "confirmations.domain_block.message": "真的非常確定封鎖整個 {domain} 網域嗎?大部分情況下,您只需要封鎖或靜音少數特定的帳帳戶能滿足需求了。您將不能在任何公開的時間軸及通知中看到來自此網域的內容。您來自該網域的跟隨者也將被移除。",
   "confirmations.logout.confirm": "登出",
-  "confirmations.logout.message": "確定要登出嗎?",
+  "confirmations.logout.message": "您確定要登出嗎?",
   "confirmations.mute.confirm": "靜音",
   "confirmations.mute.explanation": "這將會隱藏來自他們的嘟文與通知,但是他們還是可以查閱您的嘟文與跟隨您。",
-  "confirmations.mute.message": "確定靜音 {name} ?",
+  "confirmations.mute.message": "您確定要靜音 {name} ?",
   "confirmations.redraft.confirm": "刪除並重新編輯",
-  "confirmations.redraft.message": "確定刪掉這則嘟文並重新編輯嗎?將會失去這則嘟文的轉嘟及最愛,且回覆這則的嘟文將會變成獨立的嘟文。",
+  "confirmations.redraft.message": "您確定要刪掉這則嘟文並重新編輯嗎?將會失去這則嘟文的轉嘟及最愛,且回覆這則的嘟文將會變成獨立的嘟文。",
   "confirmations.reply.confirm": "回覆",
   "confirmations.reply.message": "現在回覆將蓋掉您目前正在撰寫的訊息。是否仍要回覆?",
   "confirmations.unfollow.confirm": "取消跟隨",
-  "confirmations.unfollow.message": "確定要取消跟隨 {name} 嗎?",
+  "confirmations.unfollow.message": "您確定要取消跟隨 {name} 嗎?",
   "conversation.delete": "刪除對話",
   "conversation.mark_as_read": "標記為已讀",
   "conversation.open": "檢視對話",
@@ -176,8 +176,8 @@
   "empty_column.hashtag": "這個主題標籤下什麼也沒有。",
   "empty_column.home": "您的首頁時間軸是空的!前往 {suggestions} 或使用搜尋功能來認識其他人。",
   "empty_column.home.suggestions": "檢視部份建議",
-  "empty_column.list": "這份名單還沒有東西。當此名單的成員嘟出了新的嘟文時,它們就會顯示於此。",
-  "empty_column.lists": "您還沒有建立任何名單。這裡將會顯示您所建立的名單。",
+  "empty_column.list": "這份列表下什麼也沒有。當此列表的成員嘟出了新的嘟文時,它們就會顯示於此。",
+  "empty_column.lists": "您還沒有建立任何列表。這裡將會顯示您所建立的列表。",
   "empty_column.mutes": "您尚未靜音任何使用者。",
   "empty_column.notifications": "您尚未收到任何通知,和別人互動開啟對話吧。",
   "empty_column.public": "這裡什麼都沒有!嘗試寫些公開的嘟文,或著自己跟隨其他伺服器的使用者後就會有嘟文出現了",
@@ -194,8 +194,8 @@
   "explore.trending_statuses": "嘟文",
   "explore.trending_tags": "主題標籤",
   "follow_recommendations.done": "完成",
-  "follow_recommendations.heading": "跟隨您想檢視其貼文的人!這裡有一些建議。",
-  "follow_recommendations.lead": "來自您跟隨的人的貼文將會按時間順序顯示在您的家 feed 上。不要害怕犯錯,您隨時都可以取消跟隨其他人!",
+  "follow_recommendations.heading": "跟隨您想檢視其嘟文的人!這裡有一些建議。",
+  "follow_recommendations.lead": "來自您跟隨的人之嘟文將會按時間順序顯示在您的首頁時間軸上。不要害怕犯錯,您隨時都可以取消跟隨其他人!",
   "follow_request.authorize": "授權",
   "follow_request.reject": "拒絕",
   "follow_requests.unlocked_explanation": "即便您的帳戶未被鎖定,{domain} 的管理員認為您可能想要自己審核這些帳戶的跟隨請求。",
@@ -232,10 +232,10 @@
   "keyboard_shortcuts.compose": "將焦點移至撰寫文字區塊",
   "keyboard_shortcuts.description": "說明",
   "keyboard_shortcuts.direct": "開啟私訊欄",
-  "keyboard_shortcuts.down": "在名單中往下移動",
+  "keyboard_shortcuts.down": "在列表中往下移動",
   "keyboard_shortcuts.enter": "檢視嘟文",
   "keyboard_shortcuts.favourite": "加到最愛",
-  "keyboard_shortcuts.favourites": "開啟最愛名單",
+  "keyboard_shortcuts.favourites": "開啟最愛列表",
   "keyboard_shortcuts.federated": "開啟聯邦時間軸",
   "keyboard_shortcuts.heading": "鍵盤快速鍵",
   "keyboard_shortcuts.home": "開啟首頁時間軸",
@@ -243,47 +243,47 @@
   "keyboard_shortcuts.legend": "顯示此圖例",
   "keyboard_shortcuts.local": "開啟本機時間軸",
   "keyboard_shortcuts.mention": "提及作者",
-  "keyboard_shortcuts.muted": "開啟靜音使用者名單",
+  "keyboard_shortcuts.muted": "開啟靜音使用者列表",
   "keyboard_shortcuts.my_profile": "開啟個人資料頁面",
   "keyboard_shortcuts.notifications": "開啟通知欄",
   "keyboard_shortcuts.open_media": "開啟媒體",
-  "keyboard_shortcuts.pinned": "開啟釘選的嘟文名單",
+  "keyboard_shortcuts.pinned": "開啟釘選的嘟文列表",
   "keyboard_shortcuts.profile": "開啟作者的個人資料頁面",
   "keyboard_shortcuts.reply": "回應嘟文",
-  "keyboard_shortcuts.requests": "開啟跟隨請求名單",
+  "keyboard_shortcuts.requests": "開啟跟隨請求列表",
   "keyboard_shortcuts.search": "將焦點移至搜尋框",
   "keyboard_shortcuts.spoilers": "顯示或隱藏被折疊的正文",
   "keyboard_shortcuts.start": "開啟「開始使用」欄位",
-  "keyboard_shortcuts.toggle_hidden": "顯示/隱藏在內容警告之後的正文",
-  "keyboard_shortcuts.toggle_sensitivity": "顯示 / 隱藏媒體",
+  "keyboard_shortcuts.toggle_hidden": "顯示或隱藏在內容警告之後的正文",
+  "keyboard_shortcuts.toggle_sensitivity": "顯示或隱藏媒體",
   "keyboard_shortcuts.toot": "開始發出新嘟文",
   "keyboard_shortcuts.unfocus": "取消輸入文字區塊 / 搜尋的焦點",
-  "keyboard_shortcuts.up": "在名單中往上移動",
+  "keyboard_shortcuts.up": "在列表中往上移動",
   "lightbox.close": "關閉",
   "lightbox.compress": "折疊圖片檢視框",
   "lightbox.expand": "展開圖片檢視框",
   "lightbox.next": "下一步",
   "lightbox.previous": "上一步",
-  "lists.account.add": "新增至名單",
-  "lists.account.remove": "從名單中移除",
-  "lists.delete": "刪除名單",
-  "lists.edit": "編輯名單",
+  "lists.account.add": "新增至列表",
+  "lists.account.remove": "從列表中移除",
+  "lists.delete": "刪除列表",
+  "lists.edit": "編輯列表",
   "lists.edit.submit": "變更標題",
-  "lists.new.create": "新增名單",
-  "lists.new.title_placeholder": "新名單標題",
+  "lists.new.create": "新增列表",
+  "lists.new.title_placeholder": "新列表標題",
   "lists.replies_policy.followed": "任何跟隨的使用者",
-  "lists.replies_policy.list": "名單成員",
+  "lists.replies_policy.list": "列表成員",
   "lists.replies_policy.none": "沒有人",
   "lists.replies_policy.title": "顯示回覆:",
   "lists.search": "搜尋您跟隨的使用者",
-  "lists.subheading": "您的名單",
+  "lists.subheading": "您的列表",
   "load_pending": "{count, plural, one {# 個新項目} other {# 個新項目}}",
   "loading_indicator.label": "讀取中...",
   "media_gallery.toggle_visible": "切換可見性",
   "missing_indicator.label": "找不到",
   "missing_indicator.sublabel": "找不到此資源",
   "mute_modal.duration": "持續時間",
-  "mute_modal.hide_notifications": "隱藏來自這位使用者的通知?",
+  "mute_modal.hide_notifications": "是否隱藏來自這位使用者的通知?",
   "mute_modal.indefinite": "無期限",
   "navigation_bar.apps": "行動應用程式",
   "navigation_bar.blocks": "封鎖使用者",
@@ -301,7 +301,7 @@
   "navigation_bar.follows_and_followers": "跟隨中與跟隨者",
   "navigation_bar.info": "關於此伺服器",
   "navigation_bar.keyboard_shortcuts": "快速鍵",
-  "navigation_bar.lists": "名單",
+  "navigation_bar.lists": "列表",
   "navigation_bar.logout": "登出",
   "navigation_bar.mutes": "靜音的使用者",
   "navigation_bar.personal": "個人",
@@ -320,7 +320,7 @@
   "notification.status": "{name} 剛剛嘟文",
   "notification.update": "{name} 編輯了嘟文",
   "notifications.clear": "清除通知",
-  "notifications.clear_confirmation": "確定要永久清除您的通知嗎?",
+  "notifications.clear_confirmation": "您確定要永久清除您的通知嗎?",
   "notifications.column_settings.admin.sign_up": "新註冊帳號:",
   "notifications.column_settings.alert": "桌面通知",
   "notifications.column_settings.favourite": "最愛:",
@@ -345,13 +345,13 @@
   "notifications.filter.follows": "跟隨的使用者",
   "notifications.filter.mentions": "提及",
   "notifications.filter.polls": "投票結果",
-  "notifications.filter.statuses": "已跟隨使用者的最新動態",
+  "notifications.filter.statuses": "您跟隨的使用者之最新動態",
   "notifications.grant_permission": "授予權限",
   "notifications.group": "{count} 條通知",
   "notifications.mark_as_read": "將所有通知都標記為已讀",
   "notifications.permission_denied": "由於之前拒絕了瀏覽器請求,因此桌面通知不可用",
-  "notifications.permission_denied_alert": "因為之前瀏覽器權限被拒絕,無法啟用桌面通知",
-  "notifications.permission_required": "因為尚未授予所需的權限,所以桌面通知不可用。",
+  "notifications.permission_denied_alert": "由於之前瀏覽器權限被拒絕,無法啟用桌面通知",
+  "notifications.permission_required": "由於尚未授予所需的權限,所以桌面通知不可用。",
   "notifications_permission_banner.enable": "啟用桌面通知",
   "notifications_permission_banner.how_to_control": "啟用桌面通知以在 Mastodon 沒有開啟的時候接收通知。在已經啟用桌面通知的時候,您可以透過上面的 {icon} 按鈕準確的控制哪些類型的互動會產生桌面通知。",
   "notifications_permission_banner.title": "不要錯過任何東西!",
@@ -372,20 +372,20 @@
   "privacy.private.short": "僅跟隨者",
   "privacy.public.long": "公開,且顯示於公開時間軸",
   "privacy.public.short": "公開",
-  "privacy.unlisted.long": "公開,但不會顯示在公開時間軸",
+  "privacy.unlisted.long": "公開,但不會顯示於公開時間軸",
   "privacy.unlisted.short": "不公開",
   "refresh": "重新整理",
   "regeneration_indicator.label": "載入中…",
-  "regeneration_indicator.sublabel": "您的主頁時間軸正在準備中!",
+  "regeneration_indicator.sublabel": "您的首頁時間軸正在準備中!",
   "relative_time.days": "{number} 天",
   "relative_time.full.days": "{number, plural, one {# 天} other {# 天}}前",
   "relative_time.full.hours": "{number, plural, one {# 小時} other {# 小時}}前",
   "relative_time.full.just_now": "剛剛",
   "relative_time.full.minutes": "{number, plural, one {# 分鐘} other {# 分鐘}}前",
   "relative_time.full.seconds": "{number, plural, one {# 秒} other {# 秒}}前",
-  "relative_time.hours": "{number}小時前",
+  "relative_time.hours": "{number} 小時前",
   "relative_time.just_now": "剛剛",
-  "relative_time.minutes": "{number} 分前",
+  "relative_time.minutes": "{number} 分鐘前",
   "relative_time.seconds": "{number} 秒",
   "relative_time.today": "今天",
   "reply_indicator.cancel": "取消",
@@ -401,7 +401,7 @@
   "report.close": "已完成",
   "report.comment.title": "有什麼其他您想讓我們知道的嗎?",
   "report.forward": "轉寄到 {target}",
-  "report.forward_hint": "這個帳戶屬於其他伺服器。要像該伺服器發送匿名的檢舉訊息嗎?",
+  "report.forward_hint": "這個帳戶屬於其他伺服器。要像該伺服器發送匿名的檢舉訊息嗎?",
   "report.mute": "靜音",
   "report.mute_explanation": "您將不再看到他們的嘟文。他們仍能可以跟隨您以及察看您的嘟文,並且不會知道他們已被靜音。",
   "report.next": "繼續",
@@ -425,7 +425,7 @@
   "report.thanks.title": "不想再看到這個?",
   "report.thanks.title_actionable": "感謝您的檢舉,我們將會著手處理。",
   "report.unfollow": "取消跟隨 @{name}",
-  "report.unfollow_explanation": "您正在跟隨此帳號。如不欲於首頁再見到他們的嘟文,請取消跟隨。",
+  "report.unfollow_explanation": "您正在跟隨此帳號。如不欲於首頁時間軸再見到他們的嘟文,請取消跟隨。",
   "search.placeholder": "搜尋",
   "search_popout.search_format": "進階搜尋格式",
   "search_popout.tips.full_text": "輸入簡單的文字,搜尋由您撰寫、最愛、轉嘟或提您的嘟文,以及與關鍵詞匹配的使用者名稱、帳戶顯示名稱和主題標籤。",
@@ -472,7 +472,7 @@
   "status.reblog_private": "轉嘟給原有關注者",
   "status.reblogged_by": "{name} 轉嘟了",
   "status.reblogs.empty": "還沒有人轉嘟過這則嘟文。當有人轉嘟時,它將於此顯示。",
-  "status.redraft": "刪除 & 編輯",
+  "status.redraft": "刪除並重新編輯",
   "status.remove_bookmark": "移除書籤",
   "status.reply": "回覆",
   "status.replyAll": "回覆討論串",
@@ -494,9 +494,9 @@
   "tabs_bar.local_timeline": "本機",
   "tabs_bar.notifications": "通知",
   "tabs_bar.search": "搜尋",
-  "time_remaining.days": "剩餘{number, plural, one {# 天} other {# 天}}",
-  "time_remaining.hours": "剩餘{number, plural, one {# 小時} other {# 小時}}",
-  "time_remaining.minutes": "剩餘{number, plural, one {# 分鐘} other {# 分鐘}}",
+  "time_remaining.days": "剩餘 {number, plural, one {# 天} other {# 天}}",
+  "time_remaining.hours": "剩餘 {number, plural, one {# 小時} other {# 小時}}",
+  "time_remaining.minutes": "剩餘 {number, plural, one {# 分鐘} other {# 分鐘}}",
   "time_remaining.moments": "剩餘時間",
   "time_remaining.seconds": "剩餘 {number, plural, one {# 秒} other {# 秒}}",
   "timeline_hint.remote_resource_not_displayed": "不會顯示來自其他伺服器的 {resource}",
@@ -515,10 +515,11 @@
   "upload_error.poll": "不允許在投票中上傳檔案。",
   "upload_form.audio_description": "描述內容給聽障人士",
   "upload_form.description": "為視障人士增加文字說明",
+  "upload_form.description_missing": "沒有任何描述",
   "upload_form.edit": "編輯",
   "upload_form.thumbnail": "更改預覽圖",
   "upload_form.undo": "刪除",
-  "upload_form.video_description": "描述給聽障或視障人士",
+  "upload_form.video_description": "描述內容給聽障或視障人士",
   "upload_modal.analyzing_picture": "正在分析圖片…",
   "upload_modal.apply": "套用",
   "upload_modal.applying": "正在套用⋯⋯",
diff --git a/app/javascript/mastodon/reducers/timelines.js b/app/javascript/mastodon/reducers/timelines.js
index 53a644e47..d72109e69 100644
--- a/app/javascript/mastodon/reducers/timelines.js
+++ b/app/javascript/mastodon/reducers/timelines.js
@@ -171,6 +171,17 @@ const updateTop = (state, timeline, top) => {
   }));
 };
 
+const reconnectTimeline = (state, usePendingItems) => {
+  if (state.get('online')) {
+    return state;
+  }
+
+  return state.withMutations(mMap => {
+    mMap.update(usePendingItems ? 'pendingItems' : 'items', items => items.first() ? items.unshift(null) : items);
+    mMap.set('online', true);
+  });
+};
+
 export default function timelines(state = initialState, action) {
   switch(action.type) {
   case TIMELINE_LOAD_PENDING:
@@ -196,7 +207,7 @@ export default function timelines(state = initialState, action) {
   case TIMELINE_SCROLL_TOP:
     return updateTop(state, action.timeline, action.top);
   case TIMELINE_CONNECT:
-    return state.update(action.timeline, initialTimeline, map => map.set('online', true));
+    return state.update(action.timeline, initialTimeline, map => reconnectTimeline(map, action.usePendingItems));
   case TIMELINE_DISCONNECT:
     return state.update(
       action.timeline,
diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb
index 02ecb403d..b35ae4f22 100644
--- a/app/lib/feed_manager.rb
+++ b/app/lib/feed_manager.rb
@@ -268,7 +268,7 @@ class FeedManager
     account.following.includes(:account_stat).find_each do |target_account|
       if redis.zcard(timeline_key) >= limit
         oldest_home_score = redis.zrange(timeline_key, 0, 0, with_scores: true).first.last.to_i
-        last_status_score = Mastodon::Snowflake.id_at(account.last_status_at)
+        last_status_score = Mastodon::Snowflake.id_at(target_account.last_status_at)
 
         # If the feed is full and this account has not posted more recently
         # than the last item on the feed, then we can skip the whole account
diff --git a/app/lib/search_query_transformer.rb b/app/lib/search_query_transformer.rb
index c685d7b6f..aef05e9d9 100644
--- a/app/lib/search_query_transformer.rb
+++ b/app/lib/search_query_transformer.rb
@@ -88,14 +88,14 @@ class SearchQueryTransformer < Parslet::Transform
       case prefix
       when 'from'
         @filter = :account_id
-        username, domain = term.split('@')
-        account = Account.find_remote(username, domain)
 
-        raise "Account not found: #{term}" unless account
+        username, domain = term.gsub(/\A@/, '').split('@')
+        domain           = nil if TagManager.instance.local_domain?(domain)
+        account          = Account.find_remote!(username, domain)
 
         @term = account.id
       else
-        raise "Unknown prefix: #{prefix}"
+        raise Mastodon::SyntaxError
       end
     end
   end
diff --git a/app/lib/user_settings_decorator.rb b/app/lib/user_settings_decorator.rb
index d8015e50d..d339e078c 100644
--- a/app/lib/user_settings_decorator.rb
+++ b/app/lib/user_settings_decorator.rb
@@ -43,6 +43,7 @@ class UserSettingsDecorator
     user.settings['use_pending_items']   = use_pending_items_preference if change?('setting_use_pending_items')
     user.settings['trends']              = trends_preference if change?('setting_trends')
     user.settings['crop_images']         = crop_images_preference if change?('setting_crop_images')
+    user.settings['always_send_emails']  = always_send_emails_preference if change?('setting_always_send_emails')
   end
 
   def merged_notification_emails
@@ -157,6 +158,10 @@ class UserSettingsDecorator
     boolean_cast_setting 'setting_crop_images'
   end
 
+  def always_send_emails_preference
+    boolean_cast_setting 'setting_always_send_emails'
+  end
+
   def boolean_cast_setting(key)
     ActiveModel::Type::Boolean.new.cast(settings[key])
   end
diff --git a/app/models/account_alias.rb b/app/models/account_alias.rb
index 3d659142a..b421c66e2 100644
--- a/app/models/account_alias.rb
+++ b/app/models/account_alias.rb
@@ -28,6 +28,11 @@ class AccountAlias < ApplicationRecord
     super(val.start_with?('@') ? val[1..-1] : val)
   end
 
+  def pretty_acct
+    username, domain = acct.split('@')
+    domain.nil? ? username : "#{username}@#{Addressable::IDNA.to_unicode(domain)}"
+  end
+
   private
 
   def set_uri
diff --git a/app/models/status.rb b/app/models/status.rb
index 9eaf85668..cc7ee568f 100644
--- a/app/models/status.rb
+++ b/app/models/status.rb
@@ -150,11 +150,13 @@ class Status < ApplicationRecord
       ids += favourites.where(account: Account.local).pluck(:account_id)
       ids += reblogs.where(account: Account.local).pluck(:account_id)
       ids += bookmarks.where(account: Account.local).pluck(:account_id)
+      ids += poll.votes.where(account: Account.local).pluck(:account_id) if poll.present?
     else
       ids += preloaded.mentions[id] || []
       ids += preloaded.favourites[id] || []
       ids += preloaded.reblogs[id] || []
       ids += preloaded.bookmarks[id] || []
+      ids += preloaded.votes[id] || []
     end
 
     ids.uniq
diff --git a/app/models/trends/base.rb b/app/models/trends/base.rb
index 7ed13228d..200f8d635 100644
--- a/app/models/trends/base.rb
+++ b/app/models/trends/base.rb
@@ -37,12 +37,12 @@ class Trends::Base
     Trends::Query.new(key_prefix, klass)
   end
 
-  def score(id)
-    redis.zscore("#{key_prefix}:all", id) || 0
+  def score(id, locale: nil)
+    redis.zscore([key_prefix, 'all', locale].compact.join(':'), id) || 0
   end
 
-  def rank(id)
-    redis.zrevrank("#{key_prefix}:allowed", id)
+  def rank(id, locale: nil)
+    redis.zrevrank([key_prefix, 'allowed', locale].compact.join(':'), id)
   end
 
   def currently_trending_ids(allowed, limit)
@@ -65,8 +65,8 @@ class Trends::Base
   end
 
   def trim_older_items
-    redis.zremrangebyscore("#{key_prefix}:all", '-inf', '(1')
-    redis.zremrangebyscore("#{key_prefix}:allowed", '-inf', '(1')
+    redis.zremrangebyscore("#{key_prefix}:all", '-inf', '(0.3')
+    redis.zremrangebyscore("#{key_prefix}:allowed", '-inf', '(0.3')
   end
 
   def score_at_rank(rank)
diff --git a/app/models/trends/links.rb b/app/models/trends/links.rb
index 62308e706..5f046643a 100644
--- a/app/models/trends/links.rb
+++ b/app/models/trends/links.rb
@@ -30,7 +30,6 @@ class Trends::Links < Trends::Base
   def refresh(at_time = Time.now.utc)
     preview_cards = PreviewCard.where(id: (recently_used_ids(at_time) + currently_trending_ids(false, -1)).uniq)
     calculate_scores(preview_cards, at_time)
-    trim_older_items
   end
 
   def request_review
@@ -101,6 +100,8 @@ class Trends::Links < Trends::Base
       })
     end
 
+    trim_older_items
+
     # Clean up localized sets by calculating the intersection with the main
     # set. We do this instead of just deleting the localized sets to avoid
     # having moments where the API returns empty results
@@ -108,7 +109,7 @@ class Trends::Links < Trends::Base
     redis.pipelined do
       Trends.available_locales.each do |locale|
         redis.zinterstore("#{key_prefix}:all:#{locale}", ["#{key_prefix}:all:#{locale}", "#{key_prefix}:all"], aggregate: 'max')
-        redis.zinterstore("#{key_prefix}:allowed:#{locale}", ["#{key_prefix}:allowed:#{locale}", "#{key_prefix}:all"], aggregate: 'max')
+        redis.zinterstore("#{key_prefix}:allowed:#{locale}", ["#{key_prefix}:allowed:#{locale}", "#{key_prefix}:allowed"], aggregate: 'max')
       end
     end
   end
diff --git a/app/models/trends/query.rb b/app/models/trends/query.rb
index 231b65228..cd5571bc6 100644
--- a/app/models/trends/query.rb
+++ b/app/models/trends/query.rb
@@ -14,8 +14,8 @@ class Trends::Query
     @records = []
     @loaded  = false
     @allowed = false
-    @limit   = -1
-    @offset  = 0
+    @limit   = nil
+    @offset  = nil
   end
 
   def allowed!
@@ -59,7 +59,7 @@ class Trends::Query
     @records
   end
 
-  delegate :each, :empty?, :first, :last, to: :records
+  delegate :each, :empty?, :first, :last, :size, to: :records
 
   def to_ary
     records.dup
@@ -73,7 +73,10 @@ class Trends::Query
     if tmp_ids.empty?
       klass.none
     else
-      klass.joins("join unnest(array[#{tmp_ids.join(',')}]) with ordinality as x (id, ordering) on #{klass.table_name}.id = x.id").reorder('x.ordering')
+      scope = klass.joins("join unnest(array[#{tmp_ids.join(',')}]) with ordinality as x (id, ordering) on #{klass.table_name}.id = x.id").reorder('x.ordering')
+      scope = scope.offset(@offset) if @offset.present?
+      scope = scope.limit(@limit) if @limit.present?
+      scope
     end
   end
 
@@ -93,7 +96,7 @@ class Trends::Query
   end
 
   def ids
-    redis.zrevrange(key, @offset, @limit.positive? ? @limit - 1 : @limit).map(&:to_i)
+    redis.zrevrange(key, 0, -1).map(&:to_i)
   end
 
   def perform_queries
diff --git a/app/models/trends/statuses.rb b/app/models/trends/statuses.rb
index e9c48a06b..0ebda0fe1 100644
--- a/app/models/trends/statuses.rb
+++ b/app/models/trends/statuses.rb
@@ -6,7 +6,7 @@ class Trends::Statuses < Trends::Base
   self.default_options = {
     threshold: 5,
     review_threshold: 3,
-    score_halflife: 2.hours.freeze,
+    score_halflife: 6.hours.freeze,
   }
 
   class Query < Trends::Query
@@ -22,25 +22,11 @@ class Trends::Statuses < Trends::Base
     private
 
     def apply_scopes(scope)
-      scope.includes(:account)
-    end
-
-    def perform_queries
-      return super if @account.nil?
-
-      statuses        = super
-      account_ids     = statuses.map(&:account_id)
-      account_domains = statuses.map(&:account_domain)
-
-      preloaded_relations = {
-        blocking: Account.blocking_map(account_ids, @account.id),
-        blocked_by: Account.blocked_by_map(account_ids, @account.id),
-        muting: Account.muting_map(account_ids, @account.id),
-        following: Account.following_map(account_ids, @account.id),
-        domain_blocking_by_domain: Account.domain_blocking_map_by_domain(account_domains, @account.id),
-      }
-
-      statuses.reject { |status| StatusFilter.new(status, @account, preloaded_relations).filtered? }
+      if @account.nil?
+        scope
+      else
+        scope.not_excluded_by_account(@account).not_domain_blocked_by_account(@account)
+      end
     end
   end
 
@@ -62,7 +48,6 @@ class Trends::Statuses < Trends::Base
   def refresh(at_time = Time.now.utc)
     statuses = Status.where(id: (recently_used_ids(at_time) + currently_trending_ids(false, -1)).uniq).includes(:account, :media_attachments)
     calculate_scores(statuses, at_time)
-    trim_older_items
   end
 
   def request_review
@@ -125,13 +110,15 @@ class Trends::Statuses < Trends::Base
         })
       end
 
+      trim_older_items
+
       # Clean up localized sets by calculating the intersection with the main
       # set. We do this instead of just deleting the localized sets to avoid
       # having moments where the API returns empty results
 
       Trends.available_locales.each do |locale|
         redis.zinterstore("#{key_prefix}:all:#{locale}", ["#{key_prefix}:all:#{locale}", "#{key_prefix}:all"], aggregate: 'max')
-        redis.zinterstore("#{key_prefix}:allowed:#{locale}", ["#{key_prefix}:allowed:#{locale}", "#{key_prefix}:all"], aggregate: 'max')
+        redis.zinterstore("#{key_prefix}:allowed:#{locale}", ["#{key_prefix}:allowed:#{locale}", "#{key_prefix}:allowed"], aggregate: 'max')
       end
     end
   end
diff --git a/app/models/user.rb b/app/models/user.rb
index 5dd93519c..5c1f9504a 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -130,7 +130,7 @@ class User < ApplicationRecord
            :reduce_motion, :system_font_ui, :noindex, :flavour, :skin, :display_media, :hide_followers_count,
            :expand_spoilers, :default_language, :aggregate_reblogs, :show_application,
            :advanced_layout, :use_blurhash, :use_pending_items, :trends, :crop_images,
-           :disable_swiping, :default_content_type, :system_emoji_font,
+           :disable_swiping, :always_send_emails, :default_content_type, :system_emoji_font,
            to: :settings, prefix: :setting, allow_nil: false
 
   attr_reader :invite_code
diff --git a/app/serializers/web/notification_serializer.rb b/app/serializers/web/notification_serializer.rb
index ee83ec8b2..c5a908b19 100644
--- a/app/serializers/web/notification_serializer.rb
+++ b/app/serializers/web/notification_serializer.rb
@@ -34,6 +34,6 @@ class Web::NotificationSerializer < ActiveModel::Serializer
 
   def body
     str = strip_tags(object.target_status&.spoiler_text&.presence || object.target_status&.text || object.from_account.note)
-    truncate(HTMLEntities.new.decode(str.to_str), length: 140) # Do not encode entities, since this value will not be used in HTML
+    truncate(HTMLEntities.new.decode(str.to_str), length: 140, escape: false) # Do not encode entities, since this value will not be used in HTML
   end
 end
diff --git a/app/services/activitypub/fetch_featured_collection_service.rb b/app/services/activitypub/fetch_featured_collection_service.rb
index 66234b711..07a9fe039 100644
--- a/app/services/activitypub/fetch_featured_collection_service.rb
+++ b/app/services/activitypub/fetch_featured_collection_service.rb
@@ -27,7 +27,7 @@ class ActivityPub::FetchFeaturedCollectionService < BaseService
       next if ActivityPub::TagManager.instance.local_uri?(uri)
 
       status = ActivityPub::FetchRemoteStatusService.new.call(uri, on_behalf_of: local_follower)
-      next unless status.account_id == @account.id
+      next unless status&.account_id == @account.id
 
       status.id
     rescue ActiveRecord::RecordInvalid => e
diff --git a/app/services/notify_service.rb b/app/services/notify_service.rb
index a90f17cfd..d30b33876 100644
--- a/app/services/notify_service.rb
+++ b/app/services/notify_service.rb
@@ -1,6 +1,8 @@
 # frozen_string_literal: true
 
 class NotifyService < BaseService
+  include Redisable
+
   def call(recipient, type, activity)
     @recipient    = recipient
     @activity     = activity
@@ -8,10 +10,15 @@ class NotifyService < BaseService
 
     return if recipient.user.nil? || blocked?
 
-    create_notification!
+    @notification.save!
+
+    # It's possible the underlying activity has been deleted
+    # between the save call and now
+    return if @notification.activity.nil?
+
     push_notification!
     push_to_conversation! if direct_message?
-    send_email! if email_enabled?
+    send_email! if email_needed?
   rescue ActiveRecord::RecordInvalid
     nil
   end
@@ -92,8 +99,8 @@ class NotifyService < BaseService
   end
 
   def blocked?
-    blocked   = @recipient.suspended?                            # Skip if the recipient account is suspended anyway
-    blocked ||= from_self? && @notification.type != :poll        # Skip for interactions with self
+    blocked   = @recipient.suspended?
+    blocked ||= from_self? && @notification.type != :poll
 
     return blocked if message? && from_staff?
 
@@ -117,38 +124,52 @@ class NotifyService < BaseService
     end
   end
 
-  def create_notification!
-    @notification.save!
+  def push_notification!
+    push_to_streaming_api! if subscribed_to_streaming_api?
+    push_to_web_push_subscriptions!
   end
 
-  def push_notification!
-    return if @notification.activity.nil?
+  def push_to_streaming_api!
+    redis.publish("timeline:#{@recipient.id}:notifications", Oj.dump(event: :notification, payload: InlineRenderer.render(@notification, @recipient, :notification)))
+  end
 
-    Redis.current.publish("timeline:#{@recipient.id}:notifications", Oj.dump(event: :notification, payload: InlineRenderer.render(@notification, @recipient, :notification)))
-    send_push_notifications!
+  def subscribed_to_streaming_api?
+    redis.exists?("subscribed:timeline:#{@recipient.id}") || redis.exists?("subscribed:timeline:#{@recipient.id}:notifications")
   end
 
   def push_to_conversation!
-    return if @notification.activity.nil?
     AccountConversation.add_status(@recipient, @notification.target_status)
   end
 
-  def send_push_notifications!
-    subscriptions_ids = ::Web::PushSubscription.where(user_id: @recipient.user.id)
-                                               .select { |subscription| subscription.pushable?(@notification) }
-                                               .map(&:id)
+  def push_to_web_push_subscriptions!
+    ::Web::PushNotificationWorker.push_bulk(web_push_subscriptions.select { |subscription| subscription.pushable?(@notification) }) { |subscription| [subscription.id, @notification.id] }
+  end
 
-    ::Web::PushNotificationWorker.push_bulk(subscriptions_ids) do |subscription_id|
-      [subscription_id, @notification.id]
-    end
+  def web_push_subscriptions
+    @web_push_subscriptions ||= ::Web::PushSubscription.where(user_id: @recipient.user.id).to_a
+  end
+
+  def subscribed_to_web_push?
+    web_push_subscriptions.any?
   end
 
   def send_email!
-    return if @notification.activity.nil?
-    NotificationMailer.public_send(@notification.type, @recipient, @notification).deliver_later(wait: 2.minutes)
+    NotificationMailer.public_send(@notification.type, @recipient, @notification).deliver_later(wait: 2.minutes) if NotificationMailer.respond_to?(@notification.type)
+  end
+
+  def email_needed?
+    (!recipient_online? || always_send_emails?) && send_email_for_notification_type?
+  end
+
+  def recipient_online?
+    subscribed_to_streaming_api? || subscribed_to_web_push?
+  end
+
+  def always_send_emails?
+    @recipient.user.settings.always_send_emails
   end
 
-  def email_enabled?
+  def send_email_for_notification_type?
     @recipient.user.settings.notification_emails[@notification.type.to_s]
   end
 end
diff --git a/app/views/admin/trends/links/_preview_card.html.haml b/app/views/admin/trends/links/_preview_card.html.haml
index 2e6a0c62f..7d4897c7e 100644
--- a/app/views/admin/trends/links/_preview_card.html.haml
+++ b/app/views/admin/trends/links/_preview_card.html.haml
@@ -18,9 +18,9 @@
 
       = t('admin.trends.links.shared_by_over_week', count: preview_card.history.reduce(0) { |sum, day| sum + day.accounts })
 
-      - if preview_card.trendable? && (rank = Trends.links.rank(preview_card.id))
+      - if preview_card.trendable? && (rank = Trends.links.rank(preview_card.id, locale: params[:locale].presence))

-        %abbr{ title: t('admin.trends.tags.current_score', score: Trends.links.score(preview_card.id)) }= t('admin.trends.tags.trending_rank', rank: rank + 1)
+        %abbr{ title: t('admin.trends.tags.current_score', score: Trends.links.score(preview_card.id, locale: params[:locale].presence)) }= t('admin.trends.tags.trending_rank', rank: rank + 1)
 
         - if preview_card.decaying?

diff --git a/app/views/admin/trends/statuses/_status.html.haml b/app/views/admin/trends/statuses/_status.html.haml
index 0c463c6b1..e4d75bbb9 100644
--- a/app/views/admin/trends/statuses/_status.html.haml
+++ b/app/views/admin/trends/statuses/_status.html.haml
@@ -25,9 +25,9 @@
     - if status.trendable? && !status.account.discoverable?

       = t('admin.trends.statuses.not_discoverable')
-    - if status.trendable? && (rank = Trends.statuses.rank(status.id))
+    - if status.trendable? && (rank = Trends.statuses.rank(status.id, locale: params[:locale].presence))

-      %abbr{ title: t('admin.trends.tags.current_score', score: Trends.statuses.score(status.id)) }= t('admin.trends.tags.trending_rank', rank: rank + 1)
+      %abbr{ title: t('admin.trends.tags.current_score', score: Trends.statuses.score(status.id, locale: params[:locale].presence)) }= t('admin.trends.tags.trending_rank', rank: rank + 1)
     - elsif status.requires_review?

       = t('admin.trends.pending_review')
diff --git a/app/views/settings/preferences/notifications/show.html.haml b/app/views/settings/preferences/notifications/show.html.haml
index e01cd077f..38e8b171e 100644
--- a/app/views/settings/preferences/notifications/show.html.haml
+++ b/app/views/settings/preferences/notifications/show.html.haml
@@ -28,6 +28,9 @@
         = ff.input :trending_status, as: :boolean, wrapper: :with_label
 
   .fields-group
+    = f.input :setting_always_send_emails, as: :boolean, wrapper: :with_label
+
+  .fields-group
     = f.simple_fields_for :notification_emails, hash_to_object(current_user.settings.notification_emails) do |ff|
       = ff.input :digest, as: :boolean, wrapper: :with_label