about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/FUNDING.yml2
-rw-r--r--Gemfile6
-rw-r--r--Gemfile.lock30
-rw-r--r--app/controllers/api/v1/notifications_controller.rb6
-rw-r--r--app/controllers/concerns/signature_verification.rb29
-rw-r--r--app/javascript/flavours/glitch/styles/components/emoji.scss1
-rw-r--r--app/javascript/mastodon/components/autosuggest_input.js2
-rw-r--r--app/javascript/mastodon/features/compose/index.js10
-rw-r--r--app/javascript/mastodon/features/getting_started/index.js19
-rw-r--r--app/javascript/mastodon/features/ui/components/columns_area.js10
-rw-r--r--app/javascript/mastodon/features/ui/components/notifications_counter_icon.js23
-rw-r--r--app/javascript/mastodon/features/ui/components/tabs_bar.js3
-rw-r--r--app/javascript/mastodon/features/ui/index.js17
-rw-r--r--app/javascript/mastodon/locales/ar.json3
-rw-r--r--app/javascript/mastodon/locales/ast.json3
-rw-r--r--app/javascript/mastodon/locales/bg.json3
-rw-r--r--app/javascript/mastodon/locales/bn.json753
-rw-r--r--app/javascript/mastodon/locales/cs.json1
-rw-r--r--app/javascript/mastodon/locales/cy.json3
-rw-r--r--app/javascript/mastodon/locales/da.json3
-rw-r--r--app/javascript/mastodon/locales/de.json3
-rw-r--r--app/javascript/mastodon/locales/defaultMessages.json4
-rw-r--r--app/javascript/mastodon/locales/el.json3
-rw-r--r--app/javascript/mastodon/locales/eo.json3
-rw-r--r--app/javascript/mastodon/locales/es.json3
-rw-r--r--app/javascript/mastodon/locales/eu.json3
-rw-r--r--app/javascript/mastodon/locales/fa.json3
-rw-r--r--app/javascript/mastodon/locales/fi.json3
-rw-r--r--app/javascript/mastodon/locales/gl.json3
-rw-r--r--app/javascript/mastodon/locales/he.json3
-rw-r--r--app/javascript/mastodon/locales/hi.json3
-rw-r--r--app/javascript/mastodon/locales/hr.json3
-rw-r--r--app/javascript/mastodon/locales/hu.json3
-rw-r--r--app/javascript/mastodon/locales/hy.json3
-rw-r--r--app/javascript/mastodon/locales/id.json3
-rw-r--r--app/javascript/mastodon/locales/io.json3
-rw-r--r--app/javascript/mastodon/locales/it.json3
-rw-r--r--app/javascript/mastodon/locales/ka.json3
-rw-r--r--app/javascript/mastodon/locales/kk.json3
-rw-r--r--app/javascript/mastodon/locales/ko.json3
-rw-r--r--app/javascript/mastodon/locales/lv.json3
-rw-r--r--app/javascript/mastodon/locales/ms.json3
-rw-r--r--app/javascript/mastodon/locales/nl.json2
-rw-r--r--app/javascript/mastodon/locales/no.json3
-rw-r--r--app/javascript/mastodon/locales/oc.json3
-rw-r--r--app/javascript/mastodon/locales/pl.json3
-rw-r--r--app/javascript/mastodon/locales/pt-BR.json3
-rw-r--r--app/javascript/mastodon/locales/pt.json3
-rw-r--r--app/javascript/mastodon/locales/ro.json3
-rw-r--r--app/javascript/mastodon/locales/ru.json3
-rw-r--r--app/javascript/mastodon/locales/sk.json3
-rw-r--r--app/javascript/mastodon/locales/sl.json3
-rw-r--r--app/javascript/mastodon/locales/sq.json3
-rw-r--r--app/javascript/mastodon/locales/sr-Latn.json3
-rw-r--r--app/javascript/mastodon/locales/sr.json3
-rw-r--r--app/javascript/mastodon/locales/sv.json3
-rw-r--r--app/javascript/mastodon/locales/ta.json3
-rw-r--r--app/javascript/mastodon/locales/te.json3
-rw-r--r--app/javascript/mastodon/locales/th.json3
-rw-r--r--app/javascript/mastodon/locales/tr.json3
-rw-r--r--app/javascript/mastodon/locales/uk.json3
-rw-r--r--app/javascript/mastodon/locales/zh-CN.json3
-rw-r--r--app/javascript/mastodon/locales/zh-HK.json3
-rw-r--r--app/javascript/mastodon/locales/zh-TW.json3
-rw-r--r--app/javascript/mastodon/reducers/settings.js2
-rw-r--r--app/javascript/styles/mastodon/components.scss329
-rw-r--r--app/models/notification.rb8
-rw-r--r--app/workers/activitypub/delivery_worker.rb2
-rw-r--r--config/locales/sk.yml20
-rw-r--r--package.json4
-rw-r--r--spec/controllers/api/v1/notifications_controller_spec.rb66
-rw-r--r--streaming/index.js25
-rw-r--r--yarn.lock10
73 files changed, 904 insertions, 621 deletions
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 000000000..91ee92a2e
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,2 @@
+patreon: mastodon
+open_collective: mastodon
diff --git a/Gemfile b/Gemfile
index 6c7bef290..b4312f1ac 100644
--- a/Gemfile
+++ b/Gemfile
@@ -15,7 +15,7 @@ gem 'makara', '~> 0.4'
 gem 'pghero', '~> 2.2'
 gem 'dotenv-rails', '~> 2.7'
 
-gem 'aws-sdk-s3', '~> 1.39', require: false
+gem 'aws-sdk-s3', '~> 1.40', require: false
 gem 'fog-core', '<= 2.1.0'
 gem 'fog-openstack', '~> 0.3', require: false
 gem 'paperclip', '~> 6.0'
@@ -54,7 +54,7 @@ gem 'htmlentities', '~> 4.3'
 gem 'http', '~> 3.3'
 gem 'http_accept_language', '~> 2.1'
 gem 'http_parser.rb', '~> 0.6', git: 'https://github.com/tmm1/http_parser.rb', ref: '54b17ba8c7d8d20a16dfc65d1775241833219cf2'
-gem 'httplog', '~> 1.2'
+gem 'httplog', '~> 1.3'
 gem 'idn-ruby', require: 'idn'
 gem 'kaminari', '~> 1.1'
 gem 'link_header', '~> 0.0'
@@ -131,7 +131,7 @@ group :development do
   gem 'letter_opener', '~> 1.7'
   gem 'letter_opener_web', '~> 1.3'
   gem 'memory_profiler'
-  gem 'rubocop', '~> 0.69', require: false
+  gem 'rubocop', '~> 0.70', require: false
   gem 'brakeman', '~> 4.5', require: false
   gem 'bundler-audit', '~> 0.6', require: false
   gem 'scss_lint', '~> 0.58', require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index 4dacad5e4..4b29a2be8 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -76,17 +76,17 @@ GEM
     av (0.9.0)
       cocaine (~> 0.5.3)
     aws-eventstream (1.0.3)
-    aws-partitions (1.162.0)
-    aws-sdk-core (3.52.1)
+    aws-partitions (1.165.0)
+    aws-sdk-core (3.53.0)
       aws-eventstream (~> 1.0, >= 1.0.2)
       aws-partitions (~> 1.0)
       aws-sigv4 (~> 1.1)
       jmespath (~> 1.0)
-    aws-sdk-kms (1.20.0)
-      aws-sdk-core (~> 3, >= 3.52.1)
+    aws-sdk-kms (1.21.0)
+      aws-sdk-core (~> 3, >= 3.53.0)
       aws-sigv4 (~> 1.1)
-    aws-sdk-s3 (1.39.0)
-      aws-sdk-core (~> 3, >= 3.52.1)
+    aws-sdk-s3 (1.40.0)
+      aws-sdk-core (~> 3, >= 3.53.0)
       aws-sdk-kms (~> 1)
       aws-sigv4 (~> 1.0)
     aws-sigv4 (1.1.0)
@@ -129,14 +129,13 @@ GEM
       sshkit (~> 1.3)
     capistrano-yarn (2.0.2)
       capistrano (~> 3.0)
-    capybara (3.20.0)
+    capybara (3.20.2)
       addressable
       mini_mime (>= 0.1.3)
       nokogiri (~> 1.8)
       rack (>= 1.6.0)
       rack-test (>= 0.6.3)
       regexp_parser (~> 1.2)
-      uglifier
       xpath (~> 3.2)
     case_transform (0.2)
       activesupport
@@ -208,7 +207,6 @@ GEM
     et-orbi (1.1.6)
       tzinfo
     excon (0.62.0)
-    execjs (2.7.0)
     fabrication (2.20.2)
     faker (1.9.3)
       i18n (>= 0.7)
@@ -273,7 +271,7 @@ GEM
       domain_name (~> 0.5)
     http-form_data (2.1.1)
     http_accept_language (2.1.1)
-    httplog (1.2.2)
+    httplog (1.3.0)
       rack (>= 1.0)
       rainbow (>= 2.0.0)
     i18n (1.6.0)
@@ -324,7 +322,7 @@ GEM
       letter_opener (~> 1.0)
       railties (>= 3.2)
     link_header (0.0.8)
-    lograge (0.11.0)
+    lograge (0.11.1)
       actionpack (>= 4)
       activesupport (>= 4)
       railties (>= 4)
@@ -532,7 +530,7 @@ GEM
       rspec-core (~> 3.0, >= 3.0.0)
       sidekiq (>= 2.4.0)
     rspec-support (3.8.0)
-    rubocop (0.69.0)
+    rubocop (0.70.0)
       jaro_winkler (~> 1.5.1)
       parallel (~> 1.10)
       parser (>= 2.6)
@@ -630,8 +628,6 @@ GEM
       thread_safe (~> 0.1)
     tzinfo-data (1.2019.1)
       tzinfo (>= 1.0.0)
-    uglifier (4.1.20)
-      execjs (>= 0.3.0, < 3)
     unf (0.1.4)
       unf_ext
     unf_ext (0.0.7.5)
@@ -665,7 +661,7 @@ DEPENDENCIES
   active_record_query_trace (~> 1.6)
   addressable (~> 2.6)
   annotate (~> 2.7)
-  aws-sdk-s3 (~> 1.39)
+  aws-sdk-s3 (~> 1.40)
   better_errors (~> 2.5)
   binding_of_caller (~> 0.7)
   blurhash (~> 0.1)
@@ -705,7 +701,7 @@ DEPENDENCIES
   http (~> 3.3)
   http_accept_language (~> 2.1)
   http_parser.rb (~> 0.6)!
-  httplog (~> 1.2)
+  httplog (~> 1.3)
   i18n-tasks (~> 0.9)
   idn-ruby
   iso-639
@@ -757,7 +753,7 @@ DEPENDENCIES
   rqrcode (~> 0.10)
   rspec-rails (~> 3.8)
   rspec-sidekiq (~> 3.0)
-  rubocop (~> 0.69)
+  rubocop (~> 0.70)
   sanitize (~> 5.0)
   scss_lint (~> 0.58)
   sidekiq (~> 5.2)
diff --git a/app/controllers/api/v1/notifications_controller.rb b/app/controllers/api/v1/notifications_controller.rb
index 3b492c516..c91753ae7 100644
--- a/app/controllers/api/v1/notifications_controller.rb
+++ b/app/controllers/api/v1/notifications_controller.rb
@@ -53,7 +53,7 @@ class Api::V1::NotificationsController < Api::BaseController
   end
 
   def browserable_account_notifications
-    current_account.notifications.browserable(exclude_types)
+    current_account.notifications.browserable(exclude_types, from_account)
   end
 
   def target_statuses_from_notifications
@@ -90,6 +90,10 @@ class Api::V1::NotificationsController < Api::BaseController
     val
   end
 
+  def from_account
+    params[:account_id]
+  end
+
   def pagination_params(core_params)
     params.slice(:limit, :exclude_types).permit(:limit, exclude_types: []).merge(core_params)
   end
diff --git a/app/controllers/concerns/signature_verification.rb b/app/controllers/concerns/signature_verification.rb
index 91566c4fa..90a57197c 100644
--- a/app/controllers/concerns/signature_verification.rb
+++ b/app/controllers/concerns/signature_verification.rb
@@ -43,13 +43,7 @@ module SignatureVerification
       return
     end
 
-    account_stoplight = Stoplight("source:#{request.ip}") { account_from_key_id(signature_params['keyId']) }
-      .with_fallback { nil }
-      .with_threshold(1)
-      .with_cool_off_time(5.minutes.seconds)
-      .with_error_handler { |error, handle| error.is_a?(HTTP::Error) ? handle.call(error) : raise(error) }
-
-    account = account_stoplight.run
+    account = account_from_key_id(signature_params['keyId'])
 
     if account.nil?
       @signature_verification_failure_reason = "Public key not found for key #{signature_params['keyId']}"
@@ -62,13 +56,7 @@ module SignatureVerification
 
     return account unless verify_signature(account, signature, compare_signed_string).nil?
 
-    account_stoplight = Stoplight("source:#{request.ip}") { account.possibly_stale? ? account.refresh! : account_refresh_key(account) }
-      .with_fallback { nil }
-      .with_threshold(1)
-      .with_cool_off_time(5.minutes.seconds)
-      .with_error_handler { |error, handle| error.is_a?(HTTP::Error) ? handle.call(error) : raise(error) }
-
-    account = account_stoplight.run
+    account = stoplight_wrap_request { account.possibly_stale? ? account.refresh! : account_refresh_key(account) }
 
     if account.nil?
       @signature_verification_failure_reason = "Public key not found for key #{signature_params['keyId']}"
@@ -136,14 +124,23 @@ module SignatureVerification
 
   def account_from_key_id(key_id)
     if key_id.start_with?('acct:')
-      ResolveAccountService.new.call(key_id.gsub(/\Aacct:/, ''))
+      stoplight_wrap_request { ResolveAccountService.new.call(key_id.gsub(/\Aacct:/, '')) }
     elsif !ActivityPub::TagManager.instance.local_uri?(key_id)
       account   = ActivityPub::TagManager.instance.uri_to_resource(key_id, Account)
-      account ||= ActivityPub::FetchRemoteKeyService.new.call(key_id, id: false)
+      account ||= stoplight_wrap_request { ActivityPub::FetchRemoteKeyService.new.call(key_id, id: false) }
       account
     end
   end
 
+  def stoplight_wrap_request(&block)
+    Stoplight("source:#{request.remote_ip}", &block)
+      .with_fallback { nil }
+      .with_threshold(1)
+      .with_cool_off_time(5.minutes.seconds)
+      .with_error_handler { |error, handle| error.is_a?(HTTP::Error) ? handle.call(error) : raise(error) }
+      .run
+  end
+
   def account_refresh_key(account)
     return if account.local? || !account.activitypub?
     ActivityPub::FetchRemoteAccountService.new.call(account.uri, only_key: true)
diff --git a/app/javascript/flavours/glitch/styles/components/emoji.scss b/app/javascript/flavours/glitch/styles/components/emoji.scss
index dd386d698..160e9d811 100644
--- a/app/javascript/flavours/glitch/styles/components/emoji.scss
+++ b/app/javascript/flavours/glitch/styles/components/emoji.scss
@@ -17,6 +17,7 @@
   box-shadow: 4px 4px 6px rgba($base-shadow-color, 0.4);
   border-radius: 4px;
   margin-top: 5px;
+  z-index: 2;
 
   .emoji-mart-scroll {
     transition: opacity 200ms ease;
diff --git a/app/javascript/mastodon/components/autosuggest_input.js b/app/javascript/mastodon/components/autosuggest_input.js
index bb8ab60db..4b4aa8f0e 100644
--- a/app/javascript/mastodon/components/autosuggest_input.js
+++ b/app/javascript/mastodon/components/autosuggest_input.js
@@ -49,7 +49,7 @@ export default class AutosuggestInput extends ImmutablePureComponent {
     autoFocus: PropTypes.bool,
     className: PropTypes.string,
     id: PropTypes.string,
-    searchTokens: PropTypes.list,
+    searchTokens: ImmutablePropTypes.list,
     maxLength: PropTypes.number,
   };
 
diff --git a/app/javascript/mastodon/features/compose/index.js b/app/javascript/mastodon/features/compose/index.js
index fff329106..0731abcf4 100644
--- a/app/javascript/mastodon/features/compose/index.js
+++ b/app/javascript/mastodon/features/compose/index.js
@@ -106,12 +106,12 @@ class Compose extends React.PureComponent {
         <div className='drawer__pager'>
           {!isSearchPage && <div className='drawer__inner' onFocus={this.onFocus}>
             <NavigationContainer onClose={this.onBlur} />
+
             <ComposeFormContainer />
-            {multiColumn && (
-              <div className='drawer__inner__mastodon'>
-                <img alt='' draggable='false' src={mascot || elephantUIPlane} />
-              </div>
-            )}
+
+            <div className='drawer__inner__mastodon'>
+              <img alt='' draggable='false' src={mascot || elephantUIPlane} />
+            </div>
           </div>}
 
           <Motion defaultStyle={{ x: isSearchPage ? 0 : -100 }} style={{ x: spring(showSearch || isSearchPage ? 0 : -100, { stiffness: 210, damping: 20 }) }}>
diff --git a/app/javascript/mastodon/features/getting_started/index.js b/app/javascript/mastodon/features/getting_started/index.js
index 77c27ac6b..a671578a0 100644
--- a/app/javascript/mastodon/features/getting_started/index.js
+++ b/app/javascript/mastodon/features/getting_started/index.js
@@ -8,11 +8,13 @@ import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import { me, invitesEnabled, version, profile_directory, repository, source_url } from '../../initial_state';
-import { fetchFollowRequests } from '../../actions/accounts';
+import { fetchFollowRequests } from 'mastodon/actions/accounts';
+import { changeSetting } from 'mastodon/actions/settings';
 import { List as ImmutableList } from 'immutable';
 import { Link } from 'react-router-dom';
 import NavigationBar from '../compose/components/navigation_bar';
 import Icon from 'mastodon/components/icon';
+import Toggle from 'react-toggle';
 
 const messages = defineMessages({
   home_timeline: { id: 'tabs_bar.home', defaultMessage: 'Home' },
@@ -39,10 +41,12 @@ const messages = defineMessages({
 const mapStateToProps = state => ({
   myAccount: state.getIn(['accounts', me]),
   unreadFollowRequests: state.getIn(['user_lists', 'follow_requests', 'items'], ImmutableList()).size,
+  forceSingleColumn: state.getIn(['settings', 'forceSingleColumn'], false),
 });
 
 const mapDispatchToProps = dispatch => ({
   fetchFollowRequests: () => dispatch(fetchFollowRequests()),
+  changeForceSingleColumn: checked => dispatch(changeSetting(['forceSingleColumn'], checked)),
 });
 
 const badgeDisplay = (number, limit) => {
@@ -67,6 +71,8 @@ class GettingStarted extends ImmutablePureComponent {
     fetchFollowRequests: PropTypes.func.isRequired,
     unreadFollowRequests: PropTypes.number,
     unreadNotifications: PropTypes.number,
+    forceSingleColumn: PropTypes.bool,
+    changeForceSingleColumn: PropTypes.func.isRequired,
   };
 
   componentDidMount () {
@@ -77,8 +83,12 @@ class GettingStarted extends ImmutablePureComponent {
     }
   }
 
+  handleForceSingleColumnChange = ({ target }) => {
+    this.props.changeForceSingleColumn(target.checked);
+  }
+
   render () {
-    const { intl, myAccount, multiColumn, unreadFollowRequests } = this.props;
+    const { intl, myAccount, multiColumn, unreadFollowRequests, forceSingleColumn } = this.props;
 
     const navItems = [];
     let i = 1;
@@ -177,6 +187,11 @@ class GettingStarted extends ImmutablePureComponent {
             </p>
           </div>
         </div>
+
+        <label className='navigational-toggle'>
+          <FormattedMessage id='getting_started.use_simple_layout' defaultMessage='Use simple layout' />
+          <Toggle checked={forceSingleColumn} onChange={this.handleForceSingleColumnChange} />
+        </label>
       </Column>
     );
   }
diff --git a/app/javascript/mastodon/features/ui/components/columns_area.js b/app/javascript/mastodon/features/ui/components/columns_area.js
index 63feeac45..47cea3e3a 100644
--- a/app/javascript/mastodon/features/ui/components/columns_area.js
+++ b/app/javascript/mastodon/features/ui/components/columns_area.js
@@ -5,7 +5,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 
 import ReactSwipeableViews from 'react-swipeable-views';
-import { links, getIndex, getLink } from './tabs_bar';
+import TabsBar, { links, getIndex, getLink } from './tabs_bar';
 import { Link } from 'react-router-dom';
 
 import BundleContainer from '../containers/bundle_container';
@@ -139,7 +139,7 @@ class ColumnsArea extends ImmutablePureComponent {
       <ColumnLoading title={title} icon={icon} />;
 
     return (
-      <div className='columns-area' key={index}>
+      <div className='columns-area columns-area--mobile' key={index}>
         {view}
       </div>
     );
@@ -164,13 +164,17 @@ class ColumnsArea extends ImmutablePureComponent {
       const floatingActionButton = shouldHideFAB(this.context.router.history.location.pathname) ? null : <Link key='floating-action-button' to='/statuses/new' className='floating-action-button' aria-label={intl.formatMessage(messages.publish)}><Icon id='pencil' /></Link>;
 
       return columnIndex !== -1 ? [
+        <TabsBar key='tabs' />,
+
         <ReactSwipeableViews key='content' index={columnIndex} onChangeIndex={this.handleSwipe} onTransitionEnd={this.handleAnimationEnd} animateTransitions={shouldAnimate} springConfig={{ duration: '400ms', delay: '0s', easeFunction: 'ease' }} style={{ height: '100%' }}>
           {links.map(this.renderView)}
         </ReactSwipeableViews>,
 
         floatingActionButton,
       ] : [
-        <div className='columns-area'>{children}</div>,
+        <TabsBar key='tabs' />,
+
+        <div key='content' className='columns-area columns-area--mobile'>{children}</div>,
 
         floatingActionButton,
       ];
diff --git a/app/javascript/mastodon/features/ui/components/notifications_counter_icon.js b/app/javascript/mastodon/features/ui/components/notifications_counter_icon.js
new file mode 100644
index 000000000..deb907866
--- /dev/null
+++ b/app/javascript/mastodon/features/ui/components/notifications_counter_icon.js
@@ -0,0 +1,23 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import Icon from 'mastodon/components/icon';
+
+const mapStateToProps = state => ({
+  count: state.getIn(['notifications', 'unread']),
+});
+
+const formatNumber = num => num > 99 ? '99+' : num;
+
+const NotificationsCounterIcon = ({ count }) => (
+  <i className='icon-with-badge'>
+    <Icon id='bell' fixedWidth />
+    {count > 0 && <i className='icon-with-badge__badge'>{formatNumber(count)}</i>}
+  </i>
+);
+
+NotificationsCounterIcon.propTypes = {
+  count: PropTypes.number.isRequired,
+};
+
+export default connect(mapStateToProps)(NotificationsCounterIcon);
diff --git a/app/javascript/mastodon/features/ui/components/tabs_bar.js b/app/javascript/mastodon/features/ui/components/tabs_bar.js
index 1b2bb7781..979b782bb 100644
--- a/app/javascript/mastodon/features/ui/components/tabs_bar.js
+++ b/app/javascript/mastodon/features/ui/components/tabs_bar.js
@@ -5,10 +5,11 @@ import { FormattedMessage, injectIntl } from 'react-intl';
 import { debounce } from 'lodash';
 import { isUserTouching } from '../../../is_mobile';
 import Icon from 'mastodon/components/icon';
+import NotificationsCounterIcon from './notifications_counter_icon';
 
 export const links = [
   <NavLink className='tabs-bar__link primary' to='/timelines/home' data-preview-title-id='column.home' data-preview-icon='home' ><Icon id='home' fixedWidth /><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></NavLink>,
-  <NavLink className='tabs-bar__link primary' to='/notifications' data-preview-title-id='column.notifications' data-preview-icon='bell' ><Icon id='bell' fixedWidth /><FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /></NavLink>,
+  <NavLink className='tabs-bar__link primary' to='/notifications' data-preview-title-id='column.notifications' data-preview-icon='bell' ><NotificationsCounterIcon /><FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /></NavLink>,
 
   <NavLink className='tabs-bar__link secondary' to='/timelines/public/local' data-preview-title-id='column.community' data-preview-icon='users' ><Icon id='users' fixedWidth /><FormattedMessage id='tabs_bar.local_timeline' defaultMessage='Local' /></NavLink>,
   <NavLink className='tabs-bar__link secondary' exact to='/timelines/public' data-preview-title-id='column.public' data-preview-icon='globe' ><Icon id='globe' fixedWidth /><FormattedMessage id='tabs_bar.federated_timeline' defaultMessage='Federated' /></NavLink>,
diff --git a/app/javascript/mastodon/features/ui/index.js b/app/javascript/mastodon/features/ui/index.js
index 1fcea779d..6d5279157 100644
--- a/app/javascript/mastodon/features/ui/index.js
+++ b/app/javascript/mastodon/features/ui/index.js
@@ -7,7 +7,6 @@ import { Redirect, withRouter } from 'react-router-dom';
 import PropTypes from 'prop-types';
 import NotificationsContainer from './containers/notifications_container';
 import LoadingBarContainer from './containers/loading_bar_container';
-import TabsBar from './components/tabs_bar';
 import ModalContainer from './containers/modal_container';
 import { isMobile } from '../../is_mobile';
 import { debounce } from 'lodash';
@@ -63,6 +62,7 @@ const mapStateToProps = state => ({
   hasComposingText: state.getIn(['compose', 'text']).trim().length !== 0,
   hasMediaAttachments: state.getIn(['compose', 'media_attachments']).size > 0,
   dropdownMenuIsOpen: state.getIn(['dropdown_menu', 'openId']) !== null,
+  forceSingleColumn: state.getIn(['settings', 'forceSingleColumn'], false),
 });
 
 const keyMap = {
@@ -101,6 +101,7 @@ class SwitchingColumnsArea extends React.PureComponent {
     children: PropTypes.node,
     location: PropTypes.object,
     onLayoutChange: PropTypes.func.isRequired,
+    forceSingleColumn: PropTypes.bool,
   };
 
   state = {
@@ -139,12 +140,13 @@ class SwitchingColumnsArea extends React.PureComponent {
   }
 
   render () {
-    const { children } = this.props;
+    const { children, forceSingleColumn } = this.props;
     const { mobile } = this.state;
-    const redirect = mobile ? <Redirect from='/' to='/timelines/home' exact /> : <Redirect from='/' to='/getting-started' exact />;
+    const singleColumn = forceSingleColumn || mobile;
+    const redirect = singleColumn ? <Redirect from='/' to='/timelines/home' exact /> : <Redirect from='/' to='/getting-started' exact />;
 
     return (
-      <ColumnsAreaContainer ref={this.setRef} singleColumn={mobile}>
+      <ColumnsAreaContainer ref={this.setRef} singleColumn={singleColumn}>
         <WrappedSwitch>
           {redirect}
           <WrappedRoute path='/getting-started' component={GettingStarted} content={children} />
@@ -205,6 +207,7 @@ class UI extends React.PureComponent {
     location: PropTypes.object,
     intl: PropTypes.object.isRequired,
     dropdownMenuIsOpen: PropTypes.bool,
+    forceSingleColumn: PropTypes.bool,
   };
 
   state = {
@@ -453,7 +456,7 @@ class UI extends React.PureComponent {
 
   render () {
     const { draggingOver } = this.state;
-    const { children, isComposing, location, dropdownMenuIsOpen } = this.props;
+    const { children, isComposing, location, dropdownMenuIsOpen, forceSingleColumn } = this.props;
 
     const handlers = {
       help: this.handleHotkeyToggleHelp,
@@ -479,9 +482,7 @@ class UI extends React.PureComponent {
     return (
       <HotKeys keyMap={keyMap} handlers={handlers} ref={this.setHotkeysRef} attach={window} focused>
         <div className={classNames('ui', { 'is-composing': isComposing })} ref={this.setRef} style={{ pointerEvents: dropdownMenuIsOpen ? 'none' : null }}>
-          <TabsBar />
-
-          <SwitchingColumnsArea location={location} onLayoutChange={this.handleLayoutChange}>
+          <SwitchingColumnsArea location={location} onLayoutChange={this.handleLayoutChange} forceSingleColumn={forceSingleColumn}>
             {children}
           </SwitchingColumnsArea>
 
diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json
index e815d54d5..68c8835d1 100644
--- a/app/javascript/mastodon/locales/ar.json
+++ b/app/javascript/mastodon/locales/ar.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "إزالة هذا الخيار",
   "compose_form.publish": "بوّق",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "لقد تم تحديد هذه الصورة كحساسة",
   "compose_form.sensitive.unmarked": "لم يتم تحديد الصورة كحساسة",
   "compose_form.spoiler.marked": "إنّ النص مخفي وراء تحذير",
@@ -209,6 +210,7 @@
   "lightbox.close": "إغلاق",
   "lightbox.next": "التالي",
   "lightbox.previous": "العودة",
+  "lightbox.view_context": "View context",
   "lists.account.add": "أضف إلى القائمة",
   "lists.account.remove": "إحذف من القائمة",
   "lists.delete": "Delete list",
@@ -340,7 +342,6 @@
   "status.reply": "ردّ",
   "status.replyAll": "رُد على الخيط",
   "status.report": "إبلِغ عن @{name}",
-  "status.sensitive_toggle": "اضغط للعرض",
   "status.sensitive_warning": "محتوى حساس",
   "status.share": "مشاركة",
   "status.show_less": "إعرض أقلّ",
diff --git a/app/javascript/mastodon/locales/ast.json b/app/javascript/mastodon/locales/ast.json
index a983f63a4..57849c393 100644
--- a/app/javascript/mastodon/locales/ast.json
+++ b/app/javascript/mastodon/locales/ast.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Toot",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Media is marked as sensitive",
   "compose_form.sensitive.unmarked": "Media is not marked as sensitive",
   "compose_form.spoiler.marked": "El testu nun va anubrise darrera d'una alvertencia",
@@ -209,6 +210,7 @@
   "lightbox.close": "Close",
   "lightbox.next": "Siguiente",
   "lightbox.previous": "Previous",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Amestar a la llista",
   "lists.account.remove": "Desaniciar de la llista",
   "lists.delete": "Desaniciar la llista",
@@ -340,7 +342,6 @@
   "status.reply": "Responder",
   "status.replyAll": "Reply to thread",
   "status.report": "Report @{name}",
-  "status.sensitive_toggle": "Fai clic pa velu",
   "status.sensitive_warning": "Conteníu sensible",
   "status.share": "Share",
   "status.show_less": "Amosar menos",
diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json
index 36a08b264..7836146cd 100644
--- a/app/javascript/mastodon/locales/bg.json
+++ b/app/javascript/mastodon/locales/bg.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Раздумай",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Media is marked as sensitive",
   "compose_form.sensitive.unmarked": "Media is not marked as sensitive",
   "compose_form.spoiler.marked": "Text is hidden behind warning",
@@ -209,6 +210,7 @@
   "lightbox.close": "Затвори",
   "lightbox.next": "Next",
   "lightbox.previous": "Previous",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Add to list",
   "lists.account.remove": "Remove from list",
   "lists.delete": "Delete list",
@@ -340,7 +342,6 @@
   "status.reply": "Отговор",
   "status.replyAll": "Reply to thread",
   "status.report": "Report @{name}",
-  "status.sensitive_toggle": "Покажи",
   "status.sensitive_warning": "Деликатно съдържание",
   "status.share": "Share",
   "status.show_less": "Show less",
diff --git a/app/javascript/mastodon/locales/bn.json b/app/javascript/mastodon/locales/bn.json
index 338e49f81..bdf952d3a 100644
--- a/app/javascript/mastodon/locales/bn.json
+++ b/app/javascript/mastodon/locales/bn.json
@@ -1,384 +1,385 @@
 {
-  "account.add_or_remove_from_list": "লিস্টে আরো যুক্ত বা মুছে ফেলুন",
+  "account.add_or_remove_from_list": "তালিকাতে আরো যুক্ত বা মুছে ফেলুন",
   "account.badges.bot": "রোবট",
-  "account.block": "@{name} কে বন্ধ করুন",
+  "account.block": "@{name} বন্ধ করুন",
   "account.block_domain": "{domain} থেকে সব সরিয়ে ফেলুন",
   "account.blocked": "বন্ধ করা হয়েছে",
-  "account.direct": "@{name}কে সরকারি পাঠান",
-  "account.domain_blocked": "বেবিসিটটি সরানো আছে",
-  "account.edit_profile": "Edit profile",
-  "account.endorse": "Feature on profile",
-  "account.follow": "Follow",
-  "account.followers": "Followers",
-  "account.followers.empty": "No one follows this user yet.",
-  "account.follows": "Follows",
-  "account.follows.empty": "This user doesn't follow anyone yet.",
-  "account.follows_you": "Follows you",
-  "account.hide_reblogs": "Hide boosts from @{name}",
-  "account.link_verified_on": "Ownership of this link was checked on {date}",
-  "account.locked_info": "This account privacy status is set to locked. The owner manually reviews who can follow them.",
-  "account.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. Click to cancel follow request",
-  "account.share": "Share @{name}'s profile",
-  "account.show_reblogs": "Show boosts from @{name}",
-  "account.unblock": "Unblock @{name}",
-  "account.unblock_domain": "Unhide {domain}",
-  "account.unendorse": "Don't feature on profile",
-  "account.unfollow": "Unfollow",
-  "account.unmute": "Unmute @{name}",
-  "account.unmute_notifications": "Unmute notifications from @{name}",
-  "alert.unexpected.message": "An unexpected error occurred.",
-  "alert.unexpected.title": "Oops!",
-  "boost_modal.combo": "You can press {combo} to skip this next time",
-  "bundle_column_error.body": "Something went wrong while loading this component.",
-  "bundle_column_error.retry": "Try again",
-  "bundle_column_error.title": "Network error",
-  "bundle_modal_error.close": "Close",
-  "bundle_modal_error.message": "Something went wrong while loading this component.",
-  "bundle_modal_error.retry": "Try again",
-  "column.blocks": "Blocked users",
-  "column.community": "Local timeline",
-  "column.direct": "Direct messages",
-  "column.domain_blocks": "Hidden domains",
-  "column.favourites": "Favourites",
-  "column.follow_requests": "Follow requests",
-  "column.home": "Home",
-  "column.lists": "Lists",
-  "column.mutes": "Muted users",
-  "column.notifications": "Notifications",
-  "column.pins": "Pinned toot",
-  "column.public": "Federated timeline",
-  "column_back_button.label": "Back",
-  "column_header.hide_settings": "Hide settings",
-  "column_header.moveLeft_settings": "Move column to the left",
-  "column_header.moveRight_settings": "Move column to the right",
-  "column_header.pin": "Pin",
-  "column_header.show_settings": "Show settings",
-  "column_header.unpin": "Unpin",
-  "column_subheading.settings": "Settings",
-  "community.column_settings.media_only": "Media Only",
-  "compose_form.direct_message_warning": "This toot will only be sent to all the mentioned users.",
-  "compose_form.direct_message_warning_learn_more": "Learn more",
-  "compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
-  "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.",
-  "compose_form.lock_disclaimer.lock": "locked",
-  "compose_form.placeholder": "What is on your mind?",
-  "compose_form.poll.add_option": "Add a choice",
-  "compose_form.poll.duration": "Poll duration",
-  "compose_form.poll.option_placeholder": "Choice {number}",
-  "compose_form.poll.remove_option": "Remove this choice",
-  "compose_form.publish": "Toot",
+  "account.direct": "@{name}কে সরকারি লিখুন",
+  "account.domain_blocked": "ওয়েবসাইট সরিয়ে ফেলা হয়েছে",
+  "account.edit_profile": "নিজের পাতা সম্পাদনা করুন",
+  "account.endorse": "নিজের পাতায় দেখান",
+  "account.follow": "অনুসরণ করুন",
+  "account.followers": "অনুসরণকারক",
+  "account.followers.empty": "এই ব্যবহারকারীকে কেও এখনো অনুসরণ করে না।",
+  "account.follows": "যাদেরকে অনুসরণ করেন",
+  "account.follows.empty": "এই ব্যবহারকারী কাওকে এখনো অনুসরণ করেন না।",
+  "account.follows_you": "আপনাকে অনুসরণ করে",
+  "account.hide_reblogs": "@{name}র সমর্থনগুলি সরিয়ে ফেলুন",
+  "account.link_verified_on": "এই লিংকের মালিকানা চেক করা হয়েছে {date} তারিকে",
+  "account.locked_info": "এই নিবন্ধনের গোপনীয়তার ক্ষেত্র তালা দেওয়া আছে। নিবন্ধনকারী অনুসরণ করার অনুমতি যাদেরকে দেবেন, শুধু তারাই অনুসরণ করতে পারবেন।",
+  "account.media": "ছবি বা ভিডিও",
+  "account.mention": "@{name} কে উল্লেখ করুন",
+  "account.moved_to": "{name} চলে গেছে এখানে:",
+  "account.mute": "@{name}র কার্যক্রম সরিয়ে ফেলুন",
+  "account.mute_notifications": "@{name}র প্রজ্ঞাপন আপনার কাছ থেকে সরিয়ে ফেলুন",
+  "account.muted": "সরানো আছে",
+  "account.posts": "টুট",
+  "account.posts_with_replies": "টুট এবং মতামত",
+  "account.report": "@{name}কে রিপোর্ট করে দিন",
+  "account.requested": "অনুমতির অপেক্ষায় আছে। অনুসরণ করার অনুরোধ বাতিল করতে এখানে ক্লিক করুন",
+  "account.share": "@{name}র পাতা অন্যদের দেখান",
+  "account.show_reblogs": "@{name}র সমর্থনগুলো দেখুন",
+  "account.unblock": "@{name}র কার্যকলাপ আবার দেখুন",
+  "account.unblock_domain": "{domain}থেকে আবার দেখুন",
+  "account.unendorse": "নিজের পাতায় এটা দেখতে চান না",
+  "account.unfollow": "অনুসরণ বন্ধ করুন",
+  "account.unmute": "@{name}র কার্যকলাপ আবার দেখুন",
+  "account.unmute_notifications": "@{name}র প্রজ্ঞাপন দেওয়ার অনুমতি দিন",
+  "alert.unexpected.message": "অপ্রত্যাশিত একটি সমস্যা হয়েছে।",
+  "alert.unexpected.title": "ওহো!",
+  "boost_modal.combo": "পরেরবার আপনি {combo} চাপ দিলে এটার শেষে চলে যেতে পারবেন",
+  "bundle_column_error.body": "এই অংশটি দেখতে যেয়ে কোনো সমস্যা হয়েছে।",
+  "bundle_column_error.retry": "আবার চেষ্টা করুন",
+  "bundle_column_error.title": "নেটওয়ার্কের সমস্যা হচ্ছে",
+  "bundle_modal_error.close": "বন্ধ করুন",
+  "bundle_modal_error.message": "এই অংশটি দেখতে যেয়ে কোনো সমস্যা হয়েছে।",
+  "bundle_modal_error.retry": "আবার চেষ্টা করুন",
+  "column.blocks": "যাদের বন্ধ করে রাখা হয়েছে",
+  "column.community": "স্থানীয় সময়সারি",
+  "column.direct": "সরাসরি লেখা",
+  "column.domain_blocks": "সরিয়ে ফেলা ওয়েবসাইট",
+  "column.favourites": "পছন্দের গুলো",
+  "column.follow_requests": "অনুসরণের অনুমতি চেয়েছে যারা",
+  "column.home": "বাড়ি",
+  "column.lists": "তালিকাগুলো",
+  "column.mutes": "যাদের কার্যক্রম দেখা বন্ধ আছে",
+  "column.notifications": "প্রজ্ঞাপনগুলো",
+  "column.pins": "পিন করা টুট",
+  "column.public": "যুক্ত সময়রেখা",
+  "column_back_button.label": "পেছনে",
+  "column_header.hide_settings": "সেটিংগুলো সরান",
+  "column_header.moveLeft_settings": "কলমটা বামে সরান",
+  "column_header.moveRight_settings": "কলমটা ডানে সরান",
+  "column_header.pin": "পিন দিয়ে রাখুন",
+  "column_header.show_settings": "সেটিং দেখান",
+  "column_header.unpin": "পিন খুলুন",
+  "column_subheading.settings": "সেটিং",
+  "community.column_settings.media_only": "শুধুমাত্র ছবি বা ভিডিও",
+  "compose_form.direct_message_warning": "শুধুমাত্র যাদেরকে উল্লেখ করা হয়েছে তাদেরকেই এই টুটটি পাঠানো হবে ।",
+  "compose_form.direct_message_warning_learn_more": "আরো জানুন",
+  "compose_form.hashtag_warning": "কোনো হ্যাশট্যাগের ভেতরে এই টুটটি থাকবেনা কারণ এটি তালিকাবহির্ভূত। শুধুমাত্র প্রকাশ্য ঠোটগুলো হ্যাশট্যাগের ভেতরে খুঁজে পাওয়া যাবে।",
+  "compose_form.lock_disclaimer": "আপনার নিবন্ধনে তালা দেওয়া নেই, যে কেও আপনাকে অনুসরণ করতে পারবে এবং অনুশারকদের জন্য লেখা দেখতে পারবে।",
+  "compose_form.lock_disclaimer.lock": "তালা দেওয়া",
+  "compose_form.placeholder": "আপনি কি ভাবছেন ?",
+  "compose_form.poll.add_option": "আরেকটি বিকল্প যোগ করুন",
+  "compose_form.poll.duration": "ভোটগ্রহনের সময়",
+  "compose_form.poll.option_placeholder": "বিকল্প {number}",
+  "compose_form.poll.remove_option": "এই বিকল্পটি মুছে ফেলুন",
+  "compose_form.publish": "টুট",
   "compose_form.publish_loud": "{publish}!",
-  "compose_form.sensitive.marked": "Media is marked as sensitive",
-  "compose_form.sensitive.unmarked": "Media is not marked as sensitive",
-  "compose_form.spoiler.marked": "Text is hidden behind warning",
-  "compose_form.spoiler.unmarked": "Text is not hidden",
-  "compose_form.spoiler_placeholder": "Write your warning here",
-  "confirmation_modal.cancel": "Cancel",
-  "confirmations.block.block_and_report": "Block & Report",
-  "confirmations.block.confirm": "Block",
-  "confirmations.block.message": "Are you sure you want to block {name}?",
-  "confirmations.delete.confirm": "Delete",
-  "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.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.mute.confirm": "Mute",
-  "confirmations.mute.message": "Are you sure you want to mute {name}?",
-  "confirmations.redraft.confirm": "Delete & redraft",
-  "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.",
-  "confirmations.reply.confirm": "Reply",
-  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
-  "confirmations.unfollow.confirm": "Unfollow",
-  "confirmations.unfollow.message": "Are you sure you want to unfollow {name}?",
-  "embed.instructions": "Embed this status on your website by copying the code below.",
-  "embed.preview": "Here is what it will look like:",
-  "emoji_button.activity": "Activity",
-  "emoji_button.custom": "Custom",
-  "emoji_button.flags": "Flags",
-  "emoji_button.food": "Food & Drink",
-  "emoji_button.label": "Insert emoji",
-  "emoji_button.nature": "Nature",
-  "emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
-  "emoji_button.objects": "Objects",
-  "emoji_button.people": "People",
-  "emoji_button.recent": "Frequently used",
-  "emoji_button.search": "Search...",
-  "emoji_button.search_results": "Search results",
-  "emoji_button.symbols": "Symbols",
-  "emoji_button.travel": "Travel & Places",
-  "empty_column.account_timeline": "No toots here!",
-  "empty_column.account_unavailable": "Profile unavailable",
-  "empty_column.blocks": "You haven't blocked any users yet.",
-  "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
-  "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
-  "empty_column.domain_blocks": "There are no hidden domains yet.",
-  "empty_column.favourited_statuses": "You don't have any favourite toots yet. When you favourite one, it will show up here.",
-  "empty_column.favourites": "No one has favourited this toot yet. When someone does, they will show up here.",
-  "empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.",
-  "empty_column.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.public_timeline": "the public timeline",
-  "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.public": "There is nothing here! Write something publicly, or manually follow users from other servers to fill it up",
-  "follow_request.authorize": "Authorize",
-  "follow_request.reject": "Reject",
-  "getting_started.developers": "Developers",
-  "getting_started.directory": "Profile directory",
-  "getting_started.documentation": "Documentation",
-  "getting_started.heading": "Getting started",
-  "getting_started.invite": "Invite people",
-  "getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}.",
-  "getting_started.security": "Security",
-  "getting_started.terms": "Terms of service",
-  "hashtag.column_header.tag_mode.all": "and {additional}",
-  "hashtag.column_header.tag_mode.any": "or {additional}",
-  "hashtag.column_header.tag_mode.none": "without {additional}",
-  "hashtag.column_settings.select.no_options_message": "No suggestions found",
-  "hashtag.column_settings.select.placeholder": "Enter hashtags…",
-  "hashtag.column_settings.tag_mode.all": "All of these",
-  "hashtag.column_settings.tag_mode.any": "Any of these",
-  "hashtag.column_settings.tag_mode.none": "None of these",
-  "hashtag.column_settings.tag_toggle": "Include additional tags in this column",
-  "home.column_settings.basic": "Basic",
-  "home.column_settings.show_reblogs": "Show boosts",
-  "home.column_settings.show_replies": "Show replies",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
+  "compose_form.sensitive.marked": "এই ছবি বা ভিডিওটি সংবেদনশীল হিসেবে চিহ্নিত করা হয়েছে",
+  "compose_form.sensitive.unmarked": "এই ছবি বা ভিডিওটি সংবেদনশীল হিসেবে চিহ্নিত করা হয়নি",
+  "compose_form.spoiler.marked": "লেখাটি সাবধানতার পেছনে লুকানো আছে",
+  "compose_form.spoiler.unmarked": "লেখাটি লুকানো নেই",
+  "compose_form.spoiler_placeholder": "আপনার সাবধানতা এখানে লিখুন",
+  "confirmation_modal.cancel": "বাতিল করুন",
+  "confirmations.block.block_and_report": "বন্ধ করুন এবং রিপোর্ট করুন",
+  "confirmations.block.confirm": "বন্ধ করুন",
+  "confirmations.block.message": "আপনি কি নিশ্চিত {name} কে বন্ধ করতে চান ?",
+  "confirmations.delete.confirm": "মুছে ফেলুন",
+  "confirmations.delete.message": "আপনি কি নিশ্চিত যে এই লেখাটি মুছে ফেলতে চান ?",
+  "confirmations.delete_list.confirm": "মুছে ফেলুন",
+  "confirmations.delete_list.message": "আপনি কি নিশ্চিত যে আপনি এই তালিকাটি স্থায়িভাবে মুছে ফেলতে চান ?",
+  "confirmations.domain_block.confirm": "এই ওয়েবসাইট থেকে সব সরান",
+  "confirmations.domain_block.message": "আপনি কি সত্যি সত্যি নিশ্চিত যে {domain} ওয়েবসাইট থেকে সব সরাতে চান ? সাধারণত কিছু লক্ষ্যবস্তু বন্ধ এবং সরানোযা যথেষ্ট। নিশ্চিত করলে ওই ওয়েবসাইট থেকে কোনোকিছু কোনখানে দেখবেন না। যারা আপনাকে অনুসরণ করে ওই ওয়েবসাইট থেকে তাদেরকেও মুছে ফেলা হবে।",
+  "confirmations.mute.confirm": "সরিয়ে ফেলুন",
+  "confirmations.mute.message": "আপনি কি নিশ্চিত {name} সরিয়ে ফেলতে চান ?",
+  "confirmations.redraft.confirm": "মুছে ফেলুন এবং আবার সম্পাদন করুন",
+  "confirmations.redraft.message": "আপনি কি নিশ্চিত এটি মুছে ফেলে  এবং আবার সম্পাদন করতে চান ? এটাতে যা পছন্দিত, সমর্থন বা মতামত আছে সেগুলো নতুন লেখার সাথে যুক্ত থাকবে না।",
+  "confirmations.reply.confirm": "মতামত",
+  "confirmations.reply.message": "এখন মতামত লিখতে গেলে আপনার এখন যেটা লিখছেন সেটা মুছে যাবে। আপনি নি নিশ্চিত এটা করতে চান ?",
+  "confirmations.unfollow.confirm": "অনুসরণ বন্ধ করুন",
+  "confirmations.unfollow.message": "আপনি কি নিশ্চিত {name} কে আর অনুসরণ করতে চান না ?",
+  "embed.instructions": "এই লেখাটি আপনার ওয়েবসাইটে যুক্ত করতে নিচের কোডটি বেবহার করুন।",
+  "embed.preview": "সেটা দেখতে এরকম হবে:",
+  "emoji_button.activity": "কার্যকলাপ",
+  "emoji_button.custom": "প্রথা",
+  "emoji_button.flags": "পতাকা",
+  "emoji_button.food": "খাদ্য ও পানীয়",
+  "emoji_button.label": "এমজি যুক্ত করুন",
+  "emoji_button.nature": "প্রকৃতি",
+  "emoji_button.not_found": "ইমোজি পাওয়া যায়নি !! (╯°□°)╯︵ ┻━┻",
+  "emoji_button.objects": "বস্তূ",
+  "emoji_button.people": "মানুষ",
+  "emoji_button.recent": "ঘন ব্যাবহৃত",
+  "emoji_button.search": "খুজুন...",
+  "emoji_button.search_results": "খোঁজার ফলাফল",
+  "emoji_button.symbols": "প্রতীক",
+  "emoji_button.travel": "ভ্রমণ এবং স্থান",
+  "empty_column.account_timeline": "এখানে কোনো টুট নেই!",
+  "empty_column.account_unavailable": "নিজস্ব পাতা নেই",
+  "empty_column.blocks": "আপনি কোনো ব্যবহারকারীদের বন্ধ করেন নি।",
+  "empty_column.community": "স্থানীয় সময়রেখাতে কিছু নেই। প্রকাশ্যভাবে কিছু লিখে লেখালেখির উদ্বোধন করে ফেলুন!",
+  "empty_column.direct": "আপনার কাছে সরাসরি পাঠানো কোনো লেখা নেই। যদি কেও পাঠায়, সেটা এখানে দেখা যাবে।",
+  "empty_column.domain_blocks": "এখনো কোনো সরানো ওয়েবসাইট নেই।",
+  "empty_column.favourited_statuses": "আপনার পছন্দের কোনো টুট এখনো নেই। আপনি কোনো লেখা পছন্দের হিসেবে চিহ্নিত করলে এখানে পাওয়া যাবে।",
+  "empty_column.favourites": "কেও এখনো এটাকে পছন্দের টুট হিসেবে চিহ্নিত করেনি। যদি করে, তখন তাদের এখানে পাওয়া যাবে।",
+  "empty_column.follow_requests": "আপনার এখনো কোনো অনুসরণের আবেদন পাঠানো নেই। যদি পাঠায়, এখানে পাওয়া যাবে।",
+  "empty_column.hashtag": "এই হেসটাগে এখনো কিছু নেই।",
+  "empty_column.home": "আপনার বাড়ির সময়রেখা এখনো খালি!  {public}এ ঘুরে আসুন অথবা অনুসন্ধান বেবহার করে শুরু করতে পারেন এবং অন্য ব্যবহারকারীদের সাথে সাক্ষাৎ করতে পারেন।",
+  "empty_column.home.public_timeline": "প্রকাশ্য সময়রেখা",
+  "empty_column.list": "এই তালিকাতে এখনো কিছু নেই. যখন এই তালিকায় থাকা ব্যবহারকারী নতুন কিছু লিখবে, সেগুলো এখানে পাওয়া যাবে।",
+  "empty_column.lists": "আপনার এখনো কোনো তালিকা তৈরী নেই। যদি বা যখন তৈরী করেন, সেগুলো এখানে পাওয়া যাবে।",
+  "empty_column.mutes": "আপনি এখনো কোনো ব্যবহারকারীকে সরাননি।",
+  "empty_column.notifications": "আপনার এখনো কোনো প্রজ্ঞাপন নেই। কথোপকথন শুরু করতে,  অন্যদের সাথে মেলামেশা করতে পারেন।",
+  "empty_column.public": "এখানে এখনো কিছু নেই! প্রকাশ্য ভাবে কিছু লিখুন বা অন্য সার্ভার থেকে কাওকে অনুসরণ করে এই জায়গা ভরে ফেলুন",
+  "follow_request.authorize": "অনুমতি দিন",
+  "follow_request.reject": "প্রত্যাখ্যান করুন",
+  "getting_started.developers": "তৈরিকারকদের জন্য",
+  "getting_started.directory": "নিজস্ব পাতার তালিকা",
+  "getting_started.documentation": "নথিপত্র",
+  "getting_started.heading": "শুরু করা",
+  "getting_started.invite": "অন্যদের আমন্ত্রণ করুন",
+  "getting_started.open_source_notice": "মাস্টাডন একটি মুক্ত সফটওয়্যার। আপনি তৈরিতে সাহায্য করতে পারেন অথবা সমস্যা রিপোর্ট করতে পারেন গিটহাবে {github}।",
+  "getting_started.security": "নিরাপত্তা",
+  "getting_started.terms": "ব্যবহারের নিয়মাবলী",
+  "hashtag.column_header.tag_mode.all": "এবং {additional}",
+  "hashtag.column_header.tag_mode.any": "অথবা {additional}",
+  "hashtag.column_header.tag_mode.none": "বাদ দিয়ে {additional}",
+  "hashtag.column_settings.select.no_options_message": "কোনটা পাওয়া যায় নি",
+  "hashtag.column_settings.select.placeholder": "হ্যাশট্যাগের ভেতরে ঢুকুন…",
+  "hashtag.column_settings.tag_mode.all": "এগুলো সব",
+  "hashtag.column_settings.tag_mode.any": "এর ভেতরে যেকোনোটা",
+  "hashtag.column_settings.tag_mode.none": "এগুলোর একটাও না",
+  "hashtag.column_settings.tag_toggle": "আরো ট্যাগ এই কলামে যুক্ত করুন",
+  "home.column_settings.basic": "সাধারণ",
+  "home.column_settings.show_reblogs": "সমর্থনগুলো দেখান",
+  "home.column_settings.show_replies": "মতামত দেখান",
   "intervals.full.days": "{number, plural, one {# day} other {# days}}",
-  "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
+  "intervals.full.hours": "{number, plural, one {# ঘটা} other {# ঘটা}}",
   "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
-  "introduction.federation.action": "Next",
-  "introduction.federation.federated.headline": "Federated",
-  "introduction.federation.federated.text": "Public posts from other servers of the fediverse will appear in the federated timeline.",
-  "introduction.federation.home.headline": "Home",
-  "introduction.federation.home.text": "Posts from people you follow will appear in your home feed. You can follow anyone on any server!",
-  "introduction.federation.local.headline": "Local",
-  "introduction.federation.local.text": "Public posts from people on the same server as you will appear in the local timeline.",
-  "introduction.interactions.action": "Finish toot-orial!",
-  "introduction.interactions.favourite.headline": "Favourite",
-  "introduction.interactions.favourite.text": "You can save a toot for later, and let the author know that you liked it, by favouriting it.",
-  "introduction.interactions.reblog.headline": "Boost",
-  "introduction.interactions.reblog.text": "You can share other people's toots with your followers by boosting them.",
-  "introduction.interactions.reply.headline": "Reply",
-  "introduction.interactions.reply.text": "You can reply to other people's and your own toots, which will chain them together in a conversation.",
-  "introduction.welcome.action": "Let's go!",
-  "introduction.welcome.headline": "First steps",
-  "introduction.welcome.text": "Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.",
-  "keyboard_shortcuts.back": "to navigate back",
-  "keyboard_shortcuts.blocked": "to open blocked users list",
-  "keyboard_shortcuts.boost": "to boost",
-  "keyboard_shortcuts.column": "to focus a status in one of the columns",
-  "keyboard_shortcuts.compose": "to focus the compose textarea",
-  "keyboard_shortcuts.description": "Description",
-  "keyboard_shortcuts.direct": "to open direct messages column",
-  "keyboard_shortcuts.down": "to move down in the list",
-  "keyboard_shortcuts.enter": "to open status",
-  "keyboard_shortcuts.favourite": "to favourite",
-  "keyboard_shortcuts.favourites": "to open favourites list",
-  "keyboard_shortcuts.federated": "to open federated timeline",
-  "keyboard_shortcuts.heading": "Keyboard Shortcuts",
-  "keyboard_shortcuts.home": "to open home timeline",
-  "keyboard_shortcuts.hotkey": "Hotkey",
-  "keyboard_shortcuts.legend": "to display this legend",
-  "keyboard_shortcuts.local": "to open local timeline",
-  "keyboard_shortcuts.mention": "to mention author",
-  "keyboard_shortcuts.muted": "to open muted users list",
-  "keyboard_shortcuts.my_profile": "to open your profile",
-  "keyboard_shortcuts.notifications": "to open notifications column",
-  "keyboard_shortcuts.pinned": "to open pinned toots list",
-  "keyboard_shortcuts.profile": "to open author's profile",
-  "keyboard_shortcuts.reply": "to reply",
-  "keyboard_shortcuts.requests": "to open follow requests list",
-  "keyboard_shortcuts.search": "to focus search",
-  "keyboard_shortcuts.start": "to open \"get started\" column",
-  "keyboard_shortcuts.toggle_hidden": "to show/hide text behind CW",
-  "keyboard_shortcuts.toot": "to start a brand new toot",
-  "keyboard_shortcuts.unfocus": "to un-focus compose textarea/search",
-  "keyboard_shortcuts.up": "to move up in the list",
-  "lightbox.close": "Close",
-  "lightbox.next": "Next",
-  "lightbox.previous": "Previous",
-  "lists.account.add": "Add to list",
-  "lists.account.remove": "Remove from list",
-  "lists.delete": "Delete list",
-  "lists.edit": "Edit list",
-  "lists.edit.submit": "Change title",
-  "lists.new.create": "Add list",
-  "lists.new.title_placeholder": "New list title",
-  "lists.search": "Search among people you follow",
-  "lists.subheading": "Your lists",
-  "loading_indicator.label": "Loading...",
-  "media_gallery.toggle_visible": "Toggle visibility",
-  "missing_indicator.label": "Not found",
-  "missing_indicator.sublabel": "This resource could not be found",
-  "mute_modal.hide_notifications": "Hide notifications from this user?",
-  "navigation_bar.apps": "Mobile apps",
-  "navigation_bar.blocks": "Blocked users",
-  "navigation_bar.community_timeline": "Local timeline",
-  "navigation_bar.compose": "Compose new toot",
-  "navigation_bar.direct": "Direct messages",
-  "navigation_bar.discover": "Discover",
-  "navigation_bar.domain_blocks": "Hidden domains",
-  "navigation_bar.edit_profile": "Edit profile",
-  "navigation_bar.favourites": "Favourites",
-  "navigation_bar.filters": "Muted words",
-  "navigation_bar.follow_requests": "Follow requests",
-  "navigation_bar.info": "About this server",
-  "navigation_bar.keyboard_shortcuts": "Hotkeys",
-  "navigation_bar.lists": "Lists",
-  "navigation_bar.logout": "Logout",
-  "navigation_bar.mutes": "Muted users",
-  "navigation_bar.personal": "Personal",
-  "navigation_bar.pins": "Pinned toots",
-  "navigation_bar.preferences": "Preferences",
-  "navigation_bar.public_timeline": "Federated timeline",
-  "navigation_bar.security": "Security",
-  "notification.favourite": "{name} favourited your status",
-  "notification.follow": "{name} followed you",
-  "notification.mention": "{name} mentioned you",
-  "notification.poll": "A poll you have voted in has ended",
-  "notification.reblog": "{name} boosted your status",
-  "notifications.clear": "Clear notifications",
-  "notifications.clear_confirmation": "Are you sure you want to permanently clear all your notifications?",
-  "notifications.column_settings.alert": "Desktop notifications",
-  "notifications.column_settings.favourite": "Favourites:",
-  "notifications.column_settings.filter_bar.advanced": "Display all categories",
-  "notifications.column_settings.filter_bar.category": "Quick filter bar",
-  "notifications.column_settings.filter_bar.show": "Show",
-  "notifications.column_settings.follow": "New followers:",
-  "notifications.column_settings.mention": "Mentions:",
-  "notifications.column_settings.poll": "Poll results:",
-  "notifications.column_settings.push": "Push notifications",
-  "notifications.column_settings.reblog": "Boosts:",
-  "notifications.column_settings.show": "Show in column",
-  "notifications.column_settings.sound": "Play sound",
-  "notifications.filter.all": "All",
-  "notifications.filter.boosts": "Boosts",
-  "notifications.filter.favourites": "Favourites",
-  "notifications.filter.follows": "Follows",
-  "notifications.filter.mentions": "Mentions",
-  "notifications.filter.polls": "Poll results",
-  "notifications.group": "{count} notifications",
-  "poll.closed": "Closed",
-  "poll.refresh": "Refresh",
-  "poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
-  "poll.vote": "Vote",
-  "poll_button.add_poll": "Add a poll",
-  "poll_button.remove_poll": "Remove poll",
-  "privacy.change": "Adjust status privacy",
-  "privacy.direct.long": "Post to 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.public.short": "Public",
-  "privacy.unlisted.long": "Do not show in public timelines",
-  "privacy.unlisted.short": "Unlisted",
-  "regeneration_indicator.label": "Loading…",
-  "regeneration_indicator.sublabel": "Your home feed is being prepared!",
-  "relative_time.days": "{number}d",
-  "relative_time.hours": "{number}h",
-  "relative_time.just_now": "now",
-  "relative_time.minutes": "{number}m",
-  "relative_time.seconds": "{number}s",
-  "reply_indicator.cancel": "Cancel",
-  "report.forward": "Forward to {target}",
-  "report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?",
-  "report.hint": "The report will be sent to your server moderators. You can provide an explanation of why you are reporting this account below:",
-  "report.placeholder": "Additional comments",
-  "report.submit": "Submit",
-  "report.target": "Report {target}",
-  "search.placeholder": "Search",
-  "search_popout.search_format": "Advanced search format",
-  "search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.",
-  "search_popout.tips.hashtag": "hashtag",
-  "search_popout.tips.status": "status",
-  "search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags",
-  "search_popout.tips.user": "user",
-  "search_results.accounts": "People",
-  "search_results.hashtags": "Hashtags",
-  "search_results.statuses": "Toots",
-  "search_results.total": "{count, number} {count, plural, one {result} other {results}}",
-  "status.admin_account": "Open moderation interface for @{name}",
-  "status.admin_status": "Open this status in the moderation interface",
-  "status.block": "Block @{name}",
-  "status.cancel_reblog_private": "Unboost",
-  "status.cannot_reblog": "This post cannot be boosted",
-  "status.copy": "Copy link to status",
-  "status.delete": "Delete",
-  "status.detailed_status": "Detailed conversation view",
-  "status.direct": "Direct message @{name}",
-  "status.embed": "Embed",
-  "status.favourite": "Favourite",
-  "status.filtered": "Filtered",
-  "status.load_more": "Load more",
-  "status.media_hidden": "Media hidden",
-  "status.mention": "Mention @{name}",
-  "status.more": "More",
-  "status.mute": "Mute @{name}",
-  "status.mute_conversation": "Mute conversation",
-  "status.open": "Expand this status",
-  "status.pin": "Pin on profile",
-  "status.pinned": "Pinned toot",
-  "status.read_more": "Read more",
-  "status.reblog": "Boost",
-  "status.reblog_private": "Boost to original audience",
-  "status.reblogged_by": "{name} boosted",
-  "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.",
-  "status.redraft": "Delete & re-draft",
-  "status.reply": "Reply",
-  "status.replyAll": "Reply to thread",
-  "status.report": "Report @{name}",
-  "status.sensitive_toggle": "Click to view",
-  "status.sensitive_warning": "Sensitive content",
-  "status.share": "Share",
-  "status.show_less": "Show less",
-  "status.show_less_all": "Show less for all",
-  "status.show_more": "Show more",
-  "status.show_more_all": "Show more for all",
-  "status.show_thread": "Show thread",
-  "status.unmute_conversation": "Unmute conversation",
-  "status.unpin": "Unpin from profile",
-  "suggestions.dismiss": "Dismiss suggestion",
-  "suggestions.header": "You might be interested in…",
-  "tabs_bar.federated_timeline": "Federated",
-  "tabs_bar.home": "Home",
-  "tabs_bar.local_timeline": "Local",
-  "tabs_bar.notifications": "Notifications",
-  "tabs_bar.search": "Search",
-  "time_remaining.days": "{number, plural, one {# day} other {# days}} left",
-  "time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left",
-  "time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left",
-  "time_remaining.moments": "Moments remaining",
-  "time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left",
-  "trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking",
-  "ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
-  "upload_area.title": "Drag & drop to upload",
-  "upload_button.label": "Add media (JPEG, PNG, GIF, WebM, MP4, MOV)",
-  "upload_error.limit": "File upload limit exceeded.",
-  "upload_error.poll": "File upload not allowed with polls.",
-  "upload_form.description": "Describe for the visually impaired",
-  "upload_form.focus": "Crop",
-  "upload_form.undo": "Delete",
-  "upload_progress.label": "Uploading...",
-  "video.close": "Close video",
-  "video.exit_fullscreen": "Exit full screen",
-  "video.expand": "Expand video",
-  "video.fullscreen": "Full screen",
-  "video.hide": "Hide video",
-  "video.mute": "Mute sound",
-  "video.pause": "Pause",
-  "video.play": "Play",
-  "video.unmute": "Unmute sound"
+  "introduction.federation.action": "পরবর্তী",
+  "introduction.federation.federated.headline": "যুক্তবিশ্ব",
+  "introduction.federation.federated.text": "অন্যান্য যুক্তবিশ্বের সার্ভারের লেখাগুলি যুক্তবিশ্বের সময়রেখাতে আসবে ।",
+  "introduction.federation.home.headline": "বাড়ি",
+  "introduction.federation.home.text": "যাদেরকে অনুসরণ করেন তাদের লেখাগুলো  আপনার বাড়ি-সময়রেখাতে আসবে। আপনি এখান থেকে যুক্তবিশ্বে যেকোনো সার্ভারের যে কাওকে  অনুসরণ করতে পারেন!",
+  "introduction.federation.local.headline": "স্থানীয়",
+  "introduction.federation.local.text": "আপনি যে সার্ভারে আছেন সেখানকার মানুষের প্রকাশ্য লেখাগুলো স্থানীয় সময়রেখাতে আসবে।",
+  "introduction.interactions.action": "ব্যবহার জানার অংশটি শেষ করুন!",
+  "introduction.interactions.favourite.headline": "পছন্দের",
+  "introduction.interactions.favourite.text": "পরে পড়ার জন্য বা লেখা পছন্ধ হয়েছে সেটা লেখককে জানাতে, কোনো লেখা পছন্দের হিসেবে চিহ্নিত করতে পারেন।",
+  "introduction.interactions.reblog.headline": "সমর্থন",
+  "introduction.interactions.reblog.text": "কারোর লেখা সমর্থন দিয়ে চিহ্নিত করে সেটা আপনার অনুসরণকারীদের দেখতে পারেন।",
+  "introduction.interactions.reply.headline": "মতামত",
+  "introduction.interactions.reply.text": "আপনি অন্যদের এবং নিজের লেখায় মতামত টুট করতে পারেন, যেগুলো লেখার সাথে কথোপকথন হিসেবে যুক্ত থাকবে।",
+  "introduction.welcome.action": "শুরু করা যাক!",
+  "introduction.welcome.headline": "প্রথম ধাপ",
+  "introduction.welcome.text": "যুক্তবিশ্বে স্বাগতম! কিছুক্ষনের মধ্যেই আপনি আপনার লেখা বিভিন্ন সার্ভারে সম্প্রচার করতে পারবেন। কিন্তু মনে রাখবে যে এটা একটা বিশেষ সার্ভার, {domain} কারণ এখানে আপনার নিজেস্ব পাতা রাখা হচ্ছে।",
+  "keyboard_shortcuts.back": "পেছনে যেতে",
+  "keyboard_shortcuts.blocked": "বন্ধ করা ব্যবহারকারীদের তালিকা দেখতে",
+  "keyboard_shortcuts.boost": "সমর্থন করতে",
+  "keyboard_shortcuts.column": "কোনো কলামএ কোনো লেখা ফোকাস করতে",
+  "keyboard_shortcuts.compose": "লেখা সম্পদনার জায়গায় ফোকাস করতে",
+  "keyboard_shortcuts.description": "বিবরণ",
+  "keyboard_shortcuts.direct": "সরাসরি পাঠানো লেখা দেখতে",
+  "keyboard_shortcuts.down": "তালিকার ভেতরে নিচে যেতে",
+  "keyboard_shortcuts.enter": "অবস্থা দেখতে",
+  "keyboard_shortcuts.favourite": "পছন্দের দেখতে",
+  "keyboard_shortcuts.favourites": "পছন্দের তালিকা বের করতে",
+  "keyboard_shortcuts.federated": "যুক্তবিশ্বের সময়রেখাতে যেতে",
+  "keyboard_shortcuts.heading": "কিবোর্ডের দ্রুতকারক (শর্টকাট)",
+  "keyboard_shortcuts.home": "বাড়ির সময়রেখা খুলতে",
+  "keyboard_shortcuts.hotkey": "দ্রুতকারক ছবিগুলো",
+  "keyboard_shortcuts.legend": "এই প্রদর্শনঅর্থ(legend) দেখতে",
+  "keyboard_shortcuts.local": "স্থানীয় সময়রেখাতে যেতে",
+  "keyboard_shortcuts.mention": "লেখককে উল্লেখ করতে",
+  "keyboard_shortcuts.muted": "বন্ধ করা ব্যবহারকারীদের তালিকা খুলতে",
+  "keyboard_shortcuts.my_profile": "নিজের পাতা দেখতে",
+  "keyboard_shortcuts.notifications": "প্রজ্ঞাপনের কলাম খুলতে",
+  "keyboard_shortcuts.pinned": "পিন দেওয়া টুটের তালিকা খুলতে",
+  "keyboard_shortcuts.profile": "লেখকের পাতা দেখতে",
+  "keyboard_shortcuts.reply": "মতামত দিতে",
+  "keyboard_shortcuts.requests": "অনুসরণ অনুরোধের তালিকা দেখতে",
+  "keyboard_shortcuts.search": "খোঁজার অংশে ফোকাস করতে",
+  "keyboard_shortcuts.start": "\"প্রথম শুরুর\" কলাম বের করতে",
+  "keyboard_shortcuts.toggle_hidden": "CW লেখা দেখতে বা লুকাতে",
+  "keyboard_shortcuts.toot": "নতুন একটা টুট লেখা শুরু করতে",
+  "keyboard_shortcuts.unfocus": "লেখা বা খোঁজার জায়গায় ফোকাস না করতে",
+  "keyboard_shortcuts.up": "তালিকার উপরের দিকে যেতে",
+  "lightbox.close": "বন্ধ",
+  "lightbox.next": "পরবর্তী",
+  "lightbox.previous": "পূর্ববর্তী",
+  "lightbox.view_context": "View context",
+  "lists.account.add": "তালিকাতে যুক্ত করতে",
+  "lists.account.remove": "তালিকা থেকে বাদ দিতে",
+  "lists.delete": "তালিকা মুছে ফেলতে",
+  "lists.edit": "তালিকা সম্পাদনা করতে",
+  "lists.edit.submit": "শিরোনাম সম্পাদনা করতে",
+  "lists.new.create": "তালিকাতে যুক্ত করতে",
+  "lists.new.title_placeholder": "তালিকার নতুন শিরোনাম দিতে",
+  "lists.search": "যাদের অনুসরণ করেন তাদের ভেতরে খুঁজুন",
+  "lists.subheading": "আপনার তালিকা",
+  "loading_indicator.label": "আসছে...",
+  "media_gallery.toggle_visible": "দৃশ্যতার অবস্থা বদলান",
+  "missing_indicator.label": "খুঁজে পাওয়া যায়নি",
+  "missing_indicator.sublabel": "জিনিসটা খুঁজে পাওয়া যায়নি",
+  "mute_modal.hide_notifications": "এই ব্যবহারকারীর প্রজ্ঞাপন বন্ধ করবেন ?",
+  "navigation_bar.apps": "মোবাইলের আপ্প",
+  "navigation_bar.blocks": "বন্ধ করা ব্যবহারকারী",
+  "navigation_bar.community_timeline": "স্থানীয় সময়রেখা",
+  "navigation_bar.compose": "নতুন টুট লিখুন",
+  "navigation_bar.direct": "সরাসরি লেখা",
+  "navigation_bar.discover": "ঘুরে দেখুন",
+  "navigation_bar.domain_blocks": "বন্ধ করা ওয়েবসাইট",
+  "navigation_bar.edit_profile": "নিজের পাতা সম্পাদনা করুন",
+  "navigation_bar.favourites": "পছন্দের",
+  "navigation_bar.filters": "বন্ধ করা শব্দ",
+  "navigation_bar.follow_requests": "অনুসরণের অনুরোধগুলি",
+  "navigation_bar.info": "এই সার্ভার সম্পর্কে",
+  "navigation_bar.keyboard_shortcuts": "চাবি ব্যবহার",
+  "navigation_bar.lists": "তালিকাগুলো",
+  "navigation_bar.logout": "বাইরে যান",
+  "navigation_bar.mutes": "যেসব বেভহারকারীদের কার্যক্রম বন্ধ করা আছে",
+  "navigation_bar.personal": "নিজস্ব",
+  "navigation_bar.pins": "পিন দেওয়া টুট",
+  "navigation_bar.preferences": "পছন্দসমূহ",
+  "navigation_bar.public_timeline": "যুক্তবিশ্বের সময়রেখা",
+  "navigation_bar.security": "নিরাপত্তা",
+  "notification.favourite": "{name} আপনার কার্যক্রম পছন্দ করেছেন",
+  "notification.follow": "{name} আপনাকে অনুসরণ করেছেন",
+  "notification.mention": "{name} আপনাকে উল্লেখ করেছেন",
+  "notification.poll": "আপনি ভোট দিয়েছিলেন এমন এক  নির্বাচনের ভোটের সময় শেষ হয়েছে",
+  "notification.reblog": "{name} আপনার কার্যক্রমে সমর্থন দেখিয়েছেন",
+  "notifications.clear": "প্রজ্ঞাপনগুলো মুছে ফেলতে",
+  "notifications.clear_confirmation": "আপনি কি নির্চিত প্রজ্ঞাপনগুলো মুছে ফেলতে চান ?",
+  "notifications.column_settings.alert": "কম্পিউটারে প্রজ্ঞাপন",
+  "notifications.column_settings.favourite": "পছন্দের:",
+  "notifications.column_settings.filter_bar.advanced": "সব শ্রেণীগুলো দেখতে",
+  "notifications.column_settings.filter_bar.category": "দ্রুত ছাঁকনি বার",
+  "notifications.column_settings.filter_bar.show": "দেখতে",
+  "notifications.column_settings.follow": "নতুন অনুসরণকারীরা:",
+  "notifications.column_settings.mention": "প্রজ্ঞাপনগুলো:",
+  "notifications.column_settings.poll": "নির্বাচনের ফলাফল:",
+  "notifications.column_settings.push": "পুশ প্রজ্ঞাপন",
+  "notifications.column_settings.reblog": "সমর্থনগুলো:",
+  "notifications.column_settings.show": "কলামে দেখান",
+  "notifications.column_settings.sound": "শব্দ বাজাতে",
+  "notifications.filter.all": "সব",
+  "notifications.filter.boosts": "সমর্থনগুলো",
+  "notifications.filter.favourites": "পছন্দের গুলো",
+  "notifications.filter.follows": "অনুসরণের",
+  "notifications.filter.mentions": "উল্লেখিত",
+  "notifications.filter.polls": "নির্বাচনের ফলাফল",
+  "notifications.group": "{count} প্রজ্ঞাপন",
+  "poll.closed": "বন্ধ",
+  "poll.refresh": "আবার সতেজ করতে",
+  "poll.total_votes": "{count, plural, one {# ভোট} other {# ভোট}}",
+  "poll.vote": "ভোট",
+  "poll_button.add_poll": "একটা নির্বাচন যোগ করতে",
+  "poll_button.remove_poll": "নির্বাচন বাদ দিতে",
+  "privacy.change": "লেখার গোপনীয়তা অবস্থা ঠিক করতে",
+  "privacy.direct.long": "শুধুমাত্র উল্লেখিত ব্যবহারকারীদের কাছে লিখতে",
+  "privacy.direct.short": "সরাসরি",
+  "privacy.private.long": "শুধুমাত্র আপনার অনুসরণকারীদের লিখতে",
+  "privacy.private.short": "শুধুমাত্র অনুসরণকারীদের জন্য",
+  "privacy.public.long": "সর্বজনীন প্রকাশ্য সময়রেখাতে লিখতে",
+  "privacy.public.short": "সর্বজনীন প্রকাশ্য",
+  "privacy.unlisted.long": "সর্বজনীন প্রকাশ্য সময়রেখাতে না দেখাতে",
+  "privacy.unlisted.short": "প্রকাশ্য নয়",
+  "regeneration_indicator.label": "আসছে…",
+  "regeneration_indicator.sublabel": "আপনার বাড়ির-সময়রেখা প্রস্তূত করা হচ্ছে!",
+  "relative_time.days": "{number} দিন",
+  "relative_time.hours": "{number} ঘন্টা",
+  "relative_time.just_now": "এখন",
+  "relative_time.minutes": "{number} মাস",
+  "relative_time.seconds": "{number} সেকেন্ড",
+  "reply_indicator.cancel": "বাতিল করতে",
+  "report.forward": "এটা আরো পাঠান {target} তে",
+  "report.forward_hint": "এই নিবন্ধনটি অন্য একটি সার্ভারে। অপ্রকাশিতনামাভাবে রিপোর্টের কপি সেখানেও কি পাঠাতে চান ?",
+  "report.hint": "রিপোর্টটি আপনার সার্ভারের পরিচালকের কাছে পাঠানো হবে। রিপোর্ট পাঠানোর কারণ নিচে বিস্তারিত লিখতে পারেন:",
+  "report.placeholder": "অন্য কোনো মন্তব্য",
+  "report.submit": "জমা দিন",
+  "report.target": "{target} রিপোর্ট করুন",
+  "search.placeholder": "খুঁজতে",
+  "search_popout.search_format": "বিস্তারিতভাবে খোঁজার পদ্ধতি",
+  "search_popout.tips.full_text": "সাধারণ লেখা দিয়ে খুঁজলে বের হবে সেরকম আপনার লেখা, পছন্দের লেখা, সমর্থন করা লেখা, আপনাকে উল্লেখকরা কোনো লেখা,  যা খুঁজছেন সেরকম কোনো ব্যবহারকারীর নাম বা কোনো হ্যাশট্যাগগুলো।",
+  "search_popout.tips.hashtag": "হ্যাশট্যাগ",
+  "search_popout.tips.status": "লেখা",
+  "search_popout.tips.text": "সাধারণ লেখা দিয়ে খুঁজলে বের হবে সেরকম ব্যবহারকারীর নাম বা কোনো হ্যাশট্যাগগুলো",
+  "search_popout.tips.user": "ব্যবহারকারী",
+  "search_results.accounts": "মানুষ",
+  "search_results.hashtags": "হ্যাশট্যাগগুলি",
+  "search_results.statuses": "টুট",
+  "search_results.total": "{count, number} {count, plural, one {ফলাফল} other {ফলাফল}}",
+  "status.admin_account": "@{name} র জন্য পরিচালনার ইন্টারফেসে ঢুকুন",
+  "status.admin_status": "যায় লেখাটি পরিচালনার ইন্টারফেসে খুলুন",
+  "status.block": "@{name}কে বন্ধ করুন",
+  "status.cancel_reblog_private": "সমর্থন বাতিল করতে",
+  "status.cannot_reblog": "এটিতে সমর্থন দেওয়া যাবেনা",
+  "status.copy": "লেখাটির লিংক কপি করতে",
+  "status.delete": "মুছে ফেলতে",
+  "status.detailed_status": "বিস্তারিত কথোপকথনের হিসেবে দেখতে",
+  "status.direct": "@{name} কে সরাসরি পাঠান",
+  "status.embed": "এমবেড করতে",
+  "status.favourite": "পছন্দের করতে",
+  "status.filtered": "ছাঁকনিদিত",
+  "status.load_more": "আরো দেখুন",
+  "status.media_hidden": "ছবি বা ভিডিও পেছনে",
+  "status.mention": "@{name}কে উল্লেখ করতে",
+  "status.more": "আরো",
+  "status.mute": "@{name}র কার্যক্রম সরিয়ে ফেলতে",
+  "status.mute_conversation": "কথোপকথননের প্রজ্ঞাপন সরিয়ে ফেলতে",
+  "status.open": "এটার সম্পূর্ণটা দেখতে",
+  "status.pin": "নিজের পাতায় এটা পিন করতে",
+  "status.pinned": "পিন করা টুট",
+  "status.read_more": "আরো পড়ুন",
+  "status.reblog": "সমর্থন দিতে",
+  "status.reblog_private": "আপনার অনুসরণকারীদের কাছে এটার সমর্থন দেখাতে",
+  "status.reblogged_by": "{name} সমর্থন দিয়েছে",
+  "status.reblogs.empty": "এখনো কেও এটাতে সমর্থন দেয়নি। যখন কেও দেয়, সেটা তখন এখানে দেখা যাবে।",
+  "status.redraft": "মুছে আবার নতুন করে লিখতে",
+  "status.reply": "মতামত জানাতে",
+  "status.replyAll": "লেখাযুক্ত সবার কাছে মতামত জানাতে",
+  "status.report": "@{name}কে রিপোর্ট করতে",
+  "status.sensitive_warning": "সংবেদনশীল কিছু",
+  "status.share": "অন্যদের জানান",
+  "status.show_less": "কম দেখতে",
+  "status.show_less_all": "সবগুলোতে কম দেখতে",
+  "status.show_more": "আরো দেখাতে",
+  "status.show_more_all": "সবগুলোতে আরো দেখতে",
+  "status.show_thread": "আলোচনা দেখতে",
+  "status.unmute_conversation": "আলোচনার প্রজ্ঞাপন চালু করতে",
+  "status.unpin": "নিজের পাতা থেকে পিন করে রাখাটির পিন খুলতে",
+  "suggestions.dismiss": "সাহায্যের জন্য পরামর্শগুলো সরাতে",
+  "suggestions.header": "আপনি হয়তোবা এগুলোতে আগ্রহী হতে পারেন…",
+  "tabs_bar.federated_timeline": "যুক্তবিশ্ব",
+  "tabs_bar.home": "বাড়ি",
+  "tabs_bar.local_timeline": "স্থানীয়",
+  "tabs_bar.notifications": "প্রজ্ঞাপনগুলো",
+  "tabs_bar.search": "খুঁজতে",
+  "time_remaining.days": "{number, plural, one {# day} other {# days}} বাকি আছে",
+  "time_remaining.hours": "{number, plural, one {# hour} other {# hours}} বাকি আছে",
+  "time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} বাকি আছে",
+  "time_remaining.moments": "সময় বাকি আছে",
+  "time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} বাকি আছে",
+  "trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} কথা বলছে",
+  "ui.beforeunload": "যে পর্যন্ত এটা লেখা হয়েছে, মাস্টাডন থেকে চলে গেলে এটা মুছে যাবে।",
+  "upload_area.title": "টেনে এখানে ছেড়ে দিলে এখানে যুক্ত করা যাবে",
+  "upload_button.label": "ছবি বা ভিডিও যুক্ত করতে (এসব ধরণের JPEG, PNG, GIF, WebM, MP4, MOV)",
+  "upload_error.limit": "যা যুক্ত করতে চাচ্ছেন সেটি বেশি বড়, এখানকার সর্বাধিকের মেমোরির উপরে চলে গেছে।",
+  "upload_error.poll": "নির্বাচনক্ষেত্রে কোনো ফাইল যুক্ত করা যাবেনা।",
+  "upload_form.description": "যারা দেখতে পায়না তাদের জন্য এটা বর্ণনা করতে",
+  "upload_form.focus": "সাধারণ দেখাটি পরিবর্তন করতে",
+  "upload_form.undo": "মুছে ফেলতে",
+  "upload_progress.label": "যুক্ত করতে পাঠানো হচ্ছে...",
+  "video.close": "ভিডিওটি বন্ধ করতে",
+  "video.exit_fullscreen": "পূর্ণ পর্দা থেকে বাইরে বের হতে",
+  "video.expand": "ভিডিওটি বড়ো করতে",
+  "video.fullscreen": "পূর্ণ পর্দা করতে",
+  "video.hide": "ভিডিওটি লুকাতে",
+  "video.mute": "শব্দ বন্ধ করতে",
+  "video.pause": "থামাতে",
+  "video.play": "শুরু করতে",
+  "video.unmute": "শব্দ চালু করতে"
 }
diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json
index cbf303f3c..695f22382 100644
--- a/app/javascript/mastodon/locales/cs.json
+++ b/app/javascript/mastodon/locales/cs.json
@@ -342,7 +342,6 @@
   "status.reply": "Odpovědět",
   "status.replyAll": "Odpovědět na vlákno",
   "status.report": "Nahlásit uživatele @{name}",
-  "status.sensitive_toggle": "Klikněte pro zobrazení",
   "status.sensitive_warning": "Citlivý obsah",
   "status.share": "Sdílet",
   "status.show_less": "Zobrazit méně",
diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json
index d886b2b54..92dde4607 100644
--- a/app/javascript/mastodon/locales/cy.json
+++ b/app/javascript/mastodon/locales/cy.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Tŵt",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Cyfryngau wedi'u marcio'n sensitif",
   "compose_form.sensitive.unmarked": "Nid yw'r cyfryngau wedi'u marcio'n sensitif",
   "compose_form.spoiler.marked": "Testun wedi ei guddio gan rybudd",
@@ -209,6 +210,7 @@
   "lightbox.close": "Cau",
   "lightbox.next": "Nesaf",
   "lightbox.previous": "Blaenorol",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Ychwanegwch at restr",
   "lists.account.remove": "Dileu o'r rhestr",
   "lists.delete": "Dileu rhestr",
@@ -340,7 +342,6 @@
   "status.reply": "Ateb",
   "status.replyAll": "Ateb i edefyn",
   "status.report": "Adrodd @{name}",
-  "status.sensitive_toggle": "Clicio i weld",
   "status.sensitive_warning": "Cynnwys sensitif",
   "status.share": "Rhannu",
   "status.show_less": "Dangos llai",
diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json
index 89096b29b..0afacada1 100644
--- a/app/javascript/mastodon/locales/da.json
+++ b/app/javascript/mastodon/locales/da.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Trut",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Medie er markeret som værende følsomt",
   "compose_form.sensitive.unmarked": "Mediet er ikke markeret som værende følsomt",
   "compose_form.spoiler.marked": "Teksten er skjult bag en advarsel",
@@ -209,6 +210,7 @@
   "lightbox.close": "Luk",
   "lightbox.next": "Næste",
   "lightbox.previous": "Forrige",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Tilføj til liste",
   "lists.account.remove": "Fjern fra liste",
   "lists.delete": "Slet liste",
@@ -340,7 +342,6 @@
   "status.reply": "Svar",
   "status.replyAll": "Svar samtale",
   "status.report": "Anmeld @{name}",
-  "status.sensitive_toggle": "Tryk for at se",
   "status.sensitive_warning": "Følsomt indhold",
   "status.share": "Del",
   "status.show_less": "Vis mindre",
diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json
index 13b8ccafa..8b7d256eb 100644
--- a/app/javascript/mastodon/locales/de.json
+++ b/app/javascript/mastodon/locales/de.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Auswahl entfernen",
   "compose_form.publish": "Tröt",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Medien sind als heikel markiert",
   "compose_form.sensitive.unmarked": "Medien sind nicht als heikel markiert",
   "compose_form.spoiler.marked": "Text ist hinter einer Warnung versteckt",
@@ -209,6 +210,7 @@
   "lightbox.close": "Schließen",
   "lightbox.next": "Weiter",
   "lightbox.previous": "Zurück",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Zur Liste hinzufügen",
   "lists.account.remove": "Von der Liste entfernen",
   "lists.delete": "Delete list",
@@ -340,7 +342,6 @@
   "status.reply": "Antworten",
   "status.replyAll": "Auf Thread antworten",
   "status.report": "@{name} melden",
-  "status.sensitive_toggle": "Zum Ansehen klicken",
   "status.sensitive_warning": "Heikle Inhalte",
   "status.share": "Teilen",
   "status.show_less": "Weniger anzeigen",
diff --git a/app/javascript/mastodon/locales/defaultMessages.json b/app/javascript/mastodon/locales/defaultMessages.json
index 8e7ed4210..73a9c4e92 100644
--- a/app/javascript/mastodon/locales/defaultMessages.json
+++ b/app/javascript/mastodon/locales/defaultMessages.json
@@ -2157,6 +2157,10 @@
   {
     "descriptors": [
       {
+        "defaultMessage": "Unboost",
+        "id": "status.cancel_reblog_private"
+      },
+      {
         "defaultMessage": "Boost",
         "id": "status.reblog"
       },
diff --git a/app/javascript/mastodon/locales/el.json b/app/javascript/mastodon/locales/el.json
index 69c0dcbad..8dd9e9eb9 100644
--- a/app/javascript/mastodon/locales/el.json
+++ b/app/javascript/mastodon/locales/el.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Αφαίρεση επιλογής",
   "compose_form.publish": "Τουτ",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Το πολυμέσο έχει σημειωθεί ως ευαίσθητο",
   "compose_form.sensitive.unmarked": "Το πολυμέσο δεν έχει σημειωθεί ως ευαίσθητο",
   "compose_form.spoiler.marked": "Κείμενο κρυμμένο πίσω από προειδοποίηση",
@@ -209,6 +210,7 @@
   "lightbox.close": "Κλείσιμο",
   "lightbox.next": "Επόμενο",
   "lightbox.previous": "Προηγούμενο",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Πρόσθεσε στη λίστα",
   "lists.account.remove": "Βγάλε από τη λίστα",
   "lists.delete": "Διαγραφή λίστας",
@@ -340,7 +342,6 @@
   "status.reply": "Απάντησε",
   "status.replyAll": "Απάντησε στην συζήτηση",
   "status.report": "Κατάγγειλε @{name}",
-  "status.sensitive_toggle": "Κλικ για να δεις",
   "status.sensitive_warning": "Ευαίσθητο περιεχόμενο",
   "status.share": "Μοιράσου",
   "status.show_less": "Δείξε λιγότερα",
diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json
index 740f2bfae..a89da4ad5 100644
--- a/app/javascript/mastodon/locales/eo.json
+++ b/app/javascript/mastodon/locales/eo.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Forigi ĉi tiu elekton",
   "compose_form.publish": "Hup",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Aŭdovidaĵo markita tikla",
   "compose_form.sensitive.unmarked": "Aŭdovidaĵo ne markita tikla",
   "compose_form.spoiler.marked": "Teksto kaŝita malantaŭ averto",
@@ -209,6 +210,7 @@
   "lightbox.close": "Fermi",
   "lightbox.next": "Sekva",
   "lightbox.previous": "Antaŭa",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Aldoni al la listo",
   "lists.account.remove": "Forigi de la listo",
   "lists.delete": "Forigi la liston",
@@ -340,7 +342,6 @@
   "status.reply": "Respondi",
   "status.replyAll": "Respondi al la fadeno",
   "status.report": "Signali @{name}",
-  "status.sensitive_toggle": "Alklaki por vidi",
   "status.sensitive_warning": "Tikla enhavo",
   "status.share": "Diskonigi",
   "status.show_less": "Malgrandigi",
diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json
index 158a116d0..00d756d34 100644
--- a/app/javascript/mastodon/locales/es.json
+++ b/app/javascript/mastodon/locales/es.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Tootear",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Material marcado como sensible",
   "compose_form.sensitive.unmarked": "Material no marcado como sensible",
   "compose_form.spoiler.marked": "Texto oculto tras la advertencia",
@@ -209,6 +210,7 @@
   "lightbox.close": "Cerrar",
   "lightbox.next": "Siguiente",
   "lightbox.previous": "Anterior",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Añadir a lista",
   "lists.account.remove": "Quitar de lista",
   "lists.delete": "Delete list",
@@ -340,7 +342,6 @@
   "status.reply": "Responder",
   "status.replyAll": "Responder al hilo",
   "status.report": "Reportar",
-  "status.sensitive_toggle": "Haz clic para ver",
   "status.sensitive_warning": "Contenido sensible",
   "status.share": "Compartir",
   "status.show_less": "Mostrar menos",
diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json
index bd26ae232..d4cef3d5d 100644
--- a/app/javascript/mastodon/locales/eu.json
+++ b/app/javascript/mastodon/locales/eu.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Toot",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Multimedia edukia hunkigarri gisa markatu da",
   "compose_form.sensitive.unmarked": "Multimedia edukia ez da hunkigarri gisa markatu",
   "compose_form.spoiler.marked": "Testua abisu batek ezkutatzen du",
@@ -209,6 +210,7 @@
   "lightbox.close": "Itxi",
   "lightbox.next": "Hurrengoa",
   "lightbox.previous": "Aurrekoa",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Gehitu zerrendara",
   "lists.account.remove": "Kendu zerrendatik",
   "lists.delete": "Ezabatu zerrenda",
@@ -340,7 +342,6 @@
   "status.reply": "Erantzun",
   "status.replyAll": "Erantzun harian",
   "status.report": "Salatu @{name}",
-  "status.sensitive_toggle": "Egin klik ikusteko",
   "status.sensitive_warning": "Kontuz: Eduki hunkigarria",
   "status.share": "Partekatu",
   "status.show_less": "Erakutsi gutxiago",
diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json
index 6890fa971..3dcfbc7ac 100644
--- a/app/javascript/mastodon/locales/fa.json
+++ b/app/javascript/mastodon/locales/fa.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "حذف این گزینه",
   "compose_form.publish": "بوق",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "این تصویر به عنوان حساس علامت‌گذاری شده",
   "compose_form.sensitive.unmarked": "این تصویر به عنوان حساس علامت‌گذاری نشده",
   "compose_form.spoiler.marked": "نوشته پشت هشدار محتوا پنهان است",
@@ -209,6 +210,7 @@
   "lightbox.close": "بستن",
   "lightbox.next": "بعدی",
   "lightbox.previous": "قبلی",
+  "lightbox.view_context": "View context",
   "lists.account.add": "افزودن به فهرست",
   "lists.account.remove": "پاک‌کردن از فهرست",
   "lists.delete": "حذف فهرست",
@@ -340,7 +342,6 @@
   "status.reply": "پاسخ",
   "status.replyAll": "به نوشته پاسخ دهید",
   "status.report": "گزارش دادن @{name}",
-  "status.sensitive_toggle": "برای دیدن کلیک کنید",
   "status.sensitive_warning": "محتوای حساس",
   "status.share": "هم‌رسانی",
   "status.show_less": "نهفتن",
diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json
index 825cd4a75..9e098638f 100644
--- a/app/javascript/mastodon/locales/fi.json
+++ b/app/javascript/mastodon/locales/fi.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Tuuttaa",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Media on merkitty arkaluontoiseksi",
   "compose_form.sensitive.unmarked": "Mediaa ei ole merkitty arkaluontoiseksi",
   "compose_form.spoiler.marked": "Teksti on piilotettu varoituksen taakse",
@@ -209,6 +210,7 @@
   "lightbox.close": "Sulje",
   "lightbox.next": "Seuraava",
   "lightbox.previous": "Edellinen",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Lisää listaan",
   "lists.account.remove": "Poista listasta",
   "lists.delete": "Poista lista",
@@ -340,7 +342,6 @@
   "status.reply": "Vastaa",
   "status.replyAll": "Vastaa ketjuun",
   "status.report": "Raportoi @{name}",
-  "status.sensitive_toggle": "Klikkaa nähdäksesi",
   "status.sensitive_warning": "Arkaluontoista sisältöä",
   "status.share": "Jaa",
   "status.show_less": "Näytä vähemmän",
diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json
index 723328ab4..61afd4cbf 100644
--- a/app/javascript/mastodon/locales/gl.json
+++ b/app/javascript/mastodon/locales/gl.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Toot",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Medios marcados como sensibles",
   "compose_form.sensitive.unmarked": "Os medios non están marcados como sensibles",
   "compose_form.spoiler.marked": "O texto está agochado tras un aviso",
@@ -209,6 +210,7 @@
   "lightbox.close": "Fechar",
   "lightbox.next": "Seguinte",
   "lightbox.previous": "Anterior",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Engadir á lista",
   "lists.account.remove": "Eliminar da lista",
   "lists.delete": "Delete list",
@@ -340,7 +342,6 @@
   "status.reply": "Resposta",
   "status.replyAll": "Resposta a conversa",
   "status.report": "Informar @{name}",
-  "status.sensitive_toggle": "Pulse para ver",
   "status.sensitive_warning": "Contido sensible",
   "status.share": "Compartir",
   "status.show_less": "Mostrar menos",
diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json
index c9228cffd..bf09ead22 100644
--- a/app/javascript/mastodon/locales/he.json
+++ b/app/javascript/mastodon/locales/he.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "ללחוש",
   "compose_form.publish_loud": "לחצרץ!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Media is marked as sensitive",
   "compose_form.sensitive.unmarked": "Media is not marked as sensitive",
   "compose_form.spoiler.marked": "Text is hidden behind warning",
@@ -209,6 +210,7 @@
   "lightbox.close": "סגירה",
   "lightbox.next": "הלאה",
   "lightbox.previous": "הקודם",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Add to list",
   "lists.account.remove": "Remove from list",
   "lists.delete": "Delete list",
@@ -340,7 +342,6 @@
   "status.reply": "תגובה",
   "status.replyAll": "תגובה לכולם",
   "status.report": "דיווח על @{name}",
-  "status.sensitive_toggle": "לחצו כדי לראות",
   "status.sensitive_warning": "תוכן רגיש",
   "status.share": "שיתוף",
   "status.show_less": "הראה פחות",
diff --git a/app/javascript/mastodon/locales/hi.json b/app/javascript/mastodon/locales/hi.json
index 9d507346a..5d8f4ab7f 100644
--- a/app/javascript/mastodon/locales/hi.json
+++ b/app/javascript/mastodon/locales/hi.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Toot",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Media is marked as sensitive",
   "compose_form.sensitive.unmarked": "Media is not marked as sensitive",
   "compose_form.spoiler.marked": "Text is hidden behind warning",
@@ -209,6 +210,7 @@
   "lightbox.close": "Close",
   "lightbox.next": "Next",
   "lightbox.previous": "Previous",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Add to list",
   "lists.account.remove": "Remove from list",
   "lists.delete": "Delete list",
@@ -340,7 +342,6 @@
   "status.reply": "Reply",
   "status.replyAll": "Reply to thread",
   "status.report": "Report @{name}",
-  "status.sensitive_toggle": "Click to view",
   "status.sensitive_warning": "Sensitive content",
   "status.share": "Share",
   "status.show_less": "Show less",
diff --git a/app/javascript/mastodon/locales/hr.json b/app/javascript/mastodon/locales/hr.json
index 55a4ec4ee..5353cb572 100644
--- a/app/javascript/mastodon/locales/hr.json
+++ b/app/javascript/mastodon/locales/hr.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Toot",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Media is marked as sensitive",
   "compose_form.sensitive.unmarked": "Media is not marked as sensitive",
   "compose_form.spoiler.marked": "Text is hidden behind warning",
@@ -209,6 +210,7 @@
   "lightbox.close": "Zatvori",
   "lightbox.next": "Next",
   "lightbox.previous": "Previous",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Add to list",
   "lists.account.remove": "Remove from list",
   "lists.delete": "Delete list",
@@ -340,7 +342,6 @@
   "status.reply": "Odgovori",
   "status.replyAll": "Odgovori na temu",
   "status.report": "Prijavi @{name}",
-  "status.sensitive_toggle": "Klikni da bi vidio",
   "status.sensitive_warning": "Osjetljiv sadržaj",
   "status.share": "Share",
   "status.show_less": "Pokaži manje",
diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json
index c5b0831c3..b906dd619 100644
--- a/app/javascript/mastodon/locales/hu.json
+++ b/app/javascript/mastodon/locales/hu.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Tülk",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Media is marked as sensitive",
   "compose_form.sensitive.unmarked": "Media is not marked as sensitive",
   "compose_form.spoiler.marked": "Text is hidden behind warning",
@@ -209,6 +210,7 @@
   "lightbox.close": "Bezárás",
   "lightbox.next": "Következő",
   "lightbox.previous": "Előző",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Hozzáadás a listához",
   "lists.account.remove": "Eltávolít a listából",
   "lists.delete": "Lista törlése",
@@ -340,7 +342,6 @@
   "status.reply": "Válasz",
   "status.replyAll": "Válaszolj a beszélgetésre",
   "status.report": "Report @{name}",
-  "status.sensitive_toggle": "Katt a megtekintéshez",
   "status.sensitive_warning": "Érzékeny tartalom",
   "status.share": "Megosztás",
   "status.show_less": "Kevesebb",
diff --git a/app/javascript/mastodon/locales/hy.json b/app/javascript/mastodon/locales/hy.json
index ca7732d85..e2e0aa881 100644
--- a/app/javascript/mastodon/locales/hy.json
+++ b/app/javascript/mastodon/locales/hy.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Թթել",
   "compose_form.publish_loud": "Թթե՜լ",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Media is marked as sensitive",
   "compose_form.sensitive.unmarked": "Media is not marked as sensitive",
   "compose_form.spoiler.marked": "Text is hidden behind warning",
@@ -209,6 +210,7 @@
   "lightbox.close": "Փակել",
   "lightbox.next": "Հաջորդ",
   "lightbox.previous": "Նախորդ",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Ավելացնել ցանկին",
   "lists.account.remove": "Հանել ցանկից",
   "lists.delete": "Ջնջել ցանկը",
@@ -340,7 +342,6 @@
   "status.reply": "Պատասխանել",
   "status.replyAll": "Պատասխանել թելին",
   "status.report": "Բողոքել @{name}֊ից",
-  "status.sensitive_toggle": "Կտացրու՝ դիտելու համար",
   "status.sensitive_warning": "Կասկածելի բովանդակություն",
   "status.share": "Կիսվել",
   "status.show_less": "Պակաս",
diff --git a/app/javascript/mastodon/locales/id.json b/app/javascript/mastodon/locales/id.json
index c4610c330..5b15327ed 100644
--- a/app/javascript/mastodon/locales/id.json
+++ b/app/javascript/mastodon/locales/id.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Toot",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Sumber ini telah ditandai sebagai sumber sensitif.",
   "compose_form.sensitive.unmarked": "Sumber ini tidak ditandai sebagai sumber sensitif",
   "compose_form.spoiler.marked": "Teks disembunyikan dibalik peringatan",
@@ -209,6 +210,7 @@
   "lightbox.close": "Tutup",
   "lightbox.next": "Next",
   "lightbox.previous": "Previous",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Add to list",
   "lists.account.remove": "Remove from list",
   "lists.delete": "Delete list",
@@ -340,7 +342,6 @@
   "status.reply": "Balas",
   "status.replyAll": "Balas ke semua",
   "status.report": "Laporkan @{name}",
-  "status.sensitive_toggle": "Klik untuk menampilkan",
   "status.sensitive_warning": "Konten sensitif",
   "status.share": "Share",
   "status.show_less": "Tampilkan lebih sedikit",
diff --git a/app/javascript/mastodon/locales/io.json b/app/javascript/mastodon/locales/io.json
index dcdae5771..61c65c12d 100644
--- a/app/javascript/mastodon/locales/io.json
+++ b/app/javascript/mastodon/locales/io.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Siflar",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Media is marked as sensitive",
   "compose_form.sensitive.unmarked": "Media is not marked as sensitive",
   "compose_form.spoiler.marked": "Text is hidden behind warning",
@@ -209,6 +210,7 @@
   "lightbox.close": "Klozar",
   "lightbox.next": "Next",
   "lightbox.previous": "Previous",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Add to list",
   "lists.account.remove": "Remove from list",
   "lists.delete": "Delete list",
@@ -340,7 +342,6 @@
   "status.reply": "Respondar",
   "status.replyAll": "Respondar a filo",
   "status.report": "Denuncar @{name}",
-  "status.sensitive_toggle": "Kliktar por vidar",
   "status.sensitive_warning": "Trubliva kontenajo",
   "status.share": "Share",
   "status.show_less": "Montrar mine",
diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json
index 792204830..ebdc42102 100644
--- a/app/javascript/mastodon/locales/it.json
+++ b/app/javascript/mastodon/locales/it.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Toot",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Questo media è contrassegnato come sensibile",
   "compose_form.sensitive.unmarked": "Questo media non è contrassegnato come sensibile",
   "compose_form.spoiler.marked": "Il testo è nascosto dall'avviso",
@@ -209,6 +210,7 @@
   "lightbox.close": "Chiudi",
   "lightbox.next": "Successivo",
   "lightbox.previous": "Precedente",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Aggiungi alla lista",
   "lists.account.remove": "Togli dalla lista",
   "lists.delete": "Delete list",
@@ -340,7 +342,6 @@
   "status.reply": "Rispondi",
   "status.replyAll": "Rispondi alla conversazione",
   "status.report": "Segnala @{name}",
-  "status.sensitive_toggle": "Clicca per vedere",
   "status.sensitive_warning": "Materiale sensibile",
   "status.share": "Condividi",
   "status.show_less": "Mostra meno",
diff --git a/app/javascript/mastodon/locales/ka.json b/app/javascript/mastodon/locales/ka.json
index ac983a546..237c11a66 100644
--- a/app/javascript/mastodon/locales/ka.json
+++ b/app/javascript/mastodon/locales/ka.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "ტუტი",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "მედია მონიშნულია მგრძნობიარედ",
   "compose_form.sensitive.unmarked": "მედია არაა მონიშნული მგრძნობიარედ",
   "compose_form.spoiler.marked": "გაფრთხილების უკან ტექსტი დამალულია",
@@ -209,6 +210,7 @@
   "lightbox.close": "დახურვა",
   "lightbox.next": "შემდეგი",
   "lightbox.previous": "წინა",
+  "lightbox.view_context": "View context",
   "lists.account.add": "სიაში დამატება",
   "lists.account.remove": "სიიდან ამოშლა",
   "lists.delete": "სიის წაშლა",
@@ -340,7 +342,6 @@
   "status.reply": "პასუხი",
   "status.replyAll": "უპასუხე თემას",
   "status.report": "დაარეპორტე @{name}",
-  "status.sensitive_toggle": "დააწკაპუნეთ სანახავად",
   "status.sensitive_warning": "მგრძნობიარე კონტენტი",
   "status.share": "გაზიარება",
   "status.show_less": "აჩვენე ნაკლები",
diff --git a/app/javascript/mastodon/locales/kk.json b/app/javascript/mastodon/locales/kk.json
index ee7bf5d6e..bae8dd121 100644
--- a/app/javascript/mastodon/locales/kk.json
+++ b/app/javascript/mastodon/locales/kk.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Бұл жауапты өшір",
   "compose_form.publish": "Түрт",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Медиа нәзік деп белгіленген",
   "compose_form.sensitive.unmarked": "Медиа нәзік деп белгіленбеген",
   "compose_form.spoiler.marked": "Мәтін ескертумен жасырылған",
@@ -209,6 +210,7 @@
   "lightbox.close": "Жабу",
   "lightbox.next": "Келесі",
   "lightbox.previous": "Алдыңғы",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Тізімге қосу",
   "lists.account.remove": "Тізімнен шығару",
   "lists.delete": "Тізімді өшіру",
@@ -340,7 +342,6 @@
   "status.reply": "Жауап",
   "status.replyAll": "Тақырыпқа жауап",
   "status.report": "Шағым @{name}",
-  "status.sensitive_toggle": "Қарау үшін басыңыз",
   "status.sensitive_warning": "Нәзік контент",
   "status.share": "Бөлісу",
   "status.show_less": "Аздап көрсет",
diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json
index a1e81a9d0..9a49ce4aa 100644
--- a/app/javascript/mastodon/locales/ko.json
+++ b/app/javascript/mastodon/locales/ko.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "이 항목 삭제",
   "compose_form.publish": "툿",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "미디어가 열람주의로 설정되어 있습니다",
   "compose_form.sensitive.unmarked": "미디어가 열람주의로 설정 되어 있지 않습니다",
   "compose_form.spoiler.marked": "열람주의가 설정되어 있습니다",
@@ -209,6 +210,7 @@
   "lightbox.close": "닫기",
   "lightbox.next": "다음",
   "lightbox.previous": "이전",
+  "lightbox.view_context": "View context",
   "lists.account.add": "리스트에 추가",
   "lists.account.remove": "리스트에서 제거",
   "lists.delete": "리스트 삭제",
@@ -340,7 +342,6 @@
   "status.reply": "답장",
   "status.replyAll": "전원에게 답장",
   "status.report": "신고",
-  "status.sensitive_toggle": "클릭해서 표시하기",
   "status.sensitive_warning": "민감한 미디어",
   "status.share": "공유",
   "status.show_less": "숨기기",
diff --git a/app/javascript/mastodon/locales/lv.json b/app/javascript/mastodon/locales/lv.json
index ac3342699..755f24168 100644
--- a/app/javascript/mastodon/locales/lv.json
+++ b/app/javascript/mastodon/locales/lv.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Publicēt",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Mēdijs ir atzīmēts kā sensitīvs",
   "compose_form.sensitive.unmarked": "Mēdijs nav atzīmēts kā sensitīvs",
   "compose_form.spoiler.marked": "Teksts ir paslēpts aiz brīdinājuma",
@@ -209,6 +210,7 @@
   "lightbox.close": "Close",
   "lightbox.next": "Next",
   "lightbox.previous": "Previous",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Add to list",
   "lists.account.remove": "Remove from list",
   "lists.delete": "Delete list",
@@ -340,7 +342,6 @@
   "status.reply": "Reply",
   "status.replyAll": "Reply to thread",
   "status.report": "Report @{name}",
-  "status.sensitive_toggle": "Click to view",
   "status.sensitive_warning": "Sensitive content",
   "status.share": "Share",
   "status.show_less": "Show less",
diff --git a/app/javascript/mastodon/locales/ms.json b/app/javascript/mastodon/locales/ms.json
index 220cc86f9..cc384e7ed 100644
--- a/app/javascript/mastodon/locales/ms.json
+++ b/app/javascript/mastodon/locales/ms.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Toot",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Media is marked as sensitive",
   "compose_form.sensitive.unmarked": "Media is not marked as sensitive",
   "compose_form.spoiler.marked": "Text is hidden behind warning",
@@ -209,6 +210,7 @@
   "lightbox.close": "Close",
   "lightbox.next": "Next",
   "lightbox.previous": "Previous",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Add to list",
   "lists.account.remove": "Remove from list",
   "lists.delete": "Delete list",
@@ -340,7 +342,6 @@
   "status.reply": "Reply",
   "status.replyAll": "Reply to thread",
   "status.report": "Report @{name}",
-  "status.sensitive_toggle": "Click to view",
   "status.sensitive_warning": "Sensitive content",
   "status.share": "Share",
   "status.show_less": "Show less",
diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json
index 497a11d5c..3faf2aef4 100644
--- a/app/javascript/mastodon/locales/nl.json
+++ b/app/javascript/mastodon/locales/nl.json
@@ -210,6 +210,7 @@
   "lightbox.close": "Sluiten",
   "lightbox.next": "Volgende",
   "lightbox.previous": "Vorige",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Aan lijst toevoegen",
   "lists.account.remove": "Uit lijst verwijderen",
   "lists.delete": "Lijst verwijderen",
@@ -341,7 +342,6 @@
   "status.reply": "Reageren",
   "status.replyAll": "Reageer op iedereen",
   "status.report": "Rapporteer @{name}",
-  "status.sensitive_toggle": "Klik om te bekijken",
   "status.sensitive_warning": "Gevoelige inhoud",
   "status.share": "Delen",
   "status.show_less": "Minder tonen",
diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json
index fc2c3c573..f039bcbfd 100644
--- a/app/javascript/mastodon/locales/no.json
+++ b/app/javascript/mastodon/locales/no.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Tut",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Media is marked as sensitive",
   "compose_form.sensitive.unmarked": "Media is not marked as sensitive",
   "compose_form.spoiler.marked": "Text is hidden behind warning",
@@ -209,6 +210,7 @@
   "lightbox.close": "Lukk",
   "lightbox.next": "Neste",
   "lightbox.previous": "Forrige",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Legg til i listen",
   "lists.account.remove": "Fjern fra listen",
   "lists.delete": "Slett listen",
@@ -340,7 +342,6 @@
   "status.reply": "Svar",
   "status.replyAll": "Svar til samtale",
   "status.report": "Rapporter @{name}",
-  "status.sensitive_toggle": "Klikk for å vise",
   "status.sensitive_warning": "Følsomt innhold",
   "status.share": "Del",
   "status.show_less": "Vis mindre",
diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json
index 4dfb9904e..7eaa422c9 100644
--- a/app/javascript/mastodon/locales/oc.json
+++ b/app/javascript/mastodon/locales/oc.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Levar aquesta opcion",
   "compose_form.publish": "Tut",
   "compose_form.publish_loud": "{publish} !",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Lo mèdia es marcat coma sensible",
   "compose_form.sensitive.unmarked": "Lo mèdia es pas marcat coma sensible",
   "compose_form.spoiler.marked": "Lo tèxte es rescondut jos l’avertiment",
@@ -209,6 +210,7 @@
   "lightbox.close": "Tampar",
   "lightbox.next": "Seguent",
   "lightbox.previous": "Precedent",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Ajustar a la lista",
   "lists.account.remove": "Levar de la lista",
   "lists.delete": "Suprimir la lista",
@@ -340,7 +342,6 @@
   "status.reply": "Respondre",
   "status.replyAll": "Respondre a la conversacion",
   "status.report": "Senhalar @{name}",
-  "status.sensitive_toggle": "Clicar per mostrar",
   "status.sensitive_warning": "Contengut sensible",
   "status.share": "Partejar",
   "status.show_less": "Tornar plegar",
diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json
index fce97f00e..3b6fde738 100644
--- a/app/javascript/mastodon/locales/pl.json
+++ b/app/javascript/mastodon/locales/pl.json
@@ -81,6 +81,7 @@
   "compose_form.poll.remove_option": "Usuń tę opcję",
   "compose_form.publish": "Wyślij",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Zawartość multimedia jest oznaczona jako wrażliwa",
   "compose_form.sensitive.unmarked": "Zawartość multimedialna nie jest oznaczona jako wrażliwa",
   "compose_form.spoiler.marked": "Tekst jest ukryty za ostrzeżeniem",
@@ -213,6 +214,7 @@
   "lightbox.close": "Zamknij",
   "lightbox.next": "Następne",
   "lightbox.previous": "Poprzednie",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Dodaj do listy",
   "lists.account.remove": "Usunąć z listy",
   "lists.delete": "Usuń listę",
@@ -345,7 +347,6 @@
   "status.reply": "Odpowiedz",
   "status.replyAll": "Odpowiedz na wątek",
   "status.report": "Zgłoś @{name}",
-  "status.sensitive_toggle": "Naciśnij aby wyświetlić",
   "status.sensitive_warning": "Wrażliwa zawartość",
   "status.share": "Udostępnij",
   "status.show_less": "Zwiń",
diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json
index e469344ec..4cbd2296c 100644
--- a/app/javascript/mastodon/locales/pt-BR.json
+++ b/app/javascript/mastodon/locales/pt-BR.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remover essa opção",
   "compose_form.publish": "Publicar",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Mídia está marcada como sensível",
   "compose_form.sensitive.unmarked": "Mídia não está marcada como sensível",
   "compose_form.spoiler.marked": "O texto está escondido por um aviso de conteúdo",
@@ -209,6 +210,7 @@
   "lightbox.close": "Fechar",
   "lightbox.next": "Próximo",
   "lightbox.previous": "Anterior",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Adicionar a listas",
   "lists.account.remove": "Remover da lista",
   "lists.delete": "Delete list",
@@ -340,7 +342,6 @@
   "status.reply": "Responder",
   "status.replyAll": "Responder à sequência",
   "status.report": "Denunciar @{name}",
-  "status.sensitive_toggle": "Clique para ver",
   "status.sensitive_warning": "Conteúdo sensível",
   "status.share": "Compartilhar",
   "status.show_less": "Mostrar menos",
diff --git a/app/javascript/mastodon/locales/pt.json b/app/javascript/mastodon/locales/pt.json
index 2abc3e252..b980dfa1c 100644
--- a/app/javascript/mastodon/locales/pt.json
+++ b/app/javascript/mastodon/locales/pt.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Publicar",
   "compose_form.publish_loud": "{publicar}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Media marcado como sensível",
   "compose_form.sensitive.unmarked": "Media não está marcado como sensível",
   "compose_form.spoiler.marked": "Texto escondido atrás de aviso",
@@ -209,6 +210,7 @@
   "lightbox.close": "Fechar",
   "lightbox.next": "Próximo",
   "lightbox.previous": "Anterior",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Adicionar à lista",
   "lists.account.remove": "Remover da lista",
   "lists.delete": "Delete list",
@@ -340,7 +342,6 @@
   "status.reply": "Responder",
   "status.replyAll": "Responder à conversa",
   "status.report": "Denunciar @{name}",
-  "status.sensitive_toggle": "Clique para ver",
   "status.sensitive_warning": "Conteúdo sensível",
   "status.share": "Compartilhar",
   "status.show_less": "Mostrar menos",
diff --git a/app/javascript/mastodon/locales/ro.json b/app/javascript/mastodon/locales/ro.json
index c0ec77cc6..0021846d6 100644
--- a/app/javascript/mastodon/locales/ro.json
+++ b/app/javascript/mastodon/locales/ro.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Postează",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Conținutul media este marcat ca sensibil",
   "compose_form.sensitive.unmarked": "Conținutul media nu este marcat ca sensibil",
   "compose_form.spoiler.marked": "Textul este ascuns sub o avertizare",
@@ -209,6 +210,7 @@
   "lightbox.close": "Închide",
   "lightbox.next": "Următorul",
   "lightbox.previous": "Precedentul",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Adaugă în listă",
   "lists.account.remove": "Elimină din listă",
   "lists.delete": "Șterge lista",
@@ -340,7 +342,6 @@
   "status.reply": "Răspunde",
   "status.replyAll": "Răspunde la topic",
   "status.report": "Raportează @{name}",
-  "status.sensitive_toggle": "Afișează",
   "status.sensitive_warning": "Conținut sensibil",
   "status.share": "Distribuie",
   "status.show_less": "Arată mai puțin",
diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json
index 475899797..9e8e4e324 100644
--- a/app/javascript/mastodon/locales/ru.json
+++ b/app/javascript/mastodon/locales/ru.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Удалить этот вариант",
   "compose_form.publish": "Трубить",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Медиафайлы не отмечены как чувствительные",
   "compose_form.sensitive.unmarked": "Медиафайлы не отмечены как чувствительные",
   "compose_form.spoiler.marked": "Текст скрыт за предупреждением",
@@ -209,6 +210,7 @@
   "lightbox.close": "Закрыть",
   "lightbox.next": "Далее",
   "lightbox.previous": "Назад",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Добавить в список",
   "lists.account.remove": "Убрать из списка",
   "lists.delete": "Удалить список",
@@ -340,7 +342,6 @@
   "status.reply": "Ответить",
   "status.replyAll": "Ответить всем",
   "status.report": "Пожаловаться",
-  "status.sensitive_toggle": "Нажмите для просмотра",
   "status.sensitive_warning": "Чувствительный контент",
   "status.share": "Поделиться",
   "status.show_less": "Свернуть",
diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json
index c4fcb9f18..88fc73d01 100644
--- a/app/javascript/mastodon/locales/sk.json
+++ b/app/javascript/mastodon/locales/sk.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Odstráň túto voľbu",
   "compose_form.publish": "Pošli",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Médiálny obsah je označený ako chúlostivý",
   "compose_form.sensitive.unmarked": "Médiálny obsah nieje označený ako chúlostivý",
   "compose_form.spoiler.marked": "Text je ukrytý za varovaním",
@@ -209,6 +210,7 @@
   "lightbox.close": "Zatvor",
   "lightbox.next": "Ďalšie",
   "lightbox.previous": "Predchádzajúci",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Pridaj do zoznamu",
   "lists.account.remove": "Odober zo zoznamu",
   "lists.delete": "Vymaž list",
@@ -340,7 +342,6 @@
   "status.reply": "Odpovedať",
   "status.replyAll": "Odpovedz na diskusiu",
   "status.report": "Nahlás @{name}",
-  "status.sensitive_toggle": "Klikni pre zobrazenie",
   "status.sensitive_warning": "Chúlostivý obsah",
   "status.share": "Zdieľaj",
   "status.show_less": "Zobraz menej",
diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json
index f7a294cfe..4c07165cd 100644
--- a/app/javascript/mastodon/locales/sl.json
+++ b/app/javascript/mastodon/locales/sl.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Tutni",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Medij je označen kot občutljiv",
   "compose_form.sensitive.unmarked": "Medij ni označen kot občutljiv",
   "compose_form.spoiler.marked": "Besedilo je skrito za opozorilom",
@@ -209,6 +210,7 @@
   "lightbox.close": "Close",
   "lightbox.next": "Next",
   "lightbox.previous": "Previous",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Add to list",
   "lists.account.remove": "Remove from list",
   "lists.delete": "Delete list",
@@ -340,7 +342,6 @@
   "status.reply": "Odgovori",
   "status.replyAll": "Odgovori na objavo",
   "status.report": "Prijavi @{name}",
-  "status.sensitive_toggle": "Kliknite za ogled",
   "status.sensitive_warning": "Občutljiva vsebina",
   "status.share": "Deli",
   "status.show_less": "Prikaži manj",
diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json
index 89df633cc..95bb7bd9d 100644
--- a/app/javascript/mastodon/locales/sq.json
+++ b/app/javascript/mastodon/locales/sq.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Mesazh",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Media është shënuar si rezervat",
   "compose_form.sensitive.unmarked": "Media s’është shënuar si rezervat",
   "compose_form.spoiler.marked": "Teksti është fshehur pas sinjalizimit",
@@ -209,6 +210,7 @@
   "lightbox.close": "Mbylle",
   "lightbox.next": "Pasuesja",
   "lightbox.previous": "E mëparshmja",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Shto në listë",
   "lists.account.remove": "Hiqe nga lista",
   "lists.delete": "Fshije listën",
@@ -340,7 +342,6 @@
   "status.reply": "Përgjigjuni",
   "status.replyAll": "Përgjigjuni rrjedhës",
   "status.report": "Raportojeni @{name}",
-  "status.sensitive_toggle": "Klikoni që ta shihni",
   "status.sensitive_warning": "Lëndë me spec",
   "status.share": "Ndajeni me të tjerët",
   "status.show_less": "Shfaq më pak",
diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json
index 2fc5f985a..17ce3964c 100644
--- a/app/javascript/mastodon/locales/sr-Latn.json
+++ b/app/javascript/mastodon/locales/sr-Latn.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Tutni",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Media is marked as sensitive",
   "compose_form.sensitive.unmarked": "Media is not marked as sensitive",
   "compose_form.spoiler.marked": "Text is hidden behind warning",
@@ -209,6 +210,7 @@
   "lightbox.close": "Zatvori",
   "lightbox.next": "Sledeći",
   "lightbox.previous": "Prethodni",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Dodaj na listu",
   "lists.account.remove": "Ukloni sa liste",
   "lists.delete": "Obriši listu",
@@ -340,7 +342,6 @@
   "status.reply": "Odgovori",
   "status.replyAll": "Odgovori na diskusiju",
   "status.report": "Prijavi korisnika @{name}",
-  "status.sensitive_toggle": "Kliknite da vidite",
   "status.sensitive_warning": "Osetljiv sadržaj",
   "status.share": "Podeli",
   "status.show_less": "Prikaži manje",
diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json
index 2ae34adca..8c430f6b3 100644
--- a/app/javascript/mastodon/locales/sr.json
+++ b/app/javascript/mastodon/locales/sr.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Труби",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Медији су означени као осетљиви",
   "compose_form.sensitive.unmarked": "Медији су означени као не-осетљиви",
   "compose_form.spoiler.marked": "Текст је сакривен иза упозорења",
@@ -209,6 +210,7 @@
   "lightbox.close": "Затвори",
   "lightbox.next": "Следећи",
   "lightbox.previous": "Претходни",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Додај на листу",
   "lists.account.remove": "Уклони са листе",
   "lists.delete": "Обриши листу",
@@ -340,7 +342,6 @@
   "status.reply": "Одговори",
   "status.replyAll": "Одговори на дискусију",
   "status.report": "Пријави корисника @{name}",
-  "status.sensitive_toggle": "Кликните да видите",
   "status.sensitive_warning": "Осетљив садржај",
   "status.share": "Подели",
   "status.show_less": "Прикажи мање",
diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json
index 71264ba52..52bf6e826 100644
--- a/app/javascript/mastodon/locales/sv.json
+++ b/app/javascript/mastodon/locales/sv.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Toot",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Media har markerats som känsligt",
   "compose_form.sensitive.unmarked": "Media har inte markerats som känsligt",
   "compose_form.spoiler.marked": "Texten har dolts bakom en varning",
@@ -209,6 +210,7 @@
   "lightbox.close": "Stäng",
   "lightbox.next": "Nästa",
   "lightbox.previous": "Tidigare",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Lägg till i lista",
   "lists.account.remove": "Ta bort från lista",
   "lists.delete": "Radera lista",
@@ -340,7 +342,6 @@
   "status.reply": "Svara",
   "status.replyAll": "Svara på tråden",
   "status.report": "Rapportera @{name}",
-  "status.sensitive_toggle": "Klicka för att se",
   "status.sensitive_warning": "Känsligt innehåll",
   "status.share": "Dela",
   "status.show_less": "Visa mindre",
diff --git a/app/javascript/mastodon/locales/ta.json b/app/javascript/mastodon/locales/ta.json
index 220cc86f9..cc384e7ed 100644
--- a/app/javascript/mastodon/locales/ta.json
+++ b/app/javascript/mastodon/locales/ta.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Toot",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Media is marked as sensitive",
   "compose_form.sensitive.unmarked": "Media is not marked as sensitive",
   "compose_form.spoiler.marked": "Text is hidden behind warning",
@@ -209,6 +210,7 @@
   "lightbox.close": "Close",
   "lightbox.next": "Next",
   "lightbox.previous": "Previous",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Add to list",
   "lists.account.remove": "Remove from list",
   "lists.delete": "Delete list",
@@ -340,7 +342,6 @@
   "status.reply": "Reply",
   "status.replyAll": "Reply to thread",
   "status.report": "Report @{name}",
-  "status.sensitive_toggle": "Click to view",
   "status.sensitive_warning": "Sensitive content",
   "status.share": "Share",
   "status.show_less": "Show less",
diff --git a/app/javascript/mastodon/locales/te.json b/app/javascript/mastodon/locales/te.json
index 7e818c787..39c697b0b 100644
--- a/app/javascript/mastodon/locales/te.json
+++ b/app/javascript/mastodon/locales/te.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "ఈ ఎంపికను తొలగించు",
   "compose_form.publish": "టూట్",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "మీడియా సున్నితమైనదిగా గుర్తించబడింది",
   "compose_form.sensitive.unmarked": "మీడియా సున్నితమైనదిగా గుర్తించబడలేదు",
   "compose_form.spoiler.marked": "హెచ్చరిక వెనుక పాఠ్యం దాచబడింది",
@@ -209,6 +210,7 @@
   "lightbox.close": "మూసివేయు",
   "lightbox.next": "తరువాత",
   "lightbox.previous": "మునుపటి",
+  "lightbox.view_context": "View context",
   "lists.account.add": "జాబితాకు జోడించు",
   "lists.account.remove": "జాబితా నుండి తొలగించు",
   "lists.delete": "జాబితాను తొలగించు",
@@ -340,7 +342,6 @@
   "status.reply": "ప్రత్యుత్తరం",
   "status.replyAll": "సంభాషణకు ప్రత్యుత్తరం ఇవ్వండి",
   "status.report": "@{name}పై ఫిర్యాదుచేయు",
-  "status.sensitive_toggle": "వీక్షించడానికి క్లిక్ చేయండి",
   "status.sensitive_warning": "సున్నితమైన కంటెంట్",
   "status.share": "పంచుకోండి",
   "status.show_less": "తక్కువ చూపించు",
diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json
index 630543ada..86997b70f 100644
--- a/app/javascript/mastodon/locales/th.json
+++ b/app/javascript/mastodon/locales/th.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "โพสต์",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Media is marked as sensitive",
   "compose_form.sensitive.unmarked": "Media is not marked as sensitive",
   "compose_form.spoiler.marked": "Text is hidden behind warning",
@@ -209,6 +210,7 @@
   "lightbox.close": "ปิด",
   "lightbox.next": "ถัดไป",
   "lightbox.previous": "ก่อนหน้า",
+  "lightbox.view_context": "View context",
   "lists.account.add": "เพิ่มไปยังรายการ",
   "lists.account.remove": "เอาออกจากรายการ",
   "lists.delete": "ลบรายการ",
@@ -340,7 +342,6 @@
   "status.reply": "ตอบกลับ",
   "status.replyAll": "ตอบกลับกระทู้",
   "status.report": "รายงาน @{name}",
-  "status.sensitive_toggle": "คลิกเพื่อดู",
   "status.sensitive_warning": "เนื้อหาที่ละเอียดอ่อน",
   "status.share": "แบ่งปัน",
   "status.show_less": "แสดงน้อยลง",
diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json
index 26eca8239..c3a0791b5 100644
--- a/app/javascript/mastodon/locales/tr.json
+++ b/app/javascript/mastodon/locales/tr.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Bu seçimi kaldır",
   "compose_form.publish": "Gönder",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Medya hassas olarak işaretlendi",
   "compose_form.sensitive.unmarked": "Medya hassas olarak işaretlenmemiş",
   "compose_form.spoiler.marked": "Metin uyarının arkasına gizlenir",
@@ -209,6 +210,7 @@
   "lightbox.close": "Kapat",
   "lightbox.next": "Sonraki",
   "lightbox.previous": "Önceli",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Listeye ekle",
   "lists.account.remove": "Listeden kaldır",
   "lists.delete": "Listeyi sil",
@@ -340,7 +342,6 @@
   "status.reply": "Cevapla",
   "status.replyAll": "Konuşmayı cevapla",
   "status.report": "@{name}'i raporla",
-  "status.sensitive_toggle": "Görmek için tıklayınız",
   "status.sensitive_warning": "Hassas içerik",
   "status.share": "Paylaş",
   "status.show_less": "Daha az göster",
diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json
index 51a48a2b2..d02b652ff 100644
--- a/app/javascript/mastodon/locales/uk.json
+++ b/app/javascript/mastodon/locales/uk.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "Дмухнути",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "Медіа відмічене <b>несприйнятливим</b>",
   "compose_form.sensitive.unmarked": "Медіа відмічене сприйнятливим",
   "compose_form.spoiler.marked": "Текст приховано за попередженням",
@@ -209,6 +210,7 @@
   "lightbox.close": "Закрити",
   "lightbox.next": "Далі",
   "lightbox.previous": "Назад",
+  "lightbox.view_context": "View context",
   "lists.account.add": "Додати до списку",
   "lists.account.remove": "Видалити зі списку",
   "lists.delete": "Видалити список",
@@ -340,7 +342,6 @@
   "status.reply": "Відповісти",
   "status.replyAll": "Відповісти на тред",
   "status.report": "Поскаржитися",
-  "status.sensitive_toggle": "Натисніть, щоб подивитися",
   "status.sensitive_warning": "Непристойний зміст",
   "status.share": "Share",
   "status.show_less": "Згорнути",
diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json
index f9c6b4d41..960d4bb95 100644
--- a/app/javascript/mastodon/locales/zh-CN.json
+++ b/app/javascript/mastodon/locales/zh-CN.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "嘟嘟",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "媒体已被标记为敏感内容",
   "compose_form.sensitive.unmarked": "媒体未被标记为敏感内容",
   "compose_form.spoiler.marked": "正文已被折叠在警告信息之后",
@@ -209,6 +210,7 @@
   "lightbox.close": "关闭",
   "lightbox.next": "下一步",
   "lightbox.previous": "上一步",
+  "lightbox.view_context": "View context",
   "lists.account.add": "添加到列表",
   "lists.account.remove": "从列表中删除",
   "lists.delete": "删除列表",
@@ -340,7 +342,6 @@
   "status.reply": "回复",
   "status.replyAll": "回复所有人",
   "status.report": "举报 @{name}",
-  "status.sensitive_toggle": "点击显示",
   "status.sensitive_warning": "敏感内容",
   "status.share": "分享",
   "status.show_less": "隐藏内容",
diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json
index ed448f65a..a2d7b0e82 100644
--- a/app/javascript/mastodon/locales/zh-HK.json
+++ b/app/javascript/mastodon/locales/zh-HK.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "Remove this choice",
   "compose_form.publish": "發文",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "媒體被標示為敏感",
   "compose_form.sensitive.unmarked": "媒體沒有被標示為敏感",
   "compose_form.spoiler.marked": "文字被警告隱藏",
@@ -209,6 +210,7 @@
   "lightbox.close": "關閉",
   "lightbox.next": "繼續",
   "lightbox.previous": "回退",
+  "lightbox.view_context": "View context",
   "lists.account.add": "新增到列表",
   "lists.account.remove": "從列表刪除",
   "lists.delete": "刪除列表",
@@ -340,7 +342,6 @@
   "status.reply": "回應",
   "status.replyAll": "回應所有人",
   "status.report": "舉報 @{name}",
-  "status.sensitive_toggle": "點擊顯示",
   "status.sensitive_warning": "敏感內容",
   "status.share": "分享",
   "status.show_less": "減少顯示",
diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json
index b43a0b72c..7b01ce4dd 100644
--- a/app/javascript/mastodon/locales/zh-TW.json
+++ b/app/javascript/mastodon/locales/zh-TW.json
@@ -77,6 +77,7 @@
   "compose_form.poll.remove_option": "移除此選擇",
   "compose_form.publish": "嘟掉",
   "compose_form.publish_loud": "{publish}!",
+  "compose_form.sensitive.hide": "Mark media as sensitive",
   "compose_form.sensitive.marked": "此媒體被標記為敏感內容",
   "compose_form.sensitive.unmarked": "此媒體未被標記為敏感內容",
   "compose_form.spoiler.marked": "正文已隱藏在警告之後",
@@ -209,6 +210,7 @@
   "lightbox.close": "關閉",
   "lightbox.next": "下一步",
   "lightbox.previous": "上一步",
+  "lightbox.view_context": "View context",
   "lists.account.add": "新增至名單",
   "lists.account.remove": "從名單中移除",
   "lists.delete": "刪除名單",
@@ -340,7 +342,6 @@
   "status.reply": "回覆",
   "status.replyAll": "回覆所有人",
   "status.report": "檢舉 @{name}",
-  "status.sensitive_toggle": "點擊顯示",
   "status.sensitive_warning": "敏感內容",
   "status.share": "分享",
   "status.show_less": "減少顯示",
diff --git a/app/javascript/mastodon/reducers/settings.js b/app/javascript/mastodon/reducers/settings.js
index a0eea137f..419c313af 100644
--- a/app/javascript/mastodon/reducers/settings.js
+++ b/app/javascript/mastodon/reducers/settings.js
@@ -14,6 +14,8 @@ const initialState = ImmutableMap({
 
   skinTone: 1,
 
+  forceSingleColumn: false,
+
   home: ImmutableMap({
     shows: ImmutableMap({
       reblog: true,
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index 19e7ac41b..56610374e 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -1788,16 +1788,6 @@ a.account__display-name {
   }
 }
 
-@media screen and (min-width: 360px) {
-  .columns-area {
-    padding: 10px;
-  }
-
-  .react-swipeable-view-container .columns-area {
-    height: calc(100% - 20px) !important;
-  }
-}
-
 .react-swipeable-view-container {
   &,
   .columns-area,
@@ -1860,36 +1850,6 @@ a.account__display-name {
   overflow: hidden;
 }
 
-@media screen and (min-width: 360px) {
-  .tabs-bar {
-    margin: 10px;
-    margin-bottom: 0;
-  }
-
-  .getting-started__wrapper,
-  .getting-started__trends,
-  .search {
-    margin-bottom: 10px;
-  }
-}
-
-@media screen and (max-width: 630px) {
-  .column,
-  .drawer {
-    width: 100%;
-    padding: 0;
-  }
-
-  .columns-area {
-    flex-direction: column;
-  }
-
-  .search__input,
-  .autosuggest-textarea__textarea {
-    font-size: 16px;
-  }
-}
-
 @media screen and (min-width: 631px) {
   .columns-area {
     padding: 0;
@@ -1920,6 +1880,172 @@ a.account__display-name {
   }
 }
 
+.tabs-bar {
+  box-sizing: border-box;
+  display: flex;
+  background: lighten($ui-base-color, 8%);
+  flex: 0 0 auto;
+  overflow-y: auto;
+}
+
+.tabs-bar__link {
+  display: block;
+  flex: 1 1 auto;
+  padding: 15px 10px;
+  color: $primary-text-color;
+  text-decoration: none;
+  text-align: center;
+  font-size: 14px;
+  font-weight: 500;
+  border-bottom: 2px solid lighten($ui-base-color, 8%);
+  transition: all 50ms linear;
+  transition-property: border-bottom, background, color;
+
+  .fa {
+    font-weight: 400;
+    font-size: 16px;
+  }
+
+  &.active {
+    border-bottom: 2px solid $highlight-text-color;
+    color: $highlight-text-color;
+  }
+
+  &:hover,
+  &:focus,
+  &:active {
+    @media screen and (min-width: 631px) {
+      background: lighten($ui-base-color, 14%);
+    }
+  }
+
+  span {
+    margin-left: 5px;
+    display: none;
+  }
+}
+
+@media screen and (min-width: 600px) {
+  .tabs-bar__link {
+    span {
+      display: inline;
+    }
+  }
+}
+
+.columns-area--mobile {
+  flex-direction: column;
+  width: 100%;
+  max-width: 600px;
+  margin: 0 auto;
+
+  .column,
+  .drawer {
+    width: 100%;
+    height: 100%;
+    padding: 0;
+  }
+
+  .search__input,
+  .autosuggest-textarea__textarea {
+    font-size: 16px;
+  }
+
+  @media screen and (min-width: 360px) {
+    padding: 10px;
+  }
+
+  @media screen and (min-width: 630px) {
+    .detailed-status {
+      padding: 15px;
+
+      .media-gallery,
+      .video-player {
+        margin-top: 15px;
+      }
+    }
+
+    .account__header__bar {
+      padding: 5px 10px;
+    }
+
+    .navigation-bar,
+    .compose-form {
+      padding: 15px;
+    }
+
+    .compose-form .compose-form__publish .compose-form__publish-button-wrapper {
+      padding-top: 15px;
+    }
+
+    .status {
+      padding: 15px 15px 15px (48px + 15px * 2);
+      min-height: 48px + 2px;
+
+      &__avatar {
+        left: 15px;
+        top: 17px;
+      }
+
+      &__content {
+        padding-top: 5px;
+      }
+
+      &__prepend {
+        margin-left: 48px + 15px * 2;
+        padding-top: 15px;
+      }
+
+      &__prepend-icon-wrapper {
+        left: -32px;
+      }
+
+      .media-gallery,
+      &__action-bar,
+      .video-player {
+        margin-top: 10px;
+      }
+    }
+  }
+}
+
+@media screen and (min-width: 360px) {
+  .tabs-bar {
+    margin: 10px auto;
+    margin-bottom: 0;
+    width: calc(100% - 20px);
+    max-width: 600px;
+  }
+
+  .react-swipeable-view-container .columns-area--mobile {
+    height: calc(100% - 20px) !important;
+  }
+
+  .getting-started__wrapper,
+  .getting-started__trends,
+  .search {
+    margin-bottom: 10px;
+  }
+}
+
+.icon-with-badge {
+  position: relative;
+
+  &__badge {
+    position: absolute;
+    right: -13px;
+    top: -13px;
+    background: $ui-highlight-color;
+    border: 2px solid lighten($ui-base-color, 8%);
+    padding: 1px 6px;
+    border-radius: 6px;
+    font-size: 10px;
+    font-weight: 500;
+    line-height: 14px;
+    color: $primary-text-color;
+  }
+}
+
 .drawer__pager {
   box-sizing: border-box;
   padding: 0;
@@ -1952,6 +2078,7 @@ a.account__display-name {
   background: lighten($ui-base-color, 13%) url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 234.80078 31.757813" width="234.80078" height="31.757812"><path d="M19.599609 0c-1.05 0-2.10039.375-2.90039 1.125L0 16.925781v14.832031h234.80078V17.025391l-16.5-15.900391c-1.6-1.5-4.20078-1.5-5.80078 0l-13.80078 13.099609c-1.6 1.5-4.19883 1.5-5.79883 0L179.09961 1.125c-1.6-1.5-4.19883-1.5-5.79883 0L159.5 14.224609c-1.6 1.5-4.20078 1.5-5.80078 0L139.90039 1.125c-1.6-1.5-4.20078-1.5-5.80078 0l-13.79883 13.099609c-1.6 1.5-4.20078 1.5-5.80078 0L100.69922 1.125c-1.600001-1.5-4.198829-1.5-5.798829 0l-13.59961 13.099609c-1.6 1.5-4.200781 1.5-5.800781 0L61.699219 1.125c-1.6-1.5-4.198828-1.5-5.798828 0L42.099609 14.224609c-1.6 1.5-4.198828 1.5-5.798828 0L22.5 1.125C21.7.375 20.649609 0 19.599609 0z" fill="#{hex-color($ui-base-color)}"/></svg>') no-repeat bottom / 100% auto;
   flex: 1;
   min-height: 47px;
+  display: none;
 
   > img {
     display: block;
@@ -1963,6 +2090,19 @@ a.account__display-name {
     user-drag: none;
     user-select: none;
   }
+
+  @media screen and (min-height: 640px) {
+    display: block;
+  }
+}
+
+.navigational-toggle {
+  padding: 10px;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  font-size: 14px;
+  color: $dark-text-color;
 }
 
 .pseudo-drawer {
@@ -1989,64 +2129,6 @@ a.account__display-name {
   }
 }
 
-.tabs-bar {
-  display: flex;
-  background: lighten($ui-base-color, 8%);
-  flex: 0 0 auto;
-  overflow-y: auto;
-}
-
-.tabs-bar__link {
-  display: block;
-  flex: 1 1 auto;
-  padding: 15px 10px;
-  color: $primary-text-color;
-  text-decoration: none;
-  text-align: center;
-  font-size: 14px;
-  font-weight: 500;
-  border-bottom: 2px solid lighten($ui-base-color, 8%);
-  transition: all 50ms linear;
-  transition-property: border-bottom, background, color;
-
-  .fa {
-    font-weight: 400;
-    font-size: 16px;
-  }
-
-  &.active {
-    border-bottom: 2px solid $highlight-text-color;
-    color: $highlight-text-color;
-  }
-
-  &:hover,
-  &:focus,
-  &:active {
-    @media screen and (min-width: 631px) {
-      background: lighten($ui-base-color, 14%);
-    }
-  }
-
-  span {
-    margin-left: 5px;
-    display: none;
-  }
-}
-
-@media screen and (min-width: 600px) {
-  .tabs-bar__link {
-    span {
-      display: inline;
-    }
-  }
-}
-
-@media screen and (min-width: 631px) {
-  .tabs-bar {
-    display: none;
-  }
-}
-
 .scrollable {
   overflow-y: scroll;
   overflow-x: hidden;
@@ -3190,6 +3272,10 @@ a.status-card.compact:hover {
     contain: strict;
   }
 
+  & > span {
+    max-width: 400px;
+  }
+
   a {
     color: $highlight-text-color;
     text-decoration: none;
@@ -3279,6 +3365,7 @@ a.status-card.compact:hover {
   box-shadow: 4px 4px 6px rgba($base-shadow-color, 0.4);
   border-radius: 4px;
   margin-top: 5px;
+  z-index: 2;
 
   .emoji-mart-scroll {
     transition: opacity 200ms ease;
@@ -5610,3 +5697,49 @@ noscript {
     }
   }
 }
+
+.layout-toggle {
+  display: flex;
+  padding: 5px;
+
+  button {
+    box-sizing: border-box;
+    flex: 0 0 50%;
+    background: transparent;
+    padding: 5px;
+    border: 0;
+    position: relative;
+
+    &:hover,
+    &:focus,
+    &:active {
+      svg path:first-child {
+        fill: lighten($ui-base-color, 16%);
+      }
+    }
+  }
+
+  svg {
+    width: 100%;
+    height: auto;
+
+    path:first-child {
+      fill: lighten($ui-base-color, 12%);
+    }
+
+    path:last-child {
+      fill: darken($ui-base-color, 14%);
+    }
+  }
+
+  &__active {
+    color: $ui-highlight-color;
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    background: lighten($ui-base-color, 12%);
+    border-radius: 50%;
+    padding: 0.35rem;
+  }
+}
diff --git a/app/models/notification.rb b/app/models/notification.rb
index 300269e24..498673ff1 100644
--- a/app/models/notification.rb
+++ b/app/models/notification.rb
@@ -41,9 +41,13 @@ class Notification < ApplicationRecord
   validates :account_id, uniqueness: { scope: [:activity_type, :activity_id] }
   validates :activity_type, inclusion: { in: TYPE_CLASS_MAP.values }
 
-  scope :browserable, ->(exclude_types = []) {
+  scope :browserable, ->(exclude_types = [], account_id = nil) {
     types = TYPE_CLASS_MAP.values - activity_types_from_types(exclude_types + [:follow_request])
-    where(activity_type: types)
+    if account_id.nil?
+      where(activity_type: types)
+    else
+      where(activity_type: types, from_account_id: account_id)
+    end
   }
 
   cache_associated :from_account, status: STATUS_INCLUDES, mention: [status: STATUS_INCLUDES], favourite: [:account, status: STATUS_INCLUDES], follow: :account, poll: [status: STATUS_INCLUDES]
diff --git a/app/workers/activitypub/delivery_worker.rb b/app/workers/activitypub/delivery_worker.rb
index f9c385ea3..5e4c391f0 100644
--- a/app/workers/activitypub/delivery_worker.rb
+++ b/app/workers/activitypub/delivery_worker.rb
@@ -51,7 +51,7 @@ class ActivityPub::DeliveryWorker
   end
 
   def response_error_unsalvageable?(response)
-    (400...500).cover?(response.code) && response.code != 429
+    (400...500).cover?(response.code) && ![401, 408, 429].include?(response.code)
   end
 
   def failure_tracker
diff --git a/config/locales/sk.yml b/config/locales/sk.yml
index ff0d69fb0..e770d26ba 100644
--- a/config/locales/sk.yml
+++ b/config/locales/sk.yml
@@ -14,7 +14,7 @@ sk:
     browse_public_posts: Prebádaj naživo prúd verejných príspevkov na Mastodone
     contact: Kontakt
     contact_missing: Nezadaný
-    contact_unavailable: Neuvedený
+    contact_unavailable: Neuvedený/á
     discover_users: Objavuj užívateľov
     documentation: Dokumentácia
     extended_description_html: |
@@ -67,9 +67,9 @@ sk:
       other: Príspevky
     posts_tab_heading: Príspevky
     posts_with_replies: Príspevky s odpoveďami
-    reserved_username: Prihlasovacie meno je rezervované
+    reserved_username: Prihlasovacie meno je vyhradené
     roles:
-      admin: Administrátor
+      admin: Správca
       bot: Bot
       moderator: Moderátor
     unavailable: Profil nieje dostupný
@@ -177,7 +177,7 @@ sk:
       silenced: Stíšený/é
       statuses: Príspevky
       subscribe: Odoberaj
-      suspended: Zablokovaní
+      suspended: Vylúčený/á
       title: Účty
       unconfirmed_email: Nepotvrdený email
       undo_silenced: Zruš stíšenie
@@ -288,10 +288,10 @@ sk:
       reject_reports: Zamietni hlásenia
       reject_reports_hint: Ignoruj všetky hlásenia prichádzajúce z tejto domény. Nevplýva na blokovania
       rejecting_media: odmietanie médiálnych súborov
-      rejecting_reports: odmietané hlásenia
+      rejecting_reports: odmietanie hlásení
       severity:
-        silence: stíšený
-        suspend: vylúčený
+        silence: stíšené
+        suspend: vylúčené
       show:
         affected_accounts:
           few: Je ovplyvnených %{count} účtov v databázi
@@ -315,7 +315,7 @@ sk:
       title: Blokované emailové adresy
     followers:
       back_to_account: Späť na účet
-      title: Následovatielia užívateľa %{acct}
+      title: Sledovatielia užívateľa %{acct}
     instances:
       by_domain: Doména
       delivery_available: Je v dosahu doručovania
@@ -464,7 +464,7 @@ sk:
     statuses:
       back_to_account: Späť na účet
       batch:
-        delete: Vymazať
+        delete: Vymaž
         nsfw_off: Označ ako nechúlostivé
         nsfw_on: Označ ako chúlostivé
       failed_to_execute: Nepodarilo sa vykonať
@@ -992,5 +992,5 @@ sk:
     seamless_external_login: Si prihlásená/ý cez externú službu, takže nastavenia hesla a emailu ti niesú prístupné.
     signed_in_as: 'Prihlásená/ý ako:'
   verification:
-    explanation_html: 'Môžeš sa <strong>overiť ako majiteľ odkazov v metadátach tvojho profilu</strong>. Na to musí ale odkazovaná stránka obsahovať odkaz späť na tvoj Mastodon profil. Tento spätný odkaz <strong>musí</strong> mať prívlastok <code>rel="me"</code>. Na texte odkazu nezáleží. Tu je príklad:'
+    explanation_html: 'Môžeš sa <strong>overiť ako majiteľ odkazov v metadátach tvojho profilu</strong>. Na to ale musí odkazovaná stránka obsahovať odkaz späť na tvoj Mastodon profil. Tento spätný odkaz <strong>musí</strong> mať prívlastok <code>rel="me"</code>. Na texte odkazu nezáleží. Tu je príklad:'
     verification: Overenie
diff --git a/package.json b/package.json
index 8262c73aa..826a1935b 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
   "name": "mastodon",
   "license": "AGPL-3.0-or-later",
   "engines": {
-    "node": ">=8 <11"
+    "node": ">=8.12 <12"
   },
   "scripts": {
     "postversion": "git push --tags",
@@ -70,6 +70,7 @@
     "@babel/preset-env": "^7.3.4",
     "@babel/preset-react": "^7.0.0",
     "@babel/runtime": "^7.3.4",
+    "@clusterws/cws": "^0.14.0",
     "array-includes": "^3.0.3",
     "atrament": "^0.2.3",
     "autoprefixer": "^9.4.10",
@@ -160,7 +161,6 @@
     "tiny-queue": "^0.2.1",
     "uglifyjs-webpack-plugin": "^2.1.2",
     "uuid": "^3.1.0",
-    "uws": "10.148.0",
     "webpack": "^4.29.6",
     "webpack-assets-manifest": "^3.1.1",
     "webpack-bundle-analyzer": "^3.1.0",
diff --git a/spec/controllers/api/v1/notifications_controller_spec.rb b/spec/controllers/api/v1/notifications_controller_spec.rb
index d0f82e79f..db3f4b782 100644
--- a/spec/controllers/api/v1/notifications_controller_spec.rb
+++ b/spec/controllers/api/v1/notifications_controller_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe Api::V1::NotificationsController, type: :controller do
   let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
   let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
   let(:other) { Fabricate(:user, account: Fabricate(:account, username: 'bob')) }
+  let(:third) { Fabricate(:user, account: Fabricate(:account, username: 'carol')) }
 
   before do
     allow(controller).to receive(:doorkeeper_token) { token }
@@ -55,6 +56,7 @@ RSpec.describe Api::V1::NotificationsController, type: :controller do
       mentioning_status = PostStatusService.new.call(other.account, text: 'Hello @alice')
       @mention_from_status = mentioning_status.mentions.first
       @favourite = FavouriteService.new.call(other.account, first_status)
+      @second_favourite = FavouriteService.new.call(third.account, first_status)
       @follow = FollowService.new.call(other.account, 'alice')
     end
 
@@ -84,6 +86,66 @@ RSpec.describe Api::V1::NotificationsController, type: :controller do
       end
     end
 
+    describe 'from specified user' do
+      before do
+        get :index, params: { account_id: third.account.id }
+      end
+
+      it 'returns http success' do
+        expect(response).to have_http_status(200)
+      end
+
+      it 'includes favourite' do
+        expect(assigns(:notifications).map(&:activity)).to include(@second_favourite)
+      end
+
+      it 'excludes favourite' do
+        expect(assigns(:notifications).map(&:activity)).to_not include(@favourite)
+      end
+
+      it 'excludes mention' do
+        expect(assigns(:notifications).map(&:activity)).to_not include(@mention_from_status)
+      end
+
+      it 'excludes reblog' do
+        expect(assigns(:notifications).map(&:activity)).to_not include(@reblog_of_first_status)
+      end
+
+      it 'excludes follow' do
+        expect(assigns(:notifications).map(&:activity)).to_not include(@follow)
+      end
+    end
+
+    describe 'from nonexistent user' do
+      before do
+        get :index, params: { account_id: 'foo' }
+      end
+
+      it 'returns http success' do
+        expect(response).to have_http_status(200)
+      end
+
+      it 'excludes favourite' do
+        expect(assigns(:notifications).map(&:activity)).to_not include(@favourite)
+      end
+
+      it 'excludes second favourite' do
+        expect(assigns(:notifications).map(&:activity)).to_not include(@second_favourite)
+      end
+
+      it 'excludes mention' do
+        expect(assigns(:notifications).map(&:activity)).to_not include(@mention_from_status)
+      end
+
+      it 'excludes reblog' do
+        expect(assigns(:notifications).map(&:activity)).to_not include(@reblog_of_first_status)
+      end
+
+      it 'excludes follow' do
+        expect(assigns(:notifications).map(&:activity)).to_not include(@follow)
+      end
+    end
+
     describe 'with excluded mentions' do
       before do
         get :index, params: { exclude_types: ['mention'] }
@@ -105,6 +167,10 @@ RSpec.describe Api::V1::NotificationsController, type: :controller do
         expect(assigns(:notifications).map(&:activity)).to include(@favourite)
       end
 
+      it 'includes third favourite' do
+        expect(assigns(:notifications).map(&:activity)).to include(@second_favourite)
+      end
+
       it 'includes follow' do
         expect(assigns(:notifications).map(&:activity)).to include(@follow)
       end
diff --git a/streaming/index.js b/streaming/index.js
index d4fb8cad3..55ecc3ba3 100644
--- a/streaming/index.js
+++ b/streaming/index.js
@@ -7,7 +7,7 @@ const redis = require('redis');
 const pg = require('pg');
 const log = require('npmlog');
 const url = require('url');
-const WebSocket = require('uws');
+const { WebSocketServer } = require('@clusterws/cws');
 const uuid = require('uuid');
 const fs = require('fs');
 
@@ -542,20 +542,13 @@ const startWorker = (workerId) => {
     });
   });
 
-  const wss = new WebSocket.Server({ server, verifyClient: wsVerifyClient });
+  const wss = new WebSocketServer({ server, verifyClient: wsVerifyClient });
 
-  wss.on('connection', ws => {
-    const req      = ws.upgradeReq;
+  wss.on('connection', (ws, req) => {
     const location = url.parse(req.url, true);
     req.requestId  = uuid.v4();
     req.remoteAddress = ws._socket.remoteAddress;
 
-    ws.isAlive = true;
-
-    ws.on('pong', () => {
-      ws.isAlive = true;
-    });
-
     let channel;
 
     switch(location.query.stream) {
@@ -616,17 +609,7 @@ const startWorker = (workerId) => {
     }
   });
 
-  setInterval(() => {
-    wss.clients.forEach(ws => {
-      if (ws.isAlive === false) {
-        ws.terminate();
-        return;
-      }
-
-      ws.isAlive = false;
-      ws.ping('', false, true);
-    });
-  }, 30000);
+  wss.startAutoPing(30000);
 
   attachServerWithConfig(server, address => {
     log.info(`Worker ${workerId} now listening on ${address}`);
diff --git a/yarn.lock b/yarn.lock
index 377a3523d..0165277b4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -782,6 +782,11 @@
     lodash "^4.17.11"
     to-fast-properties "^2.0.0"
 
+"@clusterws/cws@^0.14.0":
+  version "0.14.0"
+  resolved "https://registry.yarnpkg.com/@clusterws/cws/-/cws-0.14.0.tgz#242824b6884454001340222a836db6f6c5e62bfb"
+  integrity sha512-knZj3KZNHIAGsX7TUc/0Q5gcx2bKMMcTPsAOZomLKdK5a4o/umKFlttWRH84Yr1nVlQy+UMO23qfDR8gRZ/4cw==
+
 "@cnakazawa/watch@^1.0.3":
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.3.tgz#099139eaec7ebf07a27c1786a3ff64f39464d2ef"
@@ -9277,11 +9282,6 @@ uuid@^3.0.1, uuid@^3.1.0, uuid@^3.3.2:
   resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
   integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
 
-uws@10.148.0:
-  version "10.148.0"
-  resolved "https://registry.yarnpkg.com/uws/-/uws-10.148.0.tgz#3fcd35f083ca515e091cd33b2d78f0f51a666215"
-  integrity sha512-aJpFgMMyxubiE/ll4nj9nWoQbv0HzZZDWXfwyu78nuFObX0Zoyv3TWjkqKPQ1vb2sMPZoz67tri7QNE6dybNmQ==
-
 v8-compile-cache@^2.0.2:
   version "2.0.2"
   resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz#a428b28bb26790734c4fc8bc9fa106fccebf6a6c"