about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Gemfile22
-rw-r--r--Gemfile.lock105
-rw-r--r--app/controllers/api/base_controller.rb4
-rw-r--r--app/controllers/api/v1/accounts/statuses_controller.rb7
-rw-r--r--app/controllers/api/v1/favourites_controller.rb7
-rw-r--r--app/controllers/api/v1/instances_controller.rb4
-rw-r--r--app/controllers/api/v1/notifications_controller.rb7
-rw-r--r--app/controllers/api/v1/reports_controller.rb5
-rw-r--r--app/controllers/api/v1/timelines/home_controller.rb5
-rw-r--r--app/controllers/api/v1/timelines/list_controller.rb5
-rw-r--r--app/controllers/api/v1/timelines/public_controller.rb7
-rw-r--r--app/controllers/api/v1/timelines/tag_controller.rb7
-rw-r--r--app/controllers/settings/preferences_controller.rb3
-rw-r--r--app/helpers/application_helper.rb4
-rw-r--r--app/javascript/flavours/glitch/components/media_gallery.js4
-rw-r--r--app/javascript/flavours/glitch/features/video/index.js4
-rw-r--r--app/javascript/flavours/glitch/styles/about.scss46
-rw-r--r--app/javascript/flavours/glitch/styles/admin.scss2
-rw-r--r--app/javascript/flavours/glitch/styles/basics.scss6
-rw-r--r--app/javascript/flavours/glitch/styles/containers.scss4
-rw-r--r--app/javascript/flavours/glitch/styles/dashboard.scss2
-rw-r--r--app/javascript/flavours/glitch/styles/forms.scss8
-rw-r--r--app/javascript/flavours/glitch/styles/rtl.scss22
-rw-r--r--app/javascript/flavours/glitch/styles/tables.scss2
-rw-r--r--app/javascript/flavours/glitch/styles/variables.scss4
-rw-r--r--app/javascript/flavours/glitch/util/initial_state.js1
-rw-r--r--app/javascript/mastodon/actions/importer/normalizer.js3
-rw-r--r--app/javascript/mastodon/components/__tests__/__snapshots__/autosuggest_emoji-test.js.snap27
-rw-r--r--app/javascript/mastodon/components/__tests__/autosuggest_emoji-test.js29
-rw-r--r--app/javascript/mastodon/components/media_gallery.js4
-rw-r--r--app/javascript/mastodon/components/status.js2
-rw-r--r--app/javascript/mastodon/components/status_content.js40
-rw-r--r--app/javascript/mastodon/features/account_gallery/components/media_item.js4
-rw-r--r--app/javascript/mastodon/features/notifications/components/column_settings.js9
-rw-r--r--app/javascript/mastodon/features/notifications/components/notification.js5
-rw-r--r--app/javascript/mastodon/features/notifications/components/setting_toggle.js4
-rw-r--r--app/javascript/mastodon/features/ui/index.js8
-rw-r--r--app/javascript/mastodon/features/video/index.js15
-rw-r--r--app/javascript/mastodon/initial_state.js3
-rw-r--r--app/javascript/mastodon/locales/ar.json1
-rw-r--r--app/javascript/mastodon/locales/ast.json1
-rw-r--r--app/javascript/mastodon/locales/bg.json1
-rw-r--r--app/javascript/mastodon/locales/ca.json1
-rw-r--r--app/javascript/mastodon/locales/co.json1
-rw-r--r--app/javascript/mastodon/locales/cs.json1
-rw-r--r--app/javascript/mastodon/locales/cy.json668
-rw-r--r--app/javascript/mastodon/locales/da.json1
-rw-r--r--app/javascript/mastodon/locales/de.json1
-rw-r--r--app/javascript/mastodon/locales/defaultMessages.json6
-rw-r--r--app/javascript/mastodon/locales/el.json1
-rw-r--r--app/javascript/mastodon/locales/en.json1
-rw-r--r--app/javascript/mastodon/locales/eo.json1
-rw-r--r--app/javascript/mastodon/locales/es.json1
-rw-r--r--app/javascript/mastodon/locales/eu.json1
-rw-r--r--app/javascript/mastodon/locales/fa.json1
-rw-r--r--app/javascript/mastodon/locales/fi.json1
-rw-r--r--app/javascript/mastodon/locales/fr.json1
-rw-r--r--app/javascript/mastodon/locales/gl.json1
-rw-r--r--app/javascript/mastodon/locales/he.json1
-rw-r--r--app/javascript/mastodon/locales/hr.json1
-rw-r--r--app/javascript/mastodon/locales/hu.json1
-rw-r--r--app/javascript/mastodon/locales/hy.json1
-rw-r--r--app/javascript/mastodon/locales/id.json1
-rw-r--r--app/javascript/mastodon/locales/io.json1
-rw-r--r--app/javascript/mastodon/locales/it.json23
-rw-r--r--app/javascript/mastodon/locales/ja.json1
-rw-r--r--app/javascript/mastodon/locales/ka.json1
-rw-r--r--app/javascript/mastodon/locales/ko.json1
-rw-r--r--app/javascript/mastodon/locales/nl.json1
-rw-r--r--app/javascript/mastodon/locales/no.json1
-rw-r--r--app/javascript/mastodon/locales/oc.json1
-rw-r--r--app/javascript/mastodon/locales/pl.json1
-rw-r--r--app/javascript/mastodon/locales/pt-BR.json1
-rw-r--r--app/javascript/mastodon/locales/pt.json1
-rw-r--r--app/javascript/mastodon/locales/ro.json1
-rw-r--r--app/javascript/mastodon/locales/ru.json1
-rw-r--r--app/javascript/mastodon/locales/sk.json1
-rw-r--r--app/javascript/mastodon/locales/sl.json1
-rw-r--r--app/javascript/mastodon/locales/sr-Latn.json1
-rw-r--r--app/javascript/mastodon/locales/sr.json1
-rw-r--r--app/javascript/mastodon/locales/sv.json1
-rw-r--r--app/javascript/mastodon/locales/ta.json1
-rw-r--r--app/javascript/mastodon/locales/te.json1
-rw-r--r--app/javascript/mastodon/locales/th.json1
-rw-r--r--app/javascript/mastodon/locales/tr.json1
-rw-r--r--app/javascript/mastodon/locales/uk.json1
-rw-r--r--app/javascript/mastodon/locales/zh-CN.json1
-rw-r--r--app/javascript/mastodon/locales/zh-HK.json1
-rw-r--r--app/javascript/mastodon/locales/zh-TW.json1
-rw-r--r--app/javascript/mastodon/service_worker/web_push_notifications.js2
-rw-r--r--app/javascript/styles/mailer.scss2
-rw-r--r--app/javascript/styles/mastodon/about.scss46
-rw-r--r--app/javascript/styles/mastodon/admin.scss2
-rw-r--r--app/javascript/styles/mastodon/basics.scss6
-rw-r--r--app/javascript/styles/mastodon/components.scss33
-rw-r--r--app/javascript/styles/mastodon/containers.scss4
-rw-r--r--app/javascript/styles/mastodon/dashboard.scss2
-rw-r--r--app/javascript/styles/mastodon/forms.scss8
-rw-r--r--app/javascript/styles/mastodon/rtl.scss30
-rw-r--r--app/javascript/styles/mastodon/tables.scss2
-rw-r--r--app/javascript/styles/mastodon/variables.scss4
-rw-r--r--app/lib/activitypub/activity/create.rb2
-rw-r--r--app/lib/feed_manager.rb1
-rw-r--r--app/lib/user_settings_decorator.rb45
-rw-r--r--app/models/concerns/paginable.rb8
-rw-r--r--app/models/feed.rb16
-rw-r--r--app/models/home_feed.rb8
-rw-r--r--app/models/user.rb12
-rw-r--r--app/serializers/initial_state_serializer.rb19
-rw-r--r--app/views/accounts/_header.html.haml2
-rw-r--r--app/views/accounts/_moved.html.haml2
-rw-r--r--app/views/admin/reports/_status.html.haml4
-rw-r--r--app/views/settings/preferences/show.html.haml3
-rw-r--r--app/views/stream_entries/_detailed_status.html.haml8
-rw-r--r--app/views/stream_entries/_simple_status.html.haml8
-rw-r--r--config/boot.rb6
-rw-r--r--config/initializers/statsd.rb2
-rw-r--r--config/locales/ar.yml1
-rw-r--r--config/locales/cy.yml213
-rw-r--r--config/locales/devise.cy.yml18
-rw-r--r--config/locales/doorkeeper.cy.yml26
-rw-r--r--config/locales/es.yml2
-rw-r--r--config/locales/it.yml11
-rw-r--r--config/locales/pl.yml14
-rw-r--r--config/locales/simple_form.ar.yml1
-rw-r--r--config/locales/simple_form.ca.yml1
-rw-r--r--config/locales/simple_form.co.yml1
-rw-r--r--config/locales/simple_form.cs.yml1
-rw-r--r--config/locales/simple_form.cy.yml57
-rw-r--r--config/locales/simple_form.da.yml1
-rw-r--r--config/locales/simple_form.de.yml1
-rw-r--r--config/locales/simple_form.el.yml1
-rw-r--r--config/locales/simple_form.en.yml9
-rw-r--r--config/locales/simple_form.eo.yml1
-rw-r--r--config/locales/simple_form.es.yml1
-rw-r--r--config/locales/simple_form.eu.yml1
-rw-r--r--config/locales/simple_form.fa.yml1
-rw-r--r--config/locales/simple_form.fi.yml1
-rw-r--r--config/locales/simple_form.fr.yml1
-rw-r--r--config/locales/simple_form.gl.yml1
-rw-r--r--config/locales/simple_form.it.yml1
-rw-r--r--config/locales/simple_form.ja.yml8
-rw-r--r--config/locales/simple_form.ka.yml1
-rw-r--r--config/locales/simple_form.ko.yml1
-rw-r--r--config/locales/simple_form.nl.yml1
-rw-r--r--config/locales/simple_form.oc.yml1
-rw-r--r--config/locales/simple_form.pl.yml1
-rw-r--r--config/locales/simple_form.pt-BR.yml1
-rw-r--r--config/locales/simple_form.ro.yml1
-rw-r--r--config/locales/simple_form.ru.yml1
-rw-r--r--config/locales/simple_form.sk.yml5
-rw-r--r--config/locales/simple_form.sr.yml1
-rw-r--r--config/locales/simple_form.sv.yml1
-rw-r--r--config/locales/simple_form.zh-CN.yml1
-rw-r--r--config/locales/simple_form.zh-HK.yml1
-rw-r--r--config/locales/simple_form.zh-TW.yml1
-rw-r--r--config/locales/sk.yml12
-rw-r--r--config/locales/zh-CN.yml63
-rw-r--r--config/locales/zh-TW.yml4
-rw-r--r--config/routes.rb3
-rw-r--r--config/settings.yml3
-rw-r--r--config/sidekiq.yml8
-rw-r--r--dist/mastodon-sidekiq.service17
-rw-r--r--dist/mastodon-streaming.service17
-rw-r--r--dist/mastodon-web.service17
-rw-r--r--dist/nginx.conf106
-rw-r--r--docs/Contributing-to-Mastodon/Sponsors.md1
-rw-r--r--docs/Contributing-to-Mastodon/Translating.md1
-rw-r--r--docs/Extensions.md1
-rw-r--r--docs/README.md1
-rw-r--r--docs/Running-Mastodon/Administration-guide.md1
-rw-r--r--docs/Running-Mastodon/Development-guide.md1
-rw-r--r--docs/Running-Mastodon/Heroku-guide.md1
-rw-r--r--docs/Running-Mastodon/Production-guide.md1
-rw-r--r--docs/Running-Mastodon/Scalingo-guide.md1
-rw-r--r--docs/Running-Mastodon/Tuning.md1
-rw-r--r--docs/Running-Mastodon/Vagrant-guide.md1
-rw-r--r--docs/Specs-and-RFCs-used.md1
-rw-r--r--docs/Using-Mastodon/2FA.md1
-rw-r--r--docs/Using-Mastodon/Apps.md1
-rw-r--r--docs/Using-Mastodon/FAQ.md1
-rw-r--r--docs/Using-Mastodon/List-of-Mastodon-instances.md1
-rw-r--r--docs/Using-Mastodon/User-guide.md1
-rw-r--r--docs/Using-the-API/API.md1
-rw-r--r--docs/Using-the-API/OAuth-details.md1
-rw-r--r--docs/Using-the-API/Push-notifications.md1
-rw-r--r--docs/Using-the-API/Streaming-API.md1
-rw-r--r--docs/Using-the-API/Testing-with-cURL.md1
-rw-r--r--docs/Using-the-API/Tips-for-app-developers.md1
-rw-r--r--lib/mastodon/accounts_cli.rb26
-rw-r--r--spec/controllers/api/v1/favourites_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/reports_controller_spec.rb10
-rw-r--r--spec/helpers/application_helper_spec.rb8
193 files changed, 1389 insertions, 803 deletions
diff --git a/Gemfile b/Gemfile
index 27d65f272..ef2644eb2 100644
--- a/Gemfile
+++ b/Gemfile
@@ -12,7 +12,7 @@ gem 'thor', '~> 0.20'
 gem 'hamlit-rails', '~> 0.2'
 gem 'pg', '~> 1.0'
 gem 'makara', '~> 0.4'
-gem 'pghero', '~> 2.1'
+gem 'pghero', '~> 2.2'
 gem 'dotenv-rails', '~> 2.2', '< 2.3'
 
 gem 'aws-sdk-s3', '~> 1.9', require: false
@@ -24,13 +24,13 @@ gem 'streamio-ffmpeg', '~> 3.0'
 
 gem 'active_model_serializers', '~> 0.10'
 gem 'addressable', '~> 2.5'
-gem 'bootsnap', '~> 1.3'
+gem 'bootsnap', '~> 1.3', require: false
 gem 'browser'
 gem 'charlock_holmes', '~> 0.7.6'
 gem 'iso-639'
 gem 'chewy', '~> 5.0'
 gem 'cld3', '~> 3.2.0'
-gem 'devise', '~> 4.4'
+gem 'devise', '~> 4.5'
 gem 'devise-two-factor', '~> 3.0'
 
 group :pam_authentication, optional: true do
@@ -57,12 +57,12 @@ gem 'httplog', '~> 1.0'
 gem 'idn-ruby', require: 'idn'
 gem 'kaminari', '~> 1.1'
 gem 'link_header', '~> 0.0'
-gem 'mime-types', '~> 3.1', require: 'mime/types/columnar'
+gem 'mime-types', '~> 3.2', require: 'mime/types/columnar'
 gem 'nokogiri', '~> 1.8'
 gem 'nsa', '~> 0.2'
-gem 'oj', '~> 3.5'
+gem 'oj', '~> 3.6'
 gem 'ostatus2', '~> 2.0'
-gem 'ox', '~> 2.9'
+gem 'ox', '~> 2.10'
 gem 'posix-spawn', git: 'https://github.com/rtomayko/posix-spawn', ref: '58465d2e213991f8afb13b984854a49fcdcc980c'
 gem 'pundit', '~> 1.1'
 gem 'premailer-rails'
@@ -75,8 +75,8 @@ gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
 gem 'rqrcode', '~> 0.10'
 gem 'ruby-progressbar', '~> 1.4'
 gem 'sanitize', '~> 4.6'
-gem 'sidekiq', '~> 5.1'
-gem 'sidekiq-scheduler', '~> 2.2'
+gem 'sidekiq', '~> 5.2'
+gem 'sidekiq-scheduler', '~> 3.0'
 gem 'sidekiq-unique-jobs', '~> 5.0'
 gem 'sidekiq-bulk', '~>0.1.1'
 gem 'simple-navigation', '~> 4.0'
@@ -85,7 +85,7 @@ gem 'sprockets-rails', '~> 3.2', require: 'sprockets/railtie'
 gem 'stoplight', '~> 2.1.3'
 gem 'strong_migrations', '~> 0.2'
 gem 'tty-command', '~> 0.8', require: false
-gem 'tty-prompt', '~> 0.16', require: false
+gem 'tty-prompt', '~> 0.17', require: false
 gem 'twitter-text', '~> 1.14'
 gem 'tzinfo-data', '~> 1.2018'
 gem 'webpacker', '~> 3.5'
@@ -104,7 +104,7 @@ group :development, :test do
 end
 
 group :production, :test do
-  gem 'private_address_check', '~> 0.4.1'
+  gem 'private_address_check', '~> 0.5'
 end
 
 group :test do
@@ -133,7 +133,7 @@ group :development do
   gem 'bundler-audit', '~> 0.6', require: false
   gem 'scss_lint', '~> 0.57', require: false
 
-  gem 'capistrano', '~> 3.10'
+  gem 'capistrano', '~> 3.11'
   gem 'capistrano-rails', '~> 1.3'
   gem 'capistrano-rbenv', '~> 2.1'
   gem 'capistrano-yarn', '~> 2.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index e4e1c69df..f7e4fcd97 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -66,7 +66,7 @@ GEM
       public_suffix (>= 2.0.2, < 4.0)
     airbrussh (1.3.0)
       sshkit (>= 1.6.1, != 1.7.0)
-    annotate (2.7.3)
+    annotate (2.7.4)
       activerecord (>= 3.2, < 6.0)
       rake (>= 10.4, < 13.0)
     arel (9.0.0)
@@ -96,7 +96,7 @@ GEM
       rack (>= 0.9.0)
     binding_of_caller (0.8.0)
       debug_inspector (>= 0.0.1)
-    bootsnap (1.3.0)
+    bootsnap (1.3.2)
       msgpack (~> 1.0)
     brakeman (4.2.1)
     browser (2.5.3)
@@ -108,7 +108,7 @@ GEM
       bundler (~> 1.2)
       thor (~> 0.18)
     byebug (10.0.2)
-    capistrano (3.10.2)
+    capistrano (3.11.0)
       airbrussh (>= 1.0.0)
       i18n
       rake (>= 10.0.0)
@@ -147,7 +147,7 @@ GEM
     coderay (1.1.2)
     colorize (0.8.1)
     concurrent-ruby (1.0.5)
-    connection_pool (2.2.1)
+    connection_pool (2.2.2)
     crack (0.4.3)
       safe_yaml (~> 1.0.0)
     crass (1.0.4)
@@ -162,7 +162,7 @@ GEM
       rack (>= 1)
       rake (> 10, < 13)
       thor (~> 0.19)
-    devise (4.4.3)
+    devise (4.5.0)
       bcrypt (~> 3.0)
       orm_adapter (~> 0.1)
       railties (>= 4.1.0, < 6.0)
@@ -202,7 +202,7 @@ GEM
     encryptor (3.0.0)
     equatable (0.5.0)
     erubi (1.7.1)
-    et-orbi (1.1.0)
+    et-orbi (1.1.6)
       tzinfo
     excon (0.62.0)
     fabrication (2.20.1)
@@ -212,7 +212,7 @@ GEM
       multipart-post (>= 1.2, < 3)
     fast_blank (1.0.0)
     fastimage (2.1.1)
-    ffi (1.9.23)
+    ffi (1.9.25)
     fog-core (1.45.0)
       builder
       excon (~> 0.58)
@@ -225,6 +225,9 @@ GEM
       fog-json (>= 1.0)
       ipaddress (>= 0.8)
     formatador (0.2.5)
+    fugit (1.1.6)
+      et-orbi (~> 1.1, >= 1.1.6)
+      raabro (~> 1.1)
     fuubar (2.3.1)
       rspec-core (~> 3.0)
       ruby-progressbar (~> 1.4)
@@ -252,7 +255,7 @@ GEM
     heapy (0.1.3)
     highline (1.7.10)
     hiredis (0.6.1)
-    hitimes (1.2.6)
+    hitimes (1.3.0)
     hkdf (0.3.0)
     html2text (0.2.1)
       nokogiri (~> 1.6)
@@ -328,14 +331,14 @@ GEM
       mimemagic (~> 0.3.2)
     mario-redis-lock (1.2.1)
       redis (>= 3.0.5)
-    memory_profiler (0.9.10)
+    memory_profiler (0.9.11)
     method_source (0.9.0)
     microformats (4.0.7)
       json
       nokogiri
-    mime-types (3.1)
+    mime-types (3.2.2)
       mime-types-data (~> 3.2015)
-    mime-types-data (3.2016.0521)
+    mime-types-data (3.2018.0812)
     mimemagic (0.3.2)
     mini_mime (1.0.0)
     mini_portile2 (2.3.0)
@@ -347,7 +350,7 @@ GEM
     net-ldap (0.16.1)
     net-scp (1.2.1)
       net-ssh (>= 2.6.5)
-    net-ssh (4.2.0)
+    net-ssh (5.0.2)
     nio4r (2.3.1)
     nokogiri (1.8.4)
       mini_portile2 (~> 2.3.0)
@@ -358,7 +361,7 @@ GEM
       concurrent-ruby (~> 1.0.0)
       sidekiq (>= 3.5.0)
       statsd-ruby (~> 1.2.0)
-    oj (3.5.1)
+    oj (3.6.11)
     omniauth (1.8.1)
       hashie (>= 3.4.6, < 3.6.0)
       rack (>= 1.6.2, < 3)
@@ -374,7 +377,7 @@ GEM
       addressable (~> 2.5)
       http (~> 3.0)
       nokogiri (~> 1.8)
-    ox (2.9.2)
+    ox (2.10.0)
     paperclip (6.0.0)
       activemodel (>= 4.2.0)
       activesupport (>= 4.2.0)
@@ -393,9 +396,9 @@ GEM
       equatable (~> 0.5.0)
       tty-color (~> 0.4.0)
     pg (1.0.0)
-    pghero (2.1.0)
+    pghero (2.2.0)
       activerecord
-    pkg-config (1.3.0)
+    pkg-config (1.3.1)
     powerpack (0.1.1)
     premailer (1.11.1)
       addressable
@@ -404,7 +407,7 @@ GEM
     premailer-rails (1.10.2)
       actionmailer (>= 3, < 6)
       premailer (~> 1.7, >= 1.7.9)
-    private_address_check (0.4.1)
+    private_address_check (0.5.0)
     pry (0.11.3)
       coderay (~> 1.1.0)
       method_source (~> 0.9.0)
@@ -417,11 +420,12 @@ GEM
     puma (3.11.4)
     pundit (1.1.0)
       activesupport (>= 3.0.0)
+    raabro (1.1.6)
     rack (2.0.5)
     rack-attack (5.2.0)
       rack
     rack-cors (1.0.2)
-    rack-protection (2.0.1)
+    rack-protection (2.0.4)
       rack
     rack-proxy (0.6.4)
       rack
@@ -528,10 +532,10 @@ GEM
     ruby-progressbar (1.9.0)
     ruby-saml (1.7.2)
       nokogiri (>= 1.5.10)
-    rufus-scheduler (3.4.2)
-      et-orbi (~> 1.0)
+    rufus-scheduler (3.5.2)
+      fugit (~> 1.1, >= 1.1.5)
     safe_yaml (1.0.4)
-    sanitize (4.6.4)
+    sanitize (4.6.6)
       crass (~> 1.0.2)
       nokogiri (>= 1.4.4)
       nokogumbo (~> 1.4)
@@ -543,15 +547,14 @@ GEM
     scss_lint (0.57.0)
       rake (>= 0.9, < 13)
       sass (~> 3.5.5)
-    sidekiq (5.1.3)
-      concurrent-ruby (~> 1.0)
-      connection_pool (~> 2.2, >= 2.2.0)
+    sidekiq (5.2.2)
+      connection_pool (~> 2.2, >= 2.2.2)
       rack-protection (>= 1.5.0)
       redis (>= 3.3.5, < 5)
     sidekiq-bulk (0.1.1)
       activesupport
       sidekiq
-    sidekiq-scheduler (2.2.1)
+    sidekiq-scheduler (3.0.0)
       redis (>= 3, < 5)
       rufus-scheduler (~> 3.2)
       sidekiq (>= 3)
@@ -561,9 +564,9 @@ GEM
       thor (~> 0)
     simple-navigation (4.0.5)
       activesupport (>= 2.3.2)
-    simple_form (4.0.0)
-      actionpack (> 4)
-      activemodel (> 4)
+    simple_form (4.0.1)
+      actionpack (>= 5.0)
+      activemodel (>= 5.0)
     simplecov (0.16.1)
       docile (~> 1.1)
       json (>= 1.8, < 3)
@@ -576,15 +579,15 @@ GEM
       actionpack (>= 4.0)
       activesupport (>= 4.0)
       sprockets (>= 3.0.0)
-    sshkit (1.16.0)
+    sshkit (1.17.0)
       net-scp (>= 1.1.2)
       net-ssh (>= 2.8.0)
-    stackprof (0.2.11)
+    stackprof (0.2.12)
     statsd-ruby (1.2.1)
     stoplight (2.1.3)
     streamio-ffmpeg (3.0.2)
       multi_json (~> 1.8)
-    strong_migrations (0.2.2)
+    strong_migrations (0.2.3)
       activerecord (>= 3.2.0)
     temple (0.8.0)
     terminal-table (1.8.0)
@@ -597,26 +600,26 @@ GEM
     tilt (2.0.8)
     timers (4.1.2)
       hitimes
-    tty-color (0.4.2)
-    tty-command (0.8.0)
+    tty-color (0.4.3)
+    tty-command (0.8.2)
       pastel (~> 0.7.0)
-    tty-cursor (0.5.0)
-    tty-prompt (0.16.0)
+    tty-cursor (0.6.0)
+    tty-prompt (0.17.0)
       necromancer (~> 0.4.0)
       pastel (~> 0.7.0)
       timers (~> 4.0)
-      tty-cursor (~> 0.5.0)
-      tty-reader (~> 0.2.0)
-    tty-reader (0.2.0)
-      tty-cursor (~> 0.5.0)
+      tty-cursor (~> 0.6.0)
+      tty-reader (~> 0.4.0)
+    tty-reader (0.4.0)
+      tty-cursor (~> 0.6.0)
       tty-screen (~> 0.6.4)
       wisper (~> 2.0.0)
-    tty-screen (0.6.4)
+    tty-screen (0.6.5)
     twitter-text (1.14.7)
       unf (~> 0.1.0)
     tzinfo (1.2.5)
       thread_safe (~> 0.1)
-    tzinfo-data (1.2018.4)
+    tzinfo-data (1.2018.5)
       tzinfo (>= 1.0.0)
     unf (0.1.4)
       unf_ext
@@ -659,7 +662,7 @@ DEPENDENCIES
   browser
   bullet (~> 5.7)
   bundler-audit (~> 0.6)
-  capistrano (~> 3.10)
+  capistrano (~> 3.11)
   capistrano-rails (~> 1.3)
   capistrano-rbenv (~> 2.1)
   capistrano-yarn (~> 2.0)
@@ -669,7 +672,7 @@ DEPENDENCIES
   cld3 (~> 3.2.0)
   climate_control (~> 0.2)
   derailed_benchmarks
-  devise (~> 4.4)
+  devise (~> 4.5)
   devise-two-factor (~> 3.0)
   devise_pam_authenticatable2 (~> 9.2)
   doorkeeper (~> 5.0)
@@ -703,25 +706,25 @@ DEPENDENCIES
   mario-redis-lock (~> 1.2)
   memory_profiler
   microformats (~> 4.0)
-  mime-types (~> 3.1)
+  mime-types (~> 3.2)
   net-ldap (~> 0.10)
   nokogiri (~> 1.8)
   nsa (~> 0.2)
-  oj (~> 3.5)
+  oj (~> 3.6)
   omniauth (~> 1.2)
   omniauth-cas (~> 1.1)
   omniauth-saml (~> 1.10)
   ostatus2 (~> 2.0)
-  ox (~> 2.9)
+  ox (~> 2.10)
   paperclip (~> 6.0)
   paperclip-av-transcoder (~> 0.6)
   parallel_tests (~> 2.21)
   pg (~> 1.0)
-  pghero (~> 2.1)
+  pghero (~> 2.2)
   pkg-config (~> 1.3)
   posix-spawn!
   premailer-rails
-  private_address_check (~> 0.4.1)
+  private_address_check (~> 0.5)
   pry-byebug (~> 3.6)
   pry-rails (~> 0.3)
   puma (~> 3.11)
@@ -743,9 +746,9 @@ DEPENDENCIES
   ruby-progressbar (~> 1.4)
   sanitize (~> 4.6)
   scss_lint (~> 0.57)
-  sidekiq (~> 5.1)
+  sidekiq (~> 5.2)
   sidekiq-bulk (~> 0.1.1)
-  sidekiq-scheduler (~> 2.2)
+  sidekiq-scheduler (~> 3.0)
   sidekiq-unique-jobs (~> 5.0)
   simple-navigation (~> 4.0)
   simple_form (~> 4.0)
@@ -757,7 +760,7 @@ DEPENDENCIES
   strong_migrations (~> 0.2)
   thor (~> 0.20)
   tty-command (~> 0.8)
-  tty-prompt (~> 0.16)
+  tty-prompt (~> 0.17)
   twitter-text (~> 1.14)
   tzinfo-data (~> 1.2018)
   webmock (~> 3.3)
diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb
index 90f42251e..ac8de5fc0 100644
--- a/app/controllers/api/base_controller.rb
+++ b/app/controllers/api/base_controller.rb
@@ -53,6 +53,10 @@ class Api::BaseController < ApplicationController
     [params[:limit].to_i.abs, default_limit * 2].min
   end
 
+  def params_slice(*keys)
+    params.slice(*keys).permit(*keys)
+  end
+
   def current_resource_owner
     @current_user ||= User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
   end
diff --git a/app/controllers/api/v1/accounts/statuses_controller.rb b/app/controllers/api/v1/accounts/statuses_controller.rb
index 06fa6c762..b68a8805f 100644
--- a/app/controllers/api/v1/accounts/statuses_controller.rb
+++ b/app/controllers/api/v1/accounts/statuses_controller.rb
@@ -28,10 +28,9 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
 
   def account_statuses
     statuses = truthy_param?(:pinned) ? pinned_scope : permitted_account_statuses
-    statuses = statuses.paginate_by_max_id(
+    statuses = statuses.paginate_by_id(
       limit_param(DEFAULT_STATUSES_LIMIT),
-      params[:max_id],
-      params[:since_id]
+      params_slice(:max_id, :since_id, :min_id)
     )
 
     statuses.merge!(only_media_scope) if truthy_param?(:only_media)
@@ -82,7 +81,7 @@ class Api::V1::Accounts::StatusesController < Api::BaseController
 
   def prev_path
     unless @statuses.empty?
-      api_v1_account_statuses_url pagination_params(since_id: pagination_since_id)
+      api_v1_account_statuses_url pagination_params(min_id: pagination_since_id)
     end
   end
 
diff --git a/app/controllers/api/v1/favourites_controller.rb b/app/controllers/api/v1/favourites_controller.rb
index ab5204355..db827f9d4 100644
--- a/app/controllers/api/v1/favourites_controller.rb
+++ b/app/controllers/api/v1/favourites_controller.rb
@@ -26,10 +26,9 @@ class Api::V1::FavouritesController < Api::BaseController
   end
 
   def results
-    @_results ||= account_favourites.paginate_by_max_id(
+    @_results ||= account_favourites.paginate_by_id(
       limit_param(DEFAULT_STATUSES_LIMIT),
-      params[:max_id],
-      params[:since_id]
+      params_slice(:max_id, :since_id, :min_id)
     )
   end
 
@@ -49,7 +48,7 @@ class Api::V1::FavouritesController < Api::BaseController
 
   def prev_path
     unless results.empty?
-      api_v1_favourites_url pagination_params(since_id: pagination_since_id)
+      api_v1_favourites_url pagination_params(min_id: pagination_since_id)
     end
   end
 
diff --git a/app/controllers/api/v1/instances_controller.rb b/app/controllers/api/v1/instances_controller.rb
index 1c6971c18..5686e8d7c 100644
--- a/app/controllers/api/v1/instances_controller.rb
+++ b/app/controllers/api/v1/instances_controller.rb
@@ -4,6 +4,8 @@ class Api::V1::InstancesController < Api::BaseController
   respond_to :json
 
   def show
-    render json: {}, serializer: REST::InstanceSerializer
+    render_cached_json('api:v1:instances', expires_in: 5.minutes) do
+      ActiveModelSerializers::SerializableResource.new({}, serializer: REST::InstanceSerializer)
+    end
   end
 end
diff --git a/app/controllers/api/v1/notifications_controller.rb b/app/controllers/api/v1/notifications_controller.rb
index a8ed5a63b..3b492c516 100644
--- a/app/controllers/api/v1/notifications_controller.rb
+++ b/app/controllers/api/v1/notifications_controller.rb
@@ -46,10 +46,9 @@ class Api::V1::NotificationsController < Api::BaseController
   end
 
   def paginated_notifications
-    browserable_account_notifications.paginate_by_max_id(
+    browserable_account_notifications.paginate_by_id(
       limit_param(DEFAULT_NOTIFICATIONS_LIMIT),
-      params[:max_id],
-      params[:since_id]
+      params_slice(:max_id, :since_id, :min_id)
     )
   end
 
@@ -73,7 +72,7 @@ class Api::V1::NotificationsController < Api::BaseController
 
   def prev_path
     unless @notifications.empty?
-      api_v1_notifications_url pagination_params(since_id: pagination_since_id)
+      api_v1_notifications_url pagination_params(min_id: pagination_since_id)
     end
   end
 
diff --git a/app/controllers/api/v1/reports_controller.rb b/app/controllers/api/v1/reports_controller.rb
index a954101cb..9c6ee0a50 100644
--- a/app/controllers/api/v1/reports_controller.rb
+++ b/app/controllers/api/v1/reports_controller.rb
@@ -7,11 +7,6 @@ class Api::V1::ReportsController < Api::BaseController
 
   respond_to :json
 
-  def index
-    @reports = current_account.reports
-    render json: @reports, each_serializer: REST::ReportSerializer
-  end
-
   def create
     @report = ReportService.new.call(
       current_account,
diff --git a/app/controllers/api/v1/timelines/home_controller.rb b/app/controllers/api/v1/timelines/home_controller.rb
index 4412aaaa3..fcd0757f1 100644
--- a/app/controllers/api/v1/timelines/home_controller.rb
+++ b/app/controllers/api/v1/timelines/home_controller.rb
@@ -30,7 +30,8 @@ class Api::V1::Timelines::HomeController < Api::BaseController
     account_home_feed.get(
       limit_param(DEFAULT_STATUSES_LIMIT),
       params[:max_id],
-      params[:since_id]
+      params[:since_id],
+      params[:min_id]
     )
   end
 
@@ -51,7 +52,7 @@ class Api::V1::Timelines::HomeController < Api::BaseController
   end
 
   def prev_path
-    api_v1_timelines_home_url pagination_params(since_id: pagination_since_id)
+    api_v1_timelines_home_url pagination_params(min_id: pagination_since_id)
   end
 
   def pagination_max_id
diff --git a/app/controllers/api/v1/timelines/list_controller.rb b/app/controllers/api/v1/timelines/list_controller.rb
index cfc5f3b5e..a15eae468 100644
--- a/app/controllers/api/v1/timelines/list_controller.rb
+++ b/app/controllers/api/v1/timelines/list_controller.rb
@@ -32,7 +32,8 @@ class Api::V1::Timelines::ListController < Api::BaseController
     list_feed.get(
       limit_param(DEFAULT_STATUSES_LIMIT),
       params[:max_id],
-      params[:since_id]
+      params[:since_id],
+      params[:min_id]
     )
   end
 
@@ -53,7 +54,7 @@ class Api::V1::Timelines::ListController < Api::BaseController
   end
 
   def prev_path
-    api_v1_timelines_list_url params[:id], pagination_params(since_id: pagination_since_id)
+    api_v1_timelines_list_url params[:id], pagination_params(min_id: pagination_since_id)
   end
 
   def pagination_max_id
diff --git a/app/controllers/api/v1/timelines/public_controller.rb b/app/controllers/api/v1/timelines/public_controller.rb
index 13fe015b7..aabe24324 100644
--- a/app/controllers/api/v1/timelines/public_controller.rb
+++ b/app/controllers/api/v1/timelines/public_controller.rb
@@ -21,10 +21,9 @@ class Api::V1::Timelines::PublicController < Api::BaseController
   end
 
   def public_statuses
-    statuses = public_timeline_statuses.paginate_by_max_id(
+    statuses = public_timeline_statuses.paginate_by_id(
       limit_param(DEFAULT_STATUSES_LIMIT),
-      params[:max_id],
-      params[:since_id]
+      params_slice(:max_id, :since_id, :min_id)
     )
 
     if truthy_param?(:only_media)
@@ -53,7 +52,7 @@ class Api::V1::Timelines::PublicController < Api::BaseController
   end
 
   def prev_path
-    api_v1_timelines_public_url pagination_params(since_id: pagination_since_id)
+    api_v1_timelines_public_url pagination_params(min_id: pagination_since_id)
   end
 
   def pagination_max_id
diff --git a/app/controllers/api/v1/timelines/tag_controller.rb b/app/controllers/api/v1/timelines/tag_controller.rb
index 7de49a5ed..cf58d5cf4 100644
--- a/app/controllers/api/v1/timelines/tag_controller.rb
+++ b/app/controllers/api/v1/timelines/tag_controller.rb
@@ -29,10 +29,9 @@ class Api::V1::Timelines::TagController < Api::BaseController
     if @tag.nil?
       []
     else
-      statuses = tag_timeline_statuses.paginate_by_max_id(
+      statuses = tag_timeline_statuses.paginate_by_id(
         limit_param(DEFAULT_STATUSES_LIMIT),
-        params[:max_id],
-        params[:since_id]
+        params_slice(:max_id, :since_id, :min_id)
       )
 
       if truthy_param?(:only_media)
@@ -62,7 +61,7 @@ class Api::V1::Timelines::TagController < Api::BaseController
   end
 
   def prev_path
-    api_v1_timelines_tag_url params[:id], pagination_params(since_id: pagination_since_id)
+    api_v1_timelines_tag_url params[:id], pagination_params(min_id: pagination_since_id)
   end
 
   def pagination_max_id
diff --git a/app/controllers/settings/preferences_controller.rb b/app/controllers/settings/preferences_controller.rb
index d60e6a89f..5c5f31d2b 100644
--- a/app/controllers/settings/preferences_controller.rb
+++ b/app/controllers/settings/preferences_controller.rb
@@ -37,7 +37,8 @@ class Settings::PreferencesController < Settings::BaseController
       :setting_favourite_modal,
       :setting_delete_modal,
       :setting_auto_play_gif,
-      :setting_display_sensitive_media,
+      :setting_display_media,
+      :setting_expand_spoilers,
       :setting_reduce_motion,
       :setting_system_font_ui,
       :setting_noindex,
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 6b41fd36e..c002017ef 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -7,8 +7,8 @@ module ApplicationHelper
     follow
   ).freeze
 
-  def active_nav_class(path)
-    current_page?(path) ? 'active' : ''
+  def active_nav_class(*paths)
+    paths.any? { |path| current_page?(path) } ? 'active' : ''
   end
 
   def active_link_to(label, path, **options)
diff --git a/app/javascript/flavours/glitch/components/media_gallery.js b/app/javascript/flavours/glitch/components/media_gallery.js
index 605a2862b..613318102 100644
--- a/app/javascript/flavours/glitch/components/media_gallery.js
+++ b/app/javascript/flavours/glitch/components/media_gallery.js
@@ -6,7 +6,7 @@ import IconButton from './icon_button';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 import { isIOS } from 'flavours/glitch/util/is_mobile';
 import classNames from 'classnames';
-import { autoPlayGif, displaySensitiveMedia } from 'flavours/glitch/util/initial_state';
+import { autoPlayGif, displayMedia } from 'flavours/glitch/util/initial_state';
 
 const messages = defineMessages({
   hidden: {
@@ -226,7 +226,7 @@ export default class MediaGallery extends React.PureComponent {
   };
 
   state = {
-    visible: this.props.revealed === undefined ? (!this.props.sensitive || displaySensitiveMedia) : this.props.revealed,
+    visible: this.props.revealed === undefined ? (displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all') : this.props.revealed,
   };
 
   componentWillReceiveProps (nextProps) {
diff --git a/app/javascript/flavours/glitch/features/video/index.js b/app/javascript/flavours/glitch/features/video/index.js
index 5cbe01f26..227f298e4 100644
--- a/app/javascript/flavours/glitch/features/video/index.js
+++ b/app/javascript/flavours/glitch/features/video/index.js
@@ -5,7 +5,7 @@ import { fromJS } from 'immutable';
 import { throttle } from 'lodash';
 import classNames from 'classnames';
 import { isFullscreen, requestFullscreen, exitFullscreen } from 'flavours/glitch/util/fullscreen';
-import { displaySensitiveMedia } from 'flavours/glitch/util/initial_state';
+import { displayMedia } from 'flavours/glitch/util/initial_state';
 
 const messages = defineMessages({
   play: { id: 'video.play', defaultMessage: 'Play' },
@@ -114,7 +114,7 @@ export default class Video extends React.PureComponent {
     fullscreen: false,
     hovered: false,
     muted: false,
-    revealed: this.props.revealed === undefined ? (!this.props.sensitive || displaySensitiveMedia) : this.props.revealed,
+    revealed: this.props.revealed === undefined ? (displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all') : this.props.revealed,
   };
 
   setPlayerRef = c => {
diff --git a/app/javascript/flavours/glitch/styles/about.scss b/app/javascript/flavours/glitch/styles/about.scss
index ba46c65c5..f676a8c77 100644
--- a/app/javascript/flavours/glitch/styles/about.scss
+++ b/app/javascript/flavours/glitch/styles/about.scss
@@ -16,7 +16,7 @@ $small-breakpoint: 960px;
 }
 
 .rich-formatting {
-  font-family: 'mastodon-font-sans-serif', sans-serif;
+  font-family: $font-sans-serif, sans-serif;
   font-size: 16px;
   font-weight: 400;
   font-size: 16px;
@@ -31,7 +31,7 @@ $small-breakpoint: 960px;
 
   p,
   li {
-    font-family: 'mastodon-font-sans-serif', sans-serif;
+    font-family: $font-sans-serif, sans-serif;
     font-size: 16px;
     font-weight: 400;
     font-size: 16px;
@@ -62,7 +62,7 @@ $small-breakpoint: 960px;
   }
 
   h1 {
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     font-size: 26px;
     line-height: 30px;
     font-weight: 500;
@@ -70,7 +70,7 @@ $small-breakpoint: 960px;
     color: $secondary-text-color;
 
     small {
-      font-family: 'mastodon-font-sans-serif', sans-serif;
+      font-family: $font-sans-serif, sans-serif;
       display: block;
       font-size: 18px;
       font-weight: 400;
@@ -79,7 +79,7 @@ $small-breakpoint: 960px;
   }
 
   h2 {
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     font-size: 22px;
     line-height: 26px;
     font-weight: 500;
@@ -88,7 +88,7 @@ $small-breakpoint: 960px;
   }
 
   h3 {
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     font-size: 18px;
     line-height: 24px;
     font-weight: 500;
@@ -97,7 +97,7 @@ $small-breakpoint: 960px;
   }
 
   h4 {
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     font-size: 16px;
     line-height: 24px;
     font-weight: 500;
@@ -106,7 +106,7 @@ $small-breakpoint: 960px;
   }
 
   h5 {
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     font-size: 14px;
     line-height: 24px;
     font-weight: 500;
@@ -115,7 +115,7 @@ $small-breakpoint: 960px;
   }
 
   h6 {
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     font-size: 12px;
     line-height: 24px;
     font-weight: 500;
@@ -180,7 +180,7 @@ $small-breakpoint: 960px;
 
   &__section {
     flex: 1 0 0;
-    font-family: 'mastodon-font-sans-serif', sans-serif;
+    font-family: $font-sans-serif, sans-serif;
     font-size: 16px;
     line-height: 28px;
     color: $primary-text-color;
@@ -221,7 +221,7 @@ $small-breakpoint: 960px;
     bottom: -40px;
 
     .panel-header {
-      font-family: 'mastodon-font-display', sans-serif;
+      font-family: $font-display, sans-serif;
       font-size: 14px;
       line-height: 24px;
       font-weight: 500;
@@ -452,7 +452,7 @@ $small-breakpoint: 960px;
 
   p,
   li {
-    font-family: 'mastodon-font-sans-serif', sans-serif;
+    font-family: $font-sans-serif, sans-serif;
     font-size: 16px;
     font-weight: 400;
     font-size: 16px;
@@ -501,7 +501,7 @@ $small-breakpoint: 960px;
   }
 
   h1 {
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     font-size: 26px;
     line-height: 30px;
     font-weight: 500;
@@ -509,7 +509,7 @@ $small-breakpoint: 960px;
     color: $secondary-text-color;
 
     small {
-      font-family: 'mastodon-font-sans-serif', sans-serif;
+      font-family: $font-sans-serif, sans-serif;
       display: block;
       font-size: 18px;
       font-weight: 400;
@@ -518,7 +518,7 @@ $small-breakpoint: 960px;
   }
 
   h2 {
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     font-size: 22px;
     line-height: 26px;
     font-weight: 500;
@@ -527,7 +527,7 @@ $small-breakpoint: 960px;
   }
 
   h3 {
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     font-size: 18px;
     line-height: 24px;
     font-weight: 500;
@@ -536,7 +536,7 @@ $small-breakpoint: 960px;
   }
 
   h4 {
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     font-size: 16px;
     line-height: 24px;
     font-weight: 500;
@@ -545,7 +545,7 @@ $small-breakpoint: 960px;
   }
 
   h5 {
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     font-size: 14px;
     line-height: 24px;
     font-weight: 500;
@@ -554,7 +554,7 @@ $small-breakpoint: 960px;
   }
 
   h6 {
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     font-size: 12px;
     line-height: 24px;
     font-weight: 500;
@@ -621,7 +621,7 @@ $small-breakpoint: 960px;
 
       .hero .heading {
         padding-bottom: 20px;
-        font-family: 'mastodon-font-sans-serif', sans-serif;
+        font-family: $font-sans-serif, sans-serif;
         font-size: 16px;
         font-weight: 400;
         font-size: 16px;
@@ -672,7 +672,7 @@ $small-breakpoint: 960px;
         text-decoration: none;
         padding: 12px 16px;
         line-height: 32px;
-        font-family: 'mastodon-font-display', sans-serif;
+        font-family: $font-display, sans-serif;
         font-weight: 500;
         font-size: 14px;
 
@@ -745,7 +745,7 @@ $small-breakpoint: 960px;
   .about-short {
     background: darken($ui-base-color, 4%);
     padding: 50px 0 30px;
-    font-family: 'mastodon-font-sans-serif', sans-serif;
+    font-family: $font-sans-serif, sans-serif;
     font-size: 16px;
     font-weight: 400;
     font-size: 16px;
@@ -1015,7 +1015,7 @@ $small-breakpoint: 960px;
     display: flex;
     -webkit-overflow-scrolling: touch;
     -ms-overflow-style: -ms-autohiding-scrollbar;
-    font-family: 'mastodon-font-sans-serif', sans-serif;
+    font-family: $font-sans-serif, sans-serif;
     font-size: 13px;
     line-height: 18px;
     font-weight: 400;
diff --git a/app/javascript/flavours/glitch/styles/admin.scss b/app/javascript/flavours/glitch/styles/admin.scss
index b8cc33039..e16920dd4 100644
--- a/app/javascript/flavours/glitch/styles/admin.scss
+++ b/app/javascript/flavours/glitch/styles/admin.scss
@@ -443,7 +443,7 @@ $no-columns-breakpoint: 600px;
     border-radius: 0 0 4px 4px;
     padding: 10px;
     color: $darker-text-color;
-    font-family: 'mastodon-font-monospace', monospace;
+    font-family: $font-monospace, monospace;
     font-size: 12px;
     word-wrap: break-word;
     min-height: 20px;
diff --git a/app/javascript/flavours/glitch/styles/basics.scss b/app/javascript/flavours/glitch/styles/basics.scss
index 9c2499ac4..550b7fdfc 100644
--- a/app/javascript/flavours/glitch/styles/basics.scss
+++ b/app/javascript/flavours/glitch/styles/basics.scss
@@ -6,7 +6,7 @@
 }
 
 body {
-  font-family: 'mastodon-font-sans-serif', sans-serif;
+  font-family: $font-sans-serif, sans-serif;
   background: darken($ui-base-color, 8%);
   font-size: 13px;
   line-height: 18px;
@@ -29,8 +29,8 @@ body {
     // Fira Sans => Firefox OS
     // Droid Sans => Older Androids (<4.0)
     // Helvetica Neue => Older macOS <10.11
-    // mastodon-font-sans-serif => web-font (Roboto) fallback and newer Androids (>=4.0)
-    font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", mastodon-font-sans-serif, sans-serif;
+    // $font-sans-serif => web-font (Roboto) fallback and newer Androids (>=4.0)
+    font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", $font-sans-serif, sans-serif;
   }
 
   &.app-body {
diff --git a/app/javascript/flavours/glitch/styles/containers.scss b/app/javascript/flavours/glitch/styles/containers.scss
index d1b9934d7..398458e47 100644
--- a/app/javascript/flavours/glitch/styles/containers.scss
+++ b/app/javascript/flavours/glitch/styles/containers.scss
@@ -37,7 +37,7 @@
       outline: 0;
       padding: 12px 16px;
       line-height: 32px;
-      font-family: 'mastodon-font-display', sans-serif;
+      font-family: $font-display, sans-serif;
       font-weight: 500;
       font-size: 14px;
     }
@@ -633,7 +633,7 @@
             font-size: 18px;
             margin-bottom: 5px;
             color: $primary-text-color;
-            font-family: 'mastodon-font-display', sans-serif;
+            font-family: $font-display, sans-serif;
           }
         }
 
diff --git a/app/javascript/flavours/glitch/styles/dashboard.scss b/app/javascript/flavours/glitch/styles/dashboard.scss
index 949ca733f..86cf6c61b 100644
--- a/app/javascript/flavours/glitch/styles/dashboard.scss
+++ b/app/javascript/flavours/glitch/styles/dashboard.scss
@@ -35,7 +35,7 @@
     font-weight: 500;
     font-size: 24px;
     color: $primary-text-color;
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     margin-bottom: 20px;
   }
 
diff --git a/app/javascript/flavours/glitch/styles/forms.scss b/app/javascript/flavours/glitch/styles/forms.scss
index cbd3de94c..be2bf7cea 100644
--- a/app/javascript/flavours/glitch/styles/forms.scss
+++ b/app/javascript/flavours/glitch/styles/forms.scss
@@ -1,7 +1,7 @@
 $no-columns-breakpoint: 600px;
 
 code {
-  font-family: 'mastodon-font-monospace', monospace;
+  font-family: $font-monospace, monospace;
   font-weight: 400;
 }
 
@@ -474,7 +474,7 @@ code {
     width: 100%;
     border: none;
     padding: 10px;
-    font-family: 'mastodon-font-monospace', monospace;
+    font-family: $font-monospace, monospace;
     background: $ui-base-color;
     color: $primary-text-color;
     font-size: 14px;
@@ -718,7 +718,7 @@ code {
 .form_admin_settings_custom_css,
 .form_admin_settings_closed_registrations_message {
   textarea {
-    font-family: 'mastodon-font-monospace', monospace;
+    font-family: $font-monospace, monospace;
   }
 }
 
@@ -742,7 +742,7 @@ code {
     border: 0;
     padding: 10px;
     font-size: 14px;
-    font-family: 'mastodon-font-monospace', monospace;
+    font-family: $font-monospace, monospace;
   }
 
   button {
diff --git a/app/javascript/flavours/glitch/styles/rtl.scss b/app/javascript/flavours/glitch/styles/rtl.scss
index b8c0efad8..23953304a 100644
--- a/app/javascript/flavours/glitch/styles/rtl.scss
+++ b/app/javascript/flavours/glitch/styles/rtl.scss
@@ -145,6 +145,19 @@ body.rtl {
     margin-right: 6px;
   }
 
+  .status__action-bar {
+
+    &__counter {
+      margin-right: 0;
+      margin-left: 11px;
+
+      .status__action-bar-button {
+        margin-right: 0;
+        margin-left: 4px;
+      }
+    }
+  }
+
   .status__action-bar-button {
     float: right;
     margin-right: 0;
@@ -285,4 +298,13 @@ body.rtl {
       }
     }
   }
+
+  .public-layout {
+    .header {
+      .nav-button {
+        margin-left: 8px;
+        margin-right: 0;
+      }
+    }
+  }
 }
diff --git a/app/javascript/flavours/glitch/styles/tables.scss b/app/javascript/flavours/glitch/styles/tables.scss
index fa876e603..9fd0b95bb 100644
--- a/app/javascript/flavours/glitch/styles/tables.scss
+++ b/app/javascript/flavours/glitch/styles/tables.scss
@@ -90,7 +90,7 @@
 }
 
 samp {
-  font-family: 'mastodon-font-monospace', monospace;
+  font-family: $font-monospace, monospace;
 }
 
 button.table-action-link {
diff --git a/app/javascript/flavours/glitch/styles/variables.scss b/app/javascript/flavours/glitch/styles/variables.scss
index 715ecf98f..1ed1a5778 100644
--- a/app/javascript/flavours/glitch/styles/variables.scss
+++ b/app/javascript/flavours/glitch/styles/variables.scss
@@ -51,6 +51,10 @@ $media-modal-media-max-height: 80%;
 
 $no-gap-breakpoint: 415px;
 
+$font-sans-serif: 'mastodon-font-sans-serif' !default;
+$font-display: 'mastodon-font-display' !default;
+$font-monospace: 'mastodon-font-monospace' !default;
+
 // Avatar border size (8% default, 100% for rounded avatars)
 $ui-avatar-border-size: 8%;
 
diff --git a/app/javascript/flavours/glitch/util/initial_state.js b/app/javascript/flavours/glitch/util/initial_state.js
index fdf004527..0aaf65904 100644
--- a/app/javascript/flavours/glitch/util/initial_state.js
+++ b/app/javascript/flavours/glitch/util/initial_state.js
@@ -14,6 +14,7 @@ const getMeta = (prop) => initialState && initialState.meta && initialState.meta
 export const reduceMotion = getMeta('reduce_motion');
 export const autoPlayGif = getMeta('auto_play_gif');
 export const displaySensitiveMedia = getMeta('display_sensitive_media');
+export const displayMedia = getMeta('display_media') || (getMeta('display_sensitive_media') ? 'show_all' : 'default');
 export const unfollowModal = getMeta('unfollow_modal');
 export const boostModal = getMeta('boost_modal');
 export const favouriteModal = getMeta('favourite_modal');
diff --git a/app/javascript/mastodon/actions/importer/normalizer.js b/app/javascript/mastodon/actions/importer/normalizer.js
index 10a39e050..a2af3222e 100644
--- a/app/javascript/mastodon/actions/importer/normalizer.js
+++ b/app/javascript/mastodon/actions/importer/normalizer.js
@@ -1,6 +1,7 @@
 import escapeTextContentForBrowser from 'escape-html';
 import emojify from '../../features/emoji/emoji';
 import { unescapeHTML } from '../../utils/html';
+import { expandSpoilers } from '../../initial_state';
 
 const domParser = new DOMParser();
 
@@ -57,7 +58,7 @@ export function normalizeStatus(status, normalOldStatus) {
     normalStatus.search_index = domParser.parseFromString(searchContent, 'text/html').documentElement.textContent;
     normalStatus.contentHtml  = emojify(normalStatus.content, emojiMap);
     normalStatus.spoilerHtml  = emojify(escapeTextContentForBrowser(spoilerText), emojiMap);
-    normalStatus.hidden       = spoilerText.length > 0 || normalStatus.sensitive;
+    normalStatus.hidden       = expandSpoilers ? false : spoilerText.length > 0 || normalStatus.sensitive;
   }
 
   return normalStatus;
diff --git a/app/javascript/mastodon/components/__tests__/__snapshots__/autosuggest_emoji-test.js.snap b/app/javascript/mastodon/components/__tests__/__snapshots__/autosuggest_emoji-test.js.snap
new file mode 100644
index 000000000..1c3727848
--- /dev/null
+++ b/app/javascript/mastodon/components/__tests__/__snapshots__/autosuggest_emoji-test.js.snap
@@ -0,0 +1,27 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`<AutosuggestEmoji /> renders emoji with custom url 1`] = `
+<div
+  className="autosuggest-emoji"
+>
+  <img
+    alt="foobar"
+    className="emojione"
+    src="http://example.com/emoji.png"
+  />
+  :foobar:
+</div>
+`;
+
+exports[`<AutosuggestEmoji /> renders native emoji 1`] = `
+<div
+  className="autosuggest-emoji"
+>
+  <img
+    alt="💙"
+    className="emojione"
+    src="/emoji/1f499.svg"
+  />
+  :foobar:
+</div>
+`;
diff --git a/app/javascript/mastodon/components/__tests__/autosuggest_emoji-test.js b/app/javascript/mastodon/components/__tests__/autosuggest_emoji-test.js
new file mode 100644
index 000000000..05616e444
--- /dev/null
+++ b/app/javascript/mastodon/components/__tests__/autosuggest_emoji-test.js
@@ -0,0 +1,29 @@
+import React from 'react';
+import renderer from 'react-test-renderer';
+import AutosuggestEmoji from '../autosuggest_emoji';
+
+describe('<AutosuggestEmoji />', () => {
+  it('renders native emoji', () => {
+    const emoji = {
+      native: '💙',
+      colons: ':foobar:',
+    };
+    const component = renderer.create(<AutosuggestEmoji emoji={emoji} />);
+    const tree      = component.toJSON();
+
+    expect(tree).toMatchSnapshot();
+  });
+
+  it('renders emoji with custom url', () => {
+    const emoji = {
+      custom: true,
+      imageUrl: 'http://example.com/emoji.png',
+      native: 'foobar',
+      colons: ':foobar:',
+    };
+    const component = renderer.create(<AutosuggestEmoji emoji={emoji} />);
+    const tree      = component.toJSON();
+
+    expect(tree).toMatchSnapshot();
+  });
+});
diff --git a/app/javascript/mastodon/components/media_gallery.js b/app/javascript/mastodon/components/media_gallery.js
index a1785196f..ed0e4ff1b 100644
--- a/app/javascript/mastodon/components/media_gallery.js
+++ b/app/javascript/mastodon/components/media_gallery.js
@@ -6,7 +6,7 @@ import IconButton from './icon_button';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 import { isIOS } from '../is_mobile';
 import classNames from 'classnames';
-import { autoPlayGif, displaySensitiveMedia } from '../initial_state';
+import { autoPlayGif, displayMedia } from '../initial_state';
 
 const messages = defineMessages({
   toggle_visible: { id: 'media_gallery.toggle_visible', defaultMessage: 'Toggle visibility' },
@@ -197,7 +197,7 @@ class MediaGallery extends React.PureComponent {
   };
 
   state = {
-    visible: !this.props.sensitive || displaySensitiveMedia,
+    visible: displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all',
   };
 
   componentWillReceiveProps (nextProps) {
diff --git a/app/javascript/mastodon/components/status.js b/app/javascript/mastodon/components/status.js
index 6c595c712..90c689a75 100644
--- a/app/javascript/mastodon/components/status.js
+++ b/app/javascript/mastodon/components/status.js
@@ -285,7 +285,7 @@ class Status extends ImmutablePureComponent {
               </a>
             </div>
 
-            <StatusContent status={status} onClick={this.handleClick} expanded={!status.get('hidden')} onExpandedToggle={this.handleExpandedToggle} />
+            <StatusContent status={status} onClick={this.handleClick} expanded={!status.get('hidden')} onExpandedToggle={this.handleExpandedToggle} collapsable />
 
             {media}
 
diff --git a/app/javascript/mastodon/components/status_content.js b/app/javascript/mastodon/components/status_content.js
index 81013747e..eda7d6ac3 100644
--- a/app/javascript/mastodon/components/status_content.js
+++ b/app/javascript/mastodon/components/status_content.js
@@ -6,6 +6,8 @@ import { FormattedMessage } from 'react-intl';
 import Permalink from './permalink';
 import classnames from 'classnames';
 
+const MAX_HEIGHT = 642; // 20px * 32 (+ 2px padding at the top)
+
 export default class StatusContent extends React.PureComponent {
 
   static contextTypes = {
@@ -17,10 +19,12 @@ export default class StatusContent extends React.PureComponent {
     expanded: PropTypes.bool,
     onExpandedToggle: PropTypes.func,
     onClick: PropTypes.func,
+    collapsable: PropTypes.bool,
   };
 
   state = {
     hidden: true,
+    collapsed: null, //  `collapsed: null` indicates that an element doesn't need collapsing, while `true` or `false` indicates that it does (and is/isn't).
   };
 
   _updateStatusLinks () {
@@ -53,6 +57,16 @@ export default class StatusContent extends React.PureComponent {
       link.setAttribute('target', '_blank');
       link.setAttribute('rel', 'noopener');
     }
+
+    if (
+      this.props.collapsable
+      && this.props.onClick
+      && this.state.collapsed === null
+      && node.clientHeight > MAX_HEIGHT
+      && this.props.status.get('spoiler_text').length === 0
+    ) {
+      this.setState({ collapsed: true });
+    }
   }
 
   componentDidMount () {
@@ -113,6 +127,11 @@ export default class StatusContent extends React.PureComponent {
     }
   }
 
+  handleCollapsedClick = (e) => {
+    e.preventDefault();
+    this.setState({ collapsed: !this.state.collapsed });
+  }
+
   setRef = (c) => {
     this.node = c;
   }
@@ -132,12 +151,19 @@ export default class StatusContent extends React.PureComponent {
     const classNames = classnames('status__content', {
       'status__content--with-action': this.props.onClick && this.context.router,
       'status__content--with-spoiler': status.get('spoiler_text').length > 0,
+      'status__content--collapsed': this.state.collapsed === true,
     });
 
     if (isRtl(status.get('search_index'))) {
       directionStyle.direction = 'rtl';
     }
 
+    const readMoreButton = (
+      <button className='status__content__read-more-button' onClick={this.props.onClick}>
+        <FormattedMessage id='status.read_more' defaultMessage='Read more' /><i className='fa fa-fw fa-angle-right' />
+      </button>
+    );
+
     if (status.get('spoiler_text').length > 0) {
       let mentionsPlaceholder = '';
 
@@ -167,17 +193,23 @@ export default class StatusContent extends React.PureComponent {
         </div>
       );
     } else if (this.props.onClick) {
-      return (
+      const output = [
         <div
           ref={this.setRef}
           tabIndex='0'
           className={classNames}
           style={directionStyle}
+          dangerouslySetInnerHTML={content}
           onMouseDown={this.handleMouseDown}
           onMouseUp={this.handleMouseUp}
-          dangerouslySetInnerHTML={content}
-        />
-      );
+        />,
+      ];
+
+      if (this.state.collapsed) {
+        output.push(readMoreButton);
+      }
+
+      return output;
     } else {
       return (
         <div
diff --git a/app/javascript/mastodon/features/account_gallery/components/media_item.js b/app/javascript/mastodon/features/account_gallery/components/media_item.js
index f7a802dc7..7c330c430 100644
--- a/app/javascript/mastodon/features/account_gallery/components/media_item.js
+++ b/app/javascript/mastodon/features/account_gallery/components/media_item.js
@@ -2,7 +2,7 @@ import React from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import Permalink from '../../../components/permalink';
-import { displaySensitiveMedia } from '../../../initial_state';
+import { displayMedia } from '../../../initial_state';
 
 export default class MediaItem extends ImmutablePureComponent {
 
@@ -11,7 +11,7 @@ export default class MediaItem extends ImmutablePureComponent {
   };
 
   state = {
-    visible: !this.props.media.getIn(['status', 'sensitive']) || displaySensitiveMedia,
+    visible: displayMedia !== 'hide_all' && !this.props.media.getIn(['status', 'sensitive']) || displayMedia === 'show_all',
   };
 
   handleClick = () => {
diff --git a/app/javascript/mastodon/features/notifications/components/column_settings.js b/app/javascript/mastodon/features/notifications/components/column_settings.js
index d9638aaf3..fcdf5c6e6 100644
--- a/app/javascript/mastodon/features/notifications/components/column_settings.js
+++ b/app/javascript/mastodon/features/notifications/components/column_settings.js
@@ -27,7 +27,6 @@ export default class ColumnSettings extends React.PureComponent {
 
     const showPushSettings = pushSettings.get('browserSupport') && pushSettings.get('isSubscribed');
     const pushStr = showPushSettings && <FormattedMessage id='notifications.column_settings.push' defaultMessage='Push notifications' />;
-    const pushMeta = showPushSettings && <FormattedMessage id='notifications.column_settings.push_meta' defaultMessage='This device' />;
 
     return (
       <div>
@@ -40,7 +39,7 @@ export default class ColumnSettings extends React.PureComponent {
 
           <div className='column-settings__row'>
             <SettingToggle prefix='notifications_desktop' settings={settings} settingPath={['alerts', 'follow']} onChange={onChange} label={alertStr} />
-            {showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingPath={['alerts', 'follow']} meta={pushMeta} onChange={this.onPushChange} label={pushStr} />}
+            {showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingPath={['alerts', 'follow']} onChange={this.onPushChange} label={pushStr} />}
             <SettingToggle prefix='notifications' settings={settings} settingPath={['shows', 'follow']} onChange={onChange} label={showStr} />
             <SettingToggle prefix='notifications' settings={settings} settingPath={['sounds', 'follow']} onChange={onChange} label={soundStr} />
           </div>
@@ -51,7 +50,7 @@ export default class ColumnSettings extends React.PureComponent {
 
           <div className='column-settings__row'>
             <SettingToggle prefix='notifications_desktop' settings={settings} settingPath={['alerts', 'favourite']} onChange={onChange} label={alertStr} />
-            {showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingPath={['alerts', 'favourite']} meta={pushMeta} onChange={this.onPushChange} label={pushStr} />}
+            {showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingPath={['alerts', 'favourite']} onChange={this.onPushChange} label={pushStr} />}
             <SettingToggle prefix='notifications' settings={settings} settingPath={['shows', 'favourite']} onChange={onChange} label={showStr} />
             <SettingToggle prefix='notifications' settings={settings} settingPath={['sounds', 'favourite']} onChange={onChange} label={soundStr} />
           </div>
@@ -62,7 +61,7 @@ export default class ColumnSettings extends React.PureComponent {
 
           <div className='column-settings__row'>
             <SettingToggle prefix='notifications_desktop' settings={settings} settingPath={['alerts', 'mention']} onChange={onChange} label={alertStr} />
-            {showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingPath={['alerts', 'mention']} meta={pushMeta} onChange={this.onPushChange} label={pushStr} />}
+            {showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingPath={['alerts', 'mention']} onChange={this.onPushChange} label={pushStr} />}
             <SettingToggle prefix='notifications' settings={settings} settingPath={['shows', 'mention']} onChange={onChange} label={showStr} />
             <SettingToggle prefix='notifications' settings={settings} settingPath={['sounds', 'mention']} onChange={onChange} label={soundStr} />
           </div>
@@ -73,7 +72,7 @@ export default class ColumnSettings extends React.PureComponent {
 
           <div className='column-settings__row'>
             <SettingToggle prefix='notifications_desktop' settings={settings} settingPath={['alerts', 'reblog']} onChange={onChange} label={alertStr} />
-            {showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingPath={['alerts', 'reblog']} meta={pushMeta} onChange={this.onPushChange} label={pushStr} />}
+            {showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingPath={['alerts', 'reblog']} onChange={this.onPushChange} label={pushStr} />}
             <SettingToggle prefix='notifications' settings={settings} settingPath={['shows', 'reblog']} onChange={onChange} label={showStr} />
             <SettingToggle prefix='notifications' settings={settings} settingPath={['sounds', 'reblog']} onChange={onChange} label={soundStr} />
           </div>
diff --git a/app/javascript/mastodon/features/notifications/components/notification.js b/app/javascript/mastodon/features/notifications/components/notification.js
index ed4a44ca6..8df6830c5 100644
--- a/app/javascript/mastodon/features/notifications/components/notification.js
+++ b/app/javascript/mastodon/features/notifications/components/notification.js
@@ -85,8 +85,9 @@ class Notification extends ImmutablePureComponent {
             <div className='notification__favourite-icon-wrapper'>
               <i className='fa fa-fw fa-user-plus' />
             </div>
-
-            <FormattedMessage id='notification.follow' defaultMessage='{name} followed you' values={{ name: link }} />
+            <span title={notification.get('created_at')}>
+              <FormattedMessage id='notification.follow' defaultMessage='{name} followed you' values={{ name: link }} />
+            </span>
           </div>
 
           <AccountContainer id={account.get('id')} withNote={false} hidden={this.props.hidden} />
diff --git a/app/javascript/mastodon/features/notifications/components/setting_toggle.js b/app/javascript/mastodon/features/notifications/components/setting_toggle.js
index ac2211e48..7aec16d2e 100644
--- a/app/javascript/mastodon/features/notifications/components/setting_toggle.js
+++ b/app/javascript/mastodon/features/notifications/components/setting_toggle.js
@@ -10,7 +10,6 @@ export default class SettingToggle extends React.PureComponent {
     settings: ImmutablePropTypes.map.isRequired,
     settingPath: PropTypes.array.isRequired,
     label: PropTypes.node.isRequired,
-    meta: PropTypes.node,
     onChange: PropTypes.func.isRequired,
   }
 
@@ -19,14 +18,13 @@ export default class SettingToggle extends React.PureComponent {
   }
 
   render () {
-    const { prefix, settings, settingPath, label, meta } = this.props;
+    const { prefix, settings, settingPath, label } = this.props;
     const id = ['setting-toggle', prefix, ...settingPath].filter(Boolean).join('-');
 
     return (
       <div className='setting-toggle'>
         <Toggle id={id} checked={settings.getIn(settingPath)} onChange={this.onChange} onKeyDown={this.onKeyDown} />
         <label htmlFor={id} className='setting-toggle__label'>{label}</label>
-        {meta && <span className='setting-meta__label'>{meta}</span>}
       </div>
     );
   }
diff --git a/app/javascript/mastodon/features/ui/index.js b/app/javascript/mastodon/features/ui/index.js
index 2781c5d64..fb6f675f4 100644
--- a/app/javascript/mastodon/features/ui/index.js
+++ b/app/javascript/mastodon/features/ui/index.js
@@ -59,7 +59,8 @@ const messages = defineMessages({
 
 const mapStateToProps = state => ({
   isComposing: state.getIn(['compose', 'is_composing']),
-  hasComposingText: state.getIn(['compose', 'text']) !== '',
+  hasComposingText: state.getIn(['compose', 'text']).trim().length !== 0,
+  hasMediaAttachments: state.getIn(['compose', 'media_attachments']).size > 0,
   dropdownMenuIsOpen: state.getIn(['dropdown_menu', 'openId']) !== null,
 });
 
@@ -201,6 +202,7 @@ class UI extends React.PureComponent {
     children: PropTypes.node,
     isComposing: PropTypes.bool,
     hasComposingText: PropTypes.bool,
+    hasMediaAttachments: PropTypes.bool,
     location: PropTypes.object,
     intl: PropTypes.object.isRequired,
     dropdownMenuIsOpen: PropTypes.bool,
@@ -211,9 +213,9 @@ class UI extends React.PureComponent {
   };
 
   handleBeforeUnload = (e) => {
-    const { intl, isComposing, hasComposingText } = this.props;
+    const { intl, isComposing, hasComposingText, hasMediaAttachments } = this.props;
 
-    if (isComposing && hasComposingText) {
+    if (isComposing && (hasComposingText || hasMediaAttachments)) {
       // Setting returnValue to any string causes confirmation dialog.
       // Many browsers no longer display this text to users,
       // but we set user-friendly message for other browsers, e.g. Edge.
diff --git a/app/javascript/mastodon/features/video/index.js b/app/javascript/mastodon/features/video/index.js
index d17253957..67f7580b9 100644
--- a/app/javascript/mastodon/features/video/index.js
+++ b/app/javascript/mastodon/features/video/index.js
@@ -5,7 +5,7 @@ import { fromJS } from 'immutable';
 import { throttle } from 'lodash';
 import classNames from 'classnames';
 import { isFullscreen, requestFullscreen, exitFullscreen } from '../ui/util/fullscreen';
-import { displaySensitiveMedia } from '../../initial_state';
+import { displayMedia } from '../../initial_state';
 
 const messages = defineMessages({
   play: { id: 'video.play', defaultMessage: 'Play' },
@@ -111,7 +111,7 @@ class Video extends React.PureComponent {
     fullscreen: false,
     hovered: false,
     muted: false,
-    revealed: !this.props.sensitive || displaySensitiveMedia,
+    revealed: displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all',
   };
 
   setPlayerRef = c => {
@@ -272,7 +272,7 @@ class Video extends React.PureComponent {
   }
 
   render () {
-    const { preview, src, inline, startTime, onOpenVideo, onCloseVideo, intl, alt, detailed } = this.props;
+    const { preview, src, inline, startTime, onOpenVideo, onCloseVideo, intl, alt, detailed, sensitive } = this.props;
     const { containerWidth, currentTime, duration, buffer, dragging, paused, fullscreen, hovered, muted, revealed } = this.state;
     const progress = (currentTime / duration) * 100;
     const playerStyle = {};
@@ -296,6 +296,13 @@ class Video extends React.PureComponent {
       preload = 'none';
     }
 
+    let warning;
+    if (sensitive) {
+      warning = <FormattedMessage id='status.sensitive_warning' defaultMessage='Sensitive content' />;
+    } else {
+      warning = <FormattedMessage id='status.media_hidden' defaultMessage='Media hidden' />;
+    }
+
     return (
       <div
         role='menuitem'
@@ -328,7 +335,7 @@ class Video extends React.PureComponent {
         />
 
         <button type='button' className={classNames('video-player__spoiler', { active: !revealed })} onClick={this.toggleReveal}>
-          <span className='video-player__spoiler__title'><FormattedMessage id='status.sensitive_warning' defaultMessage='Sensitive content' /></span>
+          <span className='video-player__spoiler__title'>{warning}</span>
           <span className='video-player__spoiler__subtitle'><FormattedMessage id='status.sensitive_toggle' defaultMessage='Click to view' /></span>
         </button>
 
diff --git a/app/javascript/mastodon/initial_state.js b/app/javascript/mastodon/initial_state.js
index 4c6922f9b..1d3d84f9d 100644
--- a/app/javascript/mastodon/initial_state.js
+++ b/app/javascript/mastodon/initial_state.js
@@ -5,7 +5,8 @@ const getMeta = (prop) => initialState && initialState.meta && initialState.meta
 
 export const reduceMotion = getMeta('reduce_motion');
 export const autoPlayGif = getMeta('auto_play_gif');
-export const displaySensitiveMedia = getMeta('display_sensitive_media');
+export const displayMedia = getMeta('display_media');
+export const expandSpoilers = getMeta('expand_spoilers');
 export const unfollowModal = getMeta('unfollow_modal');
 export const boostModal = getMeta('boost_modal');
 export const deleteModal = getMeta('delete_modal');
diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json
index 56d78ae64..a74207db6 100644
--- a/app/javascript/mastodon/locales/ar.json
+++ b/app/javascript/mastodon/locales/ar.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "متابعُون جُدُد :",
   "notifications.column_settings.mention": "الإشارات :",
   "notifications.column_settings.push": "الإخطارات المدفوعة",
-  "notifications.column_settings.push_meta": "هذا الجهاز",
   "notifications.column_settings.reblog": "الترقيّات:",
   "notifications.column_settings.show": "إعرِضها في عمود",
   "notifications.column_settings.sound": "أصدر صوتا",
diff --git a/app/javascript/mastodon/locales/ast.json b/app/javascript/mastodon/locales/ast.json
index e3cfabee3..147c5ad2a 100644
--- a/app/javascript/mastodon/locales/ast.json
+++ b/app/javascript/mastodon/locales/ast.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Siguidores nuevos:",
   "notifications.column_settings.mention": "Menciones:",
   "notifications.column_settings.push": "Push notifications",
-  "notifications.column_settings.push_meta": "Esti preséu",
   "notifications.column_settings.reblog": "Boosts:",
   "notifications.column_settings.show": "Amosar en columna",
   "notifications.column_settings.sound": "Reproducir soníu",
diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json
index 5730c1354..756c33393 100644
--- a/app/javascript/mastodon/locales/bg.json
+++ b/app/javascript/mastodon/locales/bg.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Нови последователи:",
   "notifications.column_settings.mention": "Споменавания:",
   "notifications.column_settings.push": "Push notifications",
-  "notifications.column_settings.push_meta": "This device",
   "notifications.column_settings.reblog": "Споделяния:",
   "notifications.column_settings.show": "Покажи в колона",
   "notifications.column_settings.sound": "Play sound",
diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json
index 0364d0bba..4701c9316 100644
--- a/app/javascript/mastodon/locales/ca.json
+++ b/app/javascript/mastodon/locales/ca.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Nous seguidors:",
   "notifications.column_settings.mention": "Mencions:",
   "notifications.column_settings.push": "Push notificacions",
-  "notifications.column_settings.push_meta": "Aquest dispositiu",
   "notifications.column_settings.reblog": "Impulsos:",
   "notifications.column_settings.show": "Mostrar en la columna",
   "notifications.column_settings.sound": "Reproduïr so",
diff --git a/app/javascript/mastodon/locales/co.json b/app/javascript/mastodon/locales/co.json
index 8bf083235..62976c98e 100644
--- a/app/javascript/mastodon/locales/co.json
+++ b/app/javascript/mastodon/locales/co.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Abbunati novi:",
   "notifications.column_settings.mention": "Minzione:",
   "notifications.column_settings.push": "Nutificazione Push",
-  "notifications.column_settings.push_meta": "Quess'apparechju",
   "notifications.column_settings.reblog": "Spartere:",
   "notifications.column_settings.show": "Mustrà indè a colonna",
   "notifications.column_settings.sound": "Sunà",
diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json
index 46aa954e8..2c34fd34c 100644
--- a/app/javascript/mastodon/locales/cs.json
+++ b/app/javascript/mastodon/locales/cs.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Noví sledovatelé:",
   "notifications.column_settings.mention": "Zmínky:",
   "notifications.column_settings.push": "Push oznámení",
-  "notifications.column_settings.push_meta": "Toto zařízení",
   "notifications.column_settings.reblog": "Boosty:",
   "notifications.column_settings.show": "Zobrazit ve sloupci",
   "notifications.column_settings.sound": "Přehrát zvuk",
diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json
index a2eea600a..90f3f8e30 100644
--- a/app/javascript/mastodon/locales/cy.json
+++ b/app/javascript/mastodon/locales/cy.json
@@ -1,337 +1,335 @@
 {
-  "account.badges.bot": "Bot",
-  "account.block": "Blociwch @{name}",
-  "account.block_domain": "Cuddiwch bopeth rhag {domain}",
-  "account.blocked": "Blociwyd",
-  "account.direct": "Neges breifat @{name}",
-  "account.disclaimer_full": "Gall y wybodaeth isod adlewyrchu darlun anghyflawn o broffil defnyddiwr.",
-  "account.domain_blocked": "Domain hidden",
-  "account.edit_profile": "Golygu proffil",
-  "account.endorse": "Feature on profile",
-  "account.follow": "Dilyn",
-  "account.followers": "Dilynwyr",
-  "account.followers.empty": "Nid oes neb yn dilyn y defnyddiwr hwn eto.",
-  "account.follows": "Yn dilyn",
-  "account.follows.empty": "Nid yw'r defnyddiwr hwn yn dilyn unrhyw un eto.",
-  "account.follows_you": "Yn eich dilyn chi",
-  "account.hide_reblogs": "Hide boosts from @{name}",
-  "account.link_verified_on": "Ownership of this link was checked on {date}",
-  "account.media": "Cyfryngau",
-  "account.mention": "Crybwyll @{name}",
-  "account.moved_to": "Mae @{name} wedi symud i:",
-  "account.mute": "Mute @{name}",
-  "account.mute_notifications": "Mute notifications from @{name}",
-  "account.muted": "Distewyd",
-  "account.posts": "Tŵtiau",
-  "account.posts_with_replies": "Toots and replies",
-  "account.report": "Adroddwch @{name}",
-  "account.requested": "Awaiting approval. Click to cancel follow request",
-  "account.share": "Rhannwch broffil @{name}",
-  "account.show_reblogs": "Show boosts from @{name}",
-  "account.unblock": "Dadflociwch @{name}",
-  "account.unblock_domain": "Dadguddiwch {domain}",
-  "account.unendorse": "Don't feature on profile",
-  "account.unfollow": "Daddilynwch",
-  "account.unmute": "Unmute @{name}",
-  "account.unmute_notifications": "Unmute notifications from @{name}",
-  "account.view_full_profile": "View full profile",
-  "alert.unexpected.message": "Digwyddodd gwall annisgwyl.",
-  "alert.unexpected.title": "Wps!",
-  "boost_modal.combo": "You can press {combo} to skip this next time",
-  "bundle_column_error.body": "Aeth rhywbeth o'i le tra'n llwytho'r elfen hon.",
-  "bundle_column_error.retry": "Ceisiwch eto",
-  "bundle_column_error.title": "Gwall rhwydwaith",
-  "bundle_modal_error.close": "Close",
-  "bundle_modal_error.message": "Aeth rhywbeth o'i le tra'n llwytho'r elfen hon.",
-  "bundle_modal_error.retry": "Ceiswich eto",
-  "column.blocks": "Defnyddwyr a flociwyd",
-  "column.community": "Llinell amser lleol",
-  "column.direct": "Negeseuon preifat",
-  "column.domain_blocks": "Parthau cuddiedig",
-  "column.favourites": "Ffefrynnau",
-  "column.follow_requests": "Ceisiadau dilyn",
-  "column.home": "Hafan",
-  "column.lists": "Rhestrau",
-  "column.mutes": "Defnyddwyr a ddistewyd",
-  "column.notifications": "Hysbysiadau",
-  "column.pins": "Pinned toot",
-  "column.public": "Federated timeline",
-  "column_back_button.label": "Nôl",
-  "column_header.hide_settings": "Hide settings",
-  "column_header.moveLeft_settings": "Symudwch y golofn i'r chwith",
-  "column_header.moveRight_settings": "Symudwch y golofn i'r dde",
-  "column_header.pin": "Piniwch",
-  "column_header.show_settings": "Dangos gosodiadau",
-  "column_header.unpin": "Dadbiniwch",
-  "column_subheading.settings": "Gosodiadau",
-  "community.column_settings.media_only": "Cyfryngau yn unig",
-  "compose_form.direct_message_warning": "Mi fydd y tŵt hwn ond yn cael ei anfon at y defnyddwyr sy'n cael eu crybwyll.",
-  "compose_form.direct_message_warning_learn_more": "Dysgwch fwy",
-  "compose_form.hashtag_warning": "Ni fydd y tŵt hwn wedi ei restru o dan unrhyw hashnod gan ei fod heb ei restru. Dim ond tŵtiau cyhoeddus gellid chwilota amdanynt drwy hashnod.",
-  "compose_form.lock_disclaimer": "Nid yw eich cyfri wedi'i {locked}. Gall unrhyw un eich dilyn i weld eich POSTS dilynwyr-yn-unig.",
-  "compose_form.lock_disclaimer.lock": "wedi ei gloi",
-  "compose_form.placeholder": "Be syd ar eich meddwl?",
-  "compose_form.publish": "Tŵt",
-  "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": "Testun wedi ei guddio gan rybudd",
-  "compose_form.spoiler.unmarked": "Nid yw'r testun wedi ei guddio",
-  "compose_form.spoiler_placeholder": "Ysgrifenwch eich rhybudd yma",
-  "confirmation_modal.cancel": "Cancel",
-  "confirmations.block.confirm": "Blociwch",
-  "confirmations.block.message": "Ydych chi'n sicr eich bod eisiau blocio {name}?",
-  "confirmations.delete.confirm": "Dileu",
-  "confirmations.delete.message": "Ydych chi'n sicr eich bod eisiau dileu y statws hwn?",
-  "confirmations.delete_list.confirm": "Dileu",
-  "confirmations.delete_list.message": "Ydych chi'n sicr eich bod eisiau dileu y rhestr hwn am byth?",
-  "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": "Ydych chi'n sicr eich bod am ddistewi {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.unfollow.confirm": "Dad-ddilynwch",
-  "confirmations.unfollow.message": "Ydych chi'n sicr eich bod am ddad-ddilyn {name}?",
-  "embed.instructions": "Embed this status on your website by copying the code below.",
-  "embed.preview": "Dyma sut olwg fydd arno:",
-  "emoji_button.activity": "Gweithgarwch",
-  "emoji_button.custom": "Custom",
-  "emoji_button.flags": "Baneri",
-  "emoji_button.food": "Bwyd a Diod",
-  "emoji_button.label": "Mewnosodwch emoji",
-  "emoji_button.nature": "Natur",
-  "emoji_button.not_found": "Dim emojos!! (╯°□°)╯︵ ┻━┻",
-  "emoji_button.objects": "Gwrthrychau",
-  "emoji_button.people": "Pobl",
-  "emoji_button.recent": "Defnyddir yn aml",
-  "emoji_button.search": "Chwilio...",
-  "emoji_button.search_results": "Canlyniadau chwilio",
-  "emoji_button.symbols": "Symbolau",
-  "emoji_button.travel": "Teithio & Llefydd",
-  "empty_column.blocks": "Nid ydych wedi blocio unrhyw ddefnyddwyr eto.",
-  "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
-  "empty_column.direct": "Nid oes gennych unrhyw negeseuon preifat eto. Pan y byddwch yn anfon neu derbyn un, mi fydd yn ymddangos yma.",
-  "empty_column.domain_blocks": "Nid oes yna unrhyw barthau cuddiedig eto.",
-  "empty_column.favourited_statuses": "Nid oes gennych unrhyw hoff dwtiau eto. Pan y byddwch yn hoffi un, mi fydd yn ymddangos yma.",
-  "empty_column.favourites": "Nid oes neb wedi hoffi'r tŵt yma eto. Pan bydd rhywun yn ei hoffi, mi fyddent yn ymddangos yma.",
-  "empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.",
-  "empty_column.hashtag": "Nid oes dim ar yr hashnod hwn eto.",
-  "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 instances to fill it up",
-  "follow_request.authorize": "Caniatau",
-  "follow_request.reject": "Gwrthod",
-  "getting_started.developers": "Datblygwyr",
-  "getting_started.documentation": "Dogfennaeth",
-  "getting_started.find_friends": "Canfod ffrindiau o Twitter",
-  "getting_started.heading": "Dechrau",
-  "getting_started.invite": "Gwahoddwch bobl",
-  "getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}.",
-  "getting_started.security": "Diogelwch",
-  "getting_started.terms": "Terms of service",
-  "home.column_settings.basic": "Syml",
-  "home.column_settings.show_reblogs": "Show boosts",
-  "home.column_settings.show_replies": "Dangoswch ymatebion",
-  "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": "Disgrifiad",
-  "keyboard_shortcuts.direct": "i agor colofn negeseuon preifat",
-  "keyboard_shortcuts.down": "i symud lawr yn y rhestr",
-  "keyboard_shortcuts.enter": "i agor statws",
-  "keyboard_shortcuts.favourite": "i hoffi",
-  "keyboard_shortcuts.favourites": "i agor rhestr hoffi",
-  "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": "i grybwyll yr awdur",
-  "keyboard_shortcuts.muted": "to open muted users list",
-  "keyboard_shortcuts.my_profile": "i agor eich proffil",
-  "keyboard_shortcuts.notifications": "i agor colofn hysbysiadau",
-  "keyboard_shortcuts.pinned": "to open pinned toots list",
-  "keyboard_shortcuts.profile": "i agor proffil yr awdur",
-  "keyboard_shortcuts.reply": "i ateb",
-  "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": "i ddechrau tŵt newydd sbon",
-  "keyboard_shortcuts.unfocus": "to un-focus compose textarea/search",
-  "keyboard_shortcuts.up": "to move up in the list",
-  "lightbox.close": "Cau",
-  "lightbox.next": "Nesaf",
-  "lightbox.previous": "Previous",
-  "lists.account.add": "Ychwanegwch at restr",
-  "lists.account.remove": "Remove from list",
-  "lists.delete": "Dileu rhestr",
-  "lists.edit": "Golygwch restr",
-  "lists.new.create": "Ychwanegwch restr",
-  "lists.new.title_placeholder": "New list title",
-  "lists.search": "Search among people you follow",
-  "lists.subheading": "Eich rhestrau",
-  "loading_indicator.label": "Llwytho...",
-  "media_gallery.toggle_visible": "Toggle visibility",
-  "missing_indicator.label": "Heb ei ganfod",
-  "missing_indicator.sublabel": "Ni ellid canfod yr adnodd hwn",
-  "mute_modal.hide_notifications": "Cuddiwch hysbysiadau rhag y defnyddiwr hwn?",
-  "navigation_bar.apps": "Apiau symudol",
-  "navigation_bar.blocks": "Defnyddwyr wedi eu blocio",
-  "navigation_bar.community_timeline": "Local timeline",
-  "navigation_bar.compose": "Cyfansoddwch dŵt newydd",
-  "navigation_bar.direct": "Negeseuon preifat",
-  "navigation_bar.discover": "Darganfyddwch",
-  "navigation_bar.domain_blocks": "Parthau cuddiedig",
-  "navigation_bar.edit_profile": "Golygu proffil",
-  "navigation_bar.favourites": "Ffefrynnau",
-  "navigation_bar.filters": "Muted words",
-  "navigation_bar.follow_requests": "Ceisiadau dilyn",
-  "navigation_bar.info": "About this instance",
-  "navigation_bar.keyboard_shortcuts": "Hotkeys",
-  "navigation_bar.lists": "Rhestrau",
-  "navigation_bar.logout": "Allgofnodi",
-  "navigation_bar.mutes": "Muted users",
-  "navigation_bar.personal": "Personol",
-  "navigation_bar.pins": "Tŵtiau wedi eu pinio",
-  "navigation_bar.preferences": "Dewisiadau",
-  "navigation_bar.public_timeline": "Federated timeline",
-  "navigation_bar.security": "Diogelwch",
-  "notification.favourite": "hoffodd {name} eich statws",
-  "notification.follow": "dilynodd {name} chi",
-  "notification.mention": "{name} mentioned you",
-  "notification.reblog": "{name} boosted your status",
-  "notifications.clear": "Clirio hysbysiadau",
-  "notifications.clear_confirmation": "Are you sure you want to permanently clear all your notifications?",
-  "notifications.column_settings.alert": "Desktop notifications",
-  "notifications.column_settings.favourite": "Ffefrynnau:",
-  "notifications.column_settings.follow": "Dilynwyr newydd:",
-  "notifications.column_settings.mention": "Mentions:",
-  "notifications.column_settings.push": "Push notifications",
-  "notifications.column_settings.push_meta": "This device",
-  "notifications.column_settings.reblog": "Boosts:",
-  "notifications.column_settings.show": "Show in column",
-  "notifications.column_settings.sound": "Chwarae sain",
-  "notifications.group": "{count} o hysbysiadau",
-  "onboarding.done": "Done",
-  "onboarding.next": "Nesaf",
-  "onboarding.page_five.public_timelines": "The local timeline shows public posts from everyone on {domain}. The federated timeline shows public posts from everyone who people on {domain} follow. These are the Public Timelines, a great way to discover new people.",
-  "onboarding.page_four.home": "The home timeline shows posts from people you follow.",
-  "onboarding.page_four.notifications": "The notifications column shows when someone interacts with you.",
-  "onboarding.page_one.federation": "Mastodon is a network of independent servers joining up to make one larger social network. We call these servers instances.",
-  "onboarding.page_one.full_handle": "Your full handle",
-  "onboarding.page_one.handle_hint": "This is what you would tell your friends to search for.",
-  "onboarding.page_one.welcome": "Croeso i Mastodon!",
-  "onboarding.page_six.admin": "Your instance's admin is {admin}.",
-  "onboarding.page_six.almost_done": "Almost done...",
-  "onboarding.page_six.appetoot": "Bon Apetŵt!",
-  "onboarding.page_six.apps_available": "There are {apps} available for iOS, Android and other platforms.",
-  "onboarding.page_six.github": "Mastodon is free open-source software. You can report bugs, request features, or contribute to the code on {github}.",
-  "onboarding.page_six.guidelines": "canllawiau cymunedol",
-  "onboarding.page_six.read_guidelines": "Please read {domain}'s {guidelines}!",
-  "onboarding.page_six.various_app": "apiau symudol",
-  "onboarding.page_three.profile": "Edit your profile to change your avatar, bio, and display name. There, you will also find other preferences.",
-  "onboarding.page_three.search": "Use the search bar to find people and look at hashtags, such as {illustration} and {introductions}. To look for a person who is not on this instance, use their full handle.",
-  "onboarding.page_two.compose": "Write posts from the compose column. You can upload images, change privacy settings, and add content warnings with the icons below.",
-  "onboarding.skip": "Skip",
-  "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": "Dilynwyr-yn-unig",
-  "privacy.public.long": "Post to public timelines",
-  "privacy.public.short": "Cyhoeddus",
-  "privacy.unlisted.long": "Do not show in public timelines",
-  "privacy.unlisted.short": "Heb ei restru",
-  "regeneration_indicator.label": "Llwytho…",
-  "regeneration_indicator.sublabel": "Mae eich ffrwd cartref yn cael ei baratoi!",
-  "relative_time.days": "{number}d",
-  "relative_time.hours": "{number}h",
-  "relative_time.just_now": "nawr",
-  "relative_time.minutes": "{number}m",
-  "relative_time.seconds": "{number}s",
-  "reply_indicator.cancel": "Canslo",
-  "report.forward": "Forward to {target}",
-  "report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?",
-  "report.hint": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:",
-  "report.placeholder": "Sylwadau ychwanegol",
-  "report.submit": "Submit",
-  "report.target": "Report {target}",
-  "search.placeholder": "Chwilio",
-  "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": "hashnod",
-  "search_popout.tips.status": "statws",
-  "search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags",
-  "search_popout.tips.user": "defnyddiwr",
-  "search_results.accounts": "Pobl",
-  "search_results.hashtags": "Hanshnodau",
-  "search_results.statuses": "Twtiau",
-  "search_results.total": "{count, number} {count, plural, one {result} other {results}}",
-  "standalone.public_title": "A look inside...",
-  "status.block": "Block @{name}",
-  "status.cancel_reblog_private": "Unboost",
-  "status.cannot_reblog": "This post cannot be boosted",
-  "status.delete": "Dileu",
-  "status.detailed_status": "Detailed conversation view",
-  "status.direct": "Neges breifat @{name}",
-  "status.embed": "Plannu",
-  "status.favourite": "Favourite",
-  "status.filtered": "Filtered",
-  "status.load_more": "Llwythwch mwy",
-  "status.media_hidden": "Media hidden",
-  "status.mention": "Mention @{name}",
-  "status.more": "Mwy",
-  "status.mute": "Mute @{name}",
-  "status.mute_conversation": "Mute conversation",
-  "status.open": "Expand this status",
-  "status.pin": "Pin on profile",
-  "status.pinned": "Pinned toot",
-  "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": "Ateb",
-  "status.replyAll": "Ateb i edefyn",
-  "status.report": "Report @{name}",
-  "status.sensitive_toggle": "Click to view",
-  "status.sensitive_warning": "Cynnwys sensitif",
-  "status.share": "Rhannwch",
-  "status.show_less": "Dangoswch lai",
-  "status.show_less_all": "Dangoswch lai i bawb",
-  "status.show_more": "Dangoswch fwy",
-  "status.show_more_all": "Show more for all",
-  "status.unmute_conversation": "Unmute conversation",
-  "status.unpin": "Unpin from profile",
-  "tabs_bar.federated_timeline": "Federated",
-  "tabs_bar.home": "Hafan",
-  "tabs_bar.local_timeline": "Lleol",
-  "tabs_bar.notifications": "Hysbysiadau",
-  "tabs_bar.search": "Chwilio",
-  "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_form.description": "Describe for the visually impaired",
-  "upload_form.focus": "Crop",
-  "upload_form.undo": "Delete",
-  "upload_progress.label": "Uwchlwytho...",
-  "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": "Chwarae",
-  "video.unmute": "Unmute sound"
+    "account.badges.bot": "Bot",
+    "account.block": "Blociwch @{name}",
+    "account.block_domain": "Cuddiwch bopeth rhag {domain}",
+    "account.blocked": "Blociwyd",
+    "account.direct": "Neges breifat @{name}",
+    "account.disclaimer_full": "Gall y wybodaeth isod adlewyrchu darlun anghyflawn o broffil defnyddiwr.",
+    "account.domain_blocked": "Parth wedi ei guddio",
+    "account.edit_profile": "Golygu proffil",
+    "account.endorse": "Arddangos ar fy mhroffil",
+    "account.follow": "Dilyn",
+    "account.followers": "Dilynwyr",
+    "account.followers.empty": "Nid oes neb yn dilyn y defnyddiwr hwn eto.",
+    "account.follows": "Yn dilyn",
+    "account.follows.empty": "Nid yw'r defnyddiwr hwn yn dilyn unrhyw un eto.",
+    "account.follows_you": "Yn eich dilyn chi",
+    "account.hide_reblogs": "Cuddio bwstiau o @{name}",
+    "account.media": "Cyfryngau",
+    "account.mention": "Crybwyll @{name}",
+    "account.moved_to": "Mae @{name} wedi symud i:",
+    "account.mute": "Tawelu @{name}",
+    "account.mute_notifications": "Cuddio hysbysiadau o @{name}",
+    "account.muted": "Distewyd",
+    "account.posts": "Tŵtiau",
+    "account.posts_with_replies": "Tŵtiau ac atebion",
+    "account.report": "Adroddwch @{name}",
+    "account.requested": "Aros am gymeradwyaeth. Cliciwch er mwyn canslo cais dilyn",
+    "account.share": "Rhannwch broffil @{name}",
+    "account.show_reblogs": "Dangoswch bwstiau o @{name}",
+    "account.unblock": "Dadflociwch @{name}",
+    "account.unblock_domain": "Dadguddiwch {domain}",
+    "account.unendorse": "Peidwch a'i arddangos ar fy mhroffil",
+    "account.unfollow": "Daddilynwch",
+    "account.unmute": "Dad-dawelu @{name}",
+    "account.unmute_notifications": "Dad-dawelu hysbysiadau o @{name}",
+    "account.view_full_profile": "Gweld proffil llawn",
+    "alert.unexpected.message": "Digwyddodd gwall annisgwyl.",
+    "alert.unexpected.title": "Wps!",
+    "boost_modal.combo": "Mae modd gwasgu {combo} er mwyn sgipio hyn tro nesa",
+    "bundle_column_error.body": "Aeth rhywbeth o'i le tra'n llwytho'r elfen hon.",
+    "bundle_column_error.retry": "Ceisiwch eto",
+    "bundle_column_error.title": "Gwall rhwydwaith",
+    "bundle_modal_error.close": "Cau",
+    "bundle_modal_error.message": "Aeth rhywbeth o'i le tra'n llwytho'r elfen hon.",
+    "bundle_modal_error.retry": "Ceiswich eto",
+    "column.blocks": "Defnyddwyr a flociwyd",
+    "column.community": "Llinell amser lleol",
+    "column.direct": "Negeseuon preifat",
+    "column.domain_blocks": "Parthau cuddiedig",
+    "column.favourites": "Ffefrynnau",
+    "column.follow_requests": "Ceisiadau dilyn",
+    "column.home": "Hafan",
+    "column.lists": "Rhestrau",
+    "column.mutes": "Defnyddwyr a ddistewyd",
+    "column.notifications": "Hysbysiadau",
+    "column.pins": "Tŵtiau wedi eu pinio",
+    "column.public": "",
+    "column_back_button.label": "Nôl",
+    "column_header.hide_settings": "Cuddiwch dewisiadau",
+    "column_header.moveLeft_settings": "Symudwch y golofn i'r chwith",
+    "column_header.moveRight_settings": "Symudwch y golofn i'r dde",
+    "column_header.pin": "Piniwch",
+    "column_header.show_settings": "Dangos gosodiadau",
+    "column_header.unpin": "Dadbiniwch",
+    "column_subheading.settings": "Gosodiadau",
+    "community.column_settings.media_only": "Cyfryngau yn unig",
+    "compose_form.direct_message_warning": "Mi fydd y tŵt hwn ond yn cael ei anfon at y defnyddwyr sy'n cael eu crybwyll.",
+    "compose_form.direct_message_warning_learn_more": "Dysgwch fwy",
+    "compose_form.hashtag_warning": "Ni fydd y tŵt hwn wedi ei restru o dan unrhyw hashnod gan ei fod heb ei restru. Dim ond tŵtiau cyhoeddus gellid chwilota amdanynt drwy hashnod.",
+    "compose_form.lock_disclaimer": "Nid yw eich cyfri wedi'i {locked}. Gall unrhyw un eich dilyn i weld eich POSTS dilynwyr-yn-unig.",
+    "compose_form.lock_disclaimer.lock": "wedi ei gloi",
+    "compose_form.placeholder": "Be syd ar eich meddwl?",
+    "compose_form.publish": "Tŵt",
+    "compose_form.publish_loud": "{publish}!",
+    "compose_form.sensitive.marked": "",
+    "compose_form.sensitive.unmarked": "",
+    "compose_form.spoiler.marked": "Testun wedi ei guddio gan rybudd",
+    "compose_form.spoiler.unmarked": "Nid yw'r testun wedi ei guddio",
+    "compose_form.spoiler_placeholder": "Ysgrifenwch eich rhybudd yma",
+    "confirmation_modal.cancel": "Canslo",
+    "confirmations.block.confirm": "Blociwch",
+    "confirmations.block.message": "Ydych chi'n sicr eich bod eisiau blocio {name}?",
+    "confirmations.delete.confirm": "Dileu",
+    "confirmations.delete.message": "Ydych chi'n sicr eich bod eisiau dileu y statws hwn?",
+    "confirmations.delete_list.confirm": "Dileu",
+    "confirmations.delete_list.message": "Ydych chi'n sicr eich bod eisiau dileu y rhestr hwn am byth?",
+    "confirmations.domain_block.confirm": "",
+    "confirmations.domain_block.message": "",
+    "confirmations.mute.confirm": "Tawelu",
+    "confirmations.mute.message": "Ydych chi'n sicr eich bod am ddistewi {name}?",
+    "confirmations.redraft.confirm": "Dilëwch & ailddrafftio",
+    "confirmations.redraft.message": "Ydych chi'n siwr eich bod eisiau dileu y statws hwn a'i ailddrafftio? Bydd ffefrynnau a bwstiau'n cael ei colli, a bydd ymatebion i'r statws gwreiddiol yn cael eu hamddifadu.",
+    "confirmations.unfollow.confirm": "Dad-ddilynwch",
+    "confirmations.unfollow.message": "Ydych chi'n sicr eich bod am ddad-ddilyn {name}?",
+    "embed.instructions": "Mewnblannwch y statws hwn ar eich gwefan drwy gopïo'r côd isod.",
+    "embed.preview": "Dyma sut olwg fydd arno:",
+    "emoji_button.activity": "Gweithgarwch",
+    "emoji_button.custom": "",
+    "emoji_button.flags": "Baneri",
+    "emoji_button.food": "Bwyd a Diod",
+    "emoji_button.label": "Mewnosodwch emoji",
+    "emoji_button.nature": "Natur",
+    "emoji_button.not_found": "Dim emojos!! (╯°□°)╯︵ ┻━┻",
+    "emoji_button.objects": "Gwrthrychau",
+    "emoji_button.people": "Pobl",
+    "emoji_button.recent": "Defnyddir yn aml",
+    "emoji_button.search": "Chwilio...",
+    "emoji_button.search_results": "Canlyniadau chwilio",
+    "emoji_button.symbols": "Symbolau",
+    "emoji_button.travel": "Teithio & Llefydd",
+    "empty_column.blocks": "Nid ydych wedi blocio unrhyw ddefnyddwyr eto.",
+    "empty_column.community": "",
+    "empty_column.direct": "Nid oes gennych unrhyw negeseuon preifat eto. Pan y byddwch yn anfon neu derbyn un, mi fydd yn ymddangos yma.",
+    "empty_column.domain_blocks": "Nid oes yna unrhyw barthau cuddiedig eto.",
+    "empty_column.favourited_statuses": "Nid oes gennych unrhyw hoff dwtiau eto. Pan y byddwch yn hoffi un, mi fydd yn ymddangos yma.",
+    "empty_column.favourites": "Nid oes neb wedi hoffi'r tŵt yma eto. Pan bydd rhywun yn ei hoffi, mi fyddent yn ymddangos yma.",
+    "empty_column.follow_requests": "Nid oes gennych unrhyw geisiadau dilyn eto. Pan dderbyniwch chi un, bydd yn ymddangos yma.",
+    "empty_column.hashtag": "Nid oes dim ar yr hashnod hwn eto.",
+    "empty_column.home": "",
+    "empty_column.home.public_timeline": "y ffrwd cyhoeddus",
+    "empty_column.list": "Nid oes dim yn y rhestr yma eto. Pan y bydd aelodau'r rhestr yn cyhoeddi statws newydd, mi fydd yn ymddangos yma.",
+    "empty_column.lists": "Nid oes gennych unrhyw restrau eto. Pan grëwch chi un, mi fydd yn ymddangos yma.",
+    "empty_column.mutes": "Nid ydych wedi tawelu unrhyw ddefnyddwyr eto.",
+    "empty_column.notifications": "Nid oes gennych unrhyw hysbysiadau eto. Rhyngweithiwch ac eraill i ddechrau'r sgwrs.",
+    "empty_column.public": "Does dim byd yma! Ysgrifennwch rhywbeth yn gyhoeddus, neu dilynwch ddefnyddwyr o INSTANCES eraill i'w lenwi",
+    "follow_request.authorize": "Caniatau",
+    "follow_request.reject": "Gwrthod",
+    "getting_started.developers": "Datblygwyr",
+    "getting_started.documentation": "Dogfennaeth",
+    "getting_started.find_friends": "Canfod ffrindiau o Twitter",
+    "getting_started.heading": "Dechrau",
+    "getting_started.invite": "Gwahoddwch bobl",
+    "getting_started.open_source_notice": "Mae Mastodon yn feddalwedd côd agored. Mae modd cyfrannu neu adrodd materion ar GitHUb ar {github}.",
+    "getting_started.security": "Diogelwch",
+    "getting_started.terms": "Telerau Gwasanaeth",
+    "home.column_settings.basic": "Syml",
+    "home.column_settings.show_reblogs": "",
+    "home.column_settings.show_replies": "Dangoswch ymatebion",
+    "keyboard_shortcuts.back": "",
+    "keyboard_shortcuts.blocked": "i agor rhestr defnyddwyr a flociwyd",
+    "keyboard_shortcuts.boost": "",
+    "keyboard_shortcuts.column": "",
+    "keyboard_shortcuts.compose": "",
+    "keyboard_shortcuts.description": "Disgrifiad",
+    "keyboard_shortcuts.direct": "i agor colofn negeseuon preifat",
+    "keyboard_shortcuts.down": "i symud lawr yn y rhestr",
+    "keyboard_shortcuts.enter": "i agor statws",
+    "keyboard_shortcuts.favourite": "i hoffi",
+    "keyboard_shortcuts.favourites": "i agor rhestr hoffi",
+    "keyboard_shortcuts.federated": "",
+    "keyboard_shortcuts.heading": "",
+    "keyboard_shortcuts.home": "i agor ffrwd cartref",
+    "keyboard_shortcuts.hotkey": "Hotkey",
+    "keyboard_shortcuts.legend": "",
+    "keyboard_shortcuts.local": "i agor ffrwd lleol",
+    "keyboard_shortcuts.mention": "i grybwyll yr awdur",
+    "keyboard_shortcuts.muted": "i agor rhestr defnyddwyr a dawelwyd",
+    "keyboard_shortcuts.my_profile": "i agor eich proffil",
+    "keyboard_shortcuts.notifications": "i agor colofn hysbysiadau",
+    "keyboard_shortcuts.pinned": "",
+    "keyboard_shortcuts.profile": "i agor proffil yr awdur",
+    "keyboard_shortcuts.reply": "i ateb",
+    "keyboard_shortcuts.requests": "i agor rhestr ceisiadau dilyn",
+    "keyboard_shortcuts.search": "",
+    "keyboard_shortcuts.start": "",
+    "keyboard_shortcuts.toggle_hidden": "",
+    "keyboard_shortcuts.toot": "i ddechrau tŵt newydd sbon",
+    "keyboard_shortcuts.unfocus": "",
+    "keyboard_shortcuts.up": "i symud yn uwch yn y rhestr",
+    "lightbox.close": "Cau",
+    "lightbox.next": "Nesaf",
+    "lightbox.previous": "",
+    "lists.account.add": "Ychwanegwch at restr",
+    "lists.account.remove": "",
+    "lists.delete": "Dileu rhestr",
+    "lists.edit": "Golygwch restr",
+    "lists.new.create": "Ychwanegwch restr",
+    "lists.new.title_placeholder": "Teitl rhestr newydd",
+    "lists.search": "",
+    "lists.subheading": "Eich rhestrau",
+    "loading_indicator.label": "Llwytho...",
+    "media_gallery.toggle_visible": "",
+    "missing_indicator.label": "Heb ei ganfod",
+    "missing_indicator.sublabel": "Ni ellid canfod yr adnodd hwn",
+    "mute_modal.hide_notifications": "Cuddiwch hysbysiadau rhag y defnyddiwr hwn?",
+    "navigation_bar.apps": "Apiau symudol",
+    "navigation_bar.blocks": "Defnyddwyr wedi eu blocio",
+    "navigation_bar.community_timeline": "",
+    "navigation_bar.compose": "Cyfansoddwch dŵt newydd",
+    "navigation_bar.direct": "Negeseuon preifat",
+    "navigation_bar.discover": "Darganfyddwch",
+    "navigation_bar.domain_blocks": "Parthau cuddiedig",
+    "navigation_bar.edit_profile": "Golygu proffil",
+    "navigation_bar.favourites": "Ffefrynnau",
+    "navigation_bar.filters": "Geiriau a dawelwyd",
+    "navigation_bar.follow_requests": "Ceisiadau dilyn",
+    "navigation_bar.info": "",
+    "navigation_bar.keyboard_shortcuts": "",
+    "navigation_bar.lists": "Rhestrau",
+    "navigation_bar.logout": "Allgofnodi",
+    "navigation_bar.mutes": "Defnyddwyr a dawelwyd",
+    "navigation_bar.personal": "Personol",
+    "navigation_bar.pins": "Tŵtiau wedi eu pinio",
+    "navigation_bar.preferences": "Dewisiadau",
+    "navigation_bar.public_timeline": "",
+    "navigation_bar.security": "Diogelwch",
+    "notification.favourite": "hoffodd {name} eich statws",
+    "notification.follow": "dilynodd {name} chi",
+    "notification.mention": "Soniodd {name} amdanoch chi",
+    "notification.reblog": "",
+    "notifications.clear": "Clirio hysbysiadau",
+    "notifications.clear_confirmation": "",
+    "notifications.column_settings.alert": "",
+    "notifications.column_settings.favourite": "Ffefrynnau:",
+    "notifications.column_settings.follow": "Dilynwyr newydd:",
+    "notifications.column_settings.mention": "",
+    "notifications.column_settings.push": "Hysbysiadau push",
+    "notifications.column_settings.reblog": "",
+    "notifications.column_settings.show": "",
+    "notifications.column_settings.sound": "Chwarae sain",
+    "notifications.group": "{count} o hysbysiadau",
+    "onboarding.done": "Wedi'i wneud",
+    "onboarding.next": "Nesaf",
+    "onboarding.page_five.public_timelines": "",
+    "onboarding.page_four.home": "Mae'r ffrwd gartref yn dangos twtiau o bobl yr ydych yn dilyn.",
+    "onboarding.page_four.notifications": "",
+    "onboarding.page_one.federation": "",
+    "onboarding.page_one.full_handle": "",
+    "onboarding.page_one.handle_hint": "",
+    "onboarding.page_one.welcome": "Croeso i Mastodon!",
+    "onboarding.page_six.admin": "",
+    "onboarding.page_six.almost_done": "Bron a gorffen...",
+    "onboarding.page_six.appetoot": "Bon Apetŵt!",
+    "onboarding.page_six.apps_available": "Mae yna {apps} ar gael i iOS, Android a platfformau eraill.",
+    "onboarding.page_six.github": "Mae Mastodon yn feddalwedd côd agored rhad ac am ddim. Mae modd adrodd bygiau, gwneud ceisiadau am nodweddion penodol, neu gyfrannu i'r côd ar {github}.",
+    "onboarding.page_six.guidelines": "canllawiau cymunedol",
+    "onboarding.page_six.read_guidelines": "Darllenwch {guidelines} y {domain} os gwelwch yn dda!",
+    "onboarding.page_six.various_app": "apiau symudol",
+    "onboarding.page_three.profile": "",
+    "onboarding.page_three.search": "",
+    "onboarding.page_two.compose": "",
+    "onboarding.skip": "Sgipiwch",
+    "privacy.change": "",
+    "privacy.direct.long": "",
+    "privacy.direct.short": "Uniongyrchol",
+    "privacy.private.long": "Cyhoeddi i ddilynwyr yn unig",
+    "privacy.private.short": "Dilynwyr-yn-unig",
+    "privacy.public.long": "Cyhoeddi i ffrydiau cyhoeddus",
+    "privacy.public.short": "Cyhoeddus",
+    "privacy.unlisted.long": "Peidio a cyhoeddi i ffrydiau cyhoeddus",
+    "privacy.unlisted.short": "Heb ei restru",
+    "regeneration_indicator.label": "Llwytho…",
+    "regeneration_indicator.sublabel": "Mae eich ffrwd cartref yn cael ei baratoi!",
+    "relative_time.days": "{number}d",
+    "relative_time.hours": "{number}h",
+    "relative_time.just_now": "nawr",
+    "relative_time.minutes": "{number}m",
+    "relative_time.seconds": "{number}s",
+    "reply_indicator.cancel": "Canslo",
+    "report.forward": "",
+    "report.forward_hint": "",
+    "report.hint": "",
+    "report.placeholder": "Sylwadau ychwanegol",
+    "report.submit": "Cyflwyno",
+    "report.target": "",
+    "search.placeholder": "Chwilio",
+    "search_popout.search_format": "Fformat chwilio uwch",
+    "search_popout.tips.full_text": "",
+    "search_popout.tips.hashtag": "hashnod",
+    "search_popout.tips.status": "statws",
+    "search_popout.tips.text": "",
+    "search_popout.tips.user": "defnyddiwr",
+    "search_results.accounts": "Pobl",
+    "search_results.hashtags": "Hanshnodau",
+    "search_results.statuses": "Twtiau",
+    "search_results.total": "",
+    "standalone.public_title": "Golwg tu fewn...",
+    "status.block": "Blociwch @{name}",
+    "status.cancel_reblog_private": "",
+    "status.cannot_reblog": "",
+    "status.delete": "Dileu",
+    "status.detailed_status": "",
+    "status.direct": "Neges breifat @{name}",
+    "status.embed": "Plannu",
+    "status.favourite": "",
+    "status.filtered": "",
+    "status.load_more": "Llwythwch mwy",
+    "status.media_hidden": "",
+    "status.mention": "",
+    "status.more": "Mwy",
+    "status.mute": "Tawelu @{name}",
+    "status.mute_conversation": "",
+    "status.open": "",
+    "status.pin": "",
+    "status.pinned": "",
+    "status.reblog": "",
+    "status.reblog_private": "",
+    "status.reblogged_by": "",
+    "status.reblogs.empty": "",
+    "status.redraft": "Dilëwh & ailddrafftio",
+    "status.reply": "Ateb",
+    "status.replyAll": "Ateb i edefyn",
+    "status.report": "",
+    "status.sensitive_toggle": "",
+    "status.sensitive_warning": "Cynnwys sensitif",
+    "status.share": "Rhannwch",
+    "status.show_less": "Dangoswch lai",
+    "status.show_less_all": "Dangoswch lai i bawb",
+    "status.show_more": "Dangoswch fwy",
+    "status.show_more_all": "",
+    "status.unmute_conversation": "Dad-dawelu sgwrs",
+    "status.unpin": "",
+    "tabs_bar.federated_timeline": "",
+    "tabs_bar.home": "Hafan",
+    "tabs_bar.local_timeline": "Lleol",
+    "tabs_bar.notifications": "Hysbysiadau",
+    "tabs_bar.search": "Chwilio",
+    "trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} yn siarad",
+    "ui.beforeunload": "Mi fyddwch yn colli eich drafft os gadewch Mastodon.",
+    "upload_area.title": "Llusgwch & gollwing i uwchlwytho",
+    "upload_button.label": "Ychwanegwch gyfryngau (JPEG, PNG, GIF, WebM, MP4, MOV)",
+    "upload_form.description": "",
+    "upload_form.focus": "",
+    "upload_form.undo": "Dileu",
+    "upload_progress.label": "Uwchlwytho...",
+    "video.close": "Cau fideo",
+    "video.exit_fullscreen": "Gadael sgrîn llawn",
+    "video.expand": "Ymestyn fideo",
+    "video.fullscreen": "Sgrîn llawn",
+    "video.hide": "Cuddio fideo",
+    "video.mute": "Tawelu sain",
+    "video.pause": "Oedi",
+    "video.play": "Chwarae",
+    "video.unmute": "Dad-dawelu sain"
 }
diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json
index 959a50377..e3d040ea8 100644
--- a/app/javascript/mastodon/locales/da.json
+++ b/app/javascript/mastodon/locales/da.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Nye følgere:",
   "notifications.column_settings.mention": "Omtale:",
   "notifications.column_settings.push": "Push notifikationer",
-  "notifications.column_settings.push_meta": "Denne enhed",
   "notifications.column_settings.reblog": "Fremhævelser:",
   "notifications.column_settings.show": "Vis i kolonne",
   "notifications.column_settings.sound": "Afspil lyd",
diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json
index 4f1b2c8a0..d798878fb 100644
--- a/app/javascript/mastodon/locales/de.json
+++ b/app/javascript/mastodon/locales/de.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Neue Folgende:",
   "notifications.column_settings.mention": "Erwähnungen:",
   "notifications.column_settings.push": "Push-Benachrichtigungen",
-  "notifications.column_settings.push_meta": "Auf diesem Gerät",
   "notifications.column_settings.reblog": "Geteilte Beiträge:",
   "notifications.column_settings.show": "In der Spalte anzeigen",
   "notifications.column_settings.sound": "Ton abspielen",
diff --git a/app/javascript/mastodon/locales/defaultMessages.json b/app/javascript/mastodon/locales/defaultMessages.json
index 5215bfb4e..b396726f7 100644
--- a/app/javascript/mastodon/locales/defaultMessages.json
+++ b/app/javascript/mastodon/locales/defaultMessages.json
@@ -1542,10 +1542,6 @@
         "id": "notifications.column_settings.push"
       },
       {
-        "defaultMessage": "This device",
-        "id": "notifications.column_settings.push_meta"
-      },
-      {
         "defaultMessage": "New followers:",
         "id": "notifications.column_settings.follow"
       },
@@ -2141,4 +2137,4 @@
     ],
     "path": "app/javascript/mastodon/features/video/index.json"
   }
-]
\ No newline at end of file
+]
diff --git a/app/javascript/mastodon/locales/el.json b/app/javascript/mastodon/locales/el.json
index 9c2a31722..4e4b733ec 100644
--- a/app/javascript/mastodon/locales/el.json
+++ b/app/javascript/mastodon/locales/el.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Νέοι ακόλουθοι:",
   "notifications.column_settings.mention": "Αναφορές:",
   "notifications.column_settings.push": "Άμεσες ειδοποιήσεις",
-  "notifications.column_settings.push_meta": "Αυτή η συσκευή",
   "notifications.column_settings.reblog": "Προωθήσεις:",
   "notifications.column_settings.show": "Εμφάνισε σε στήλη",
   "notifications.column_settings.sound": "Ηχητική ειδοποίηση",
diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json
index b117dad95..65b290be7 100644
--- a/app/javascript/mastodon/locales/en.json
+++ b/app/javascript/mastodon/locales/en.json
@@ -221,7 +221,6 @@
   "notifications.column_settings.follow": "New followers:",
   "notifications.column_settings.mention": "Mentions:",
   "notifications.column_settings.push": "Push notifications",
-  "notifications.column_settings.push_meta": "This device",
   "notifications.column_settings.reblog": "Boosts:",
   "notifications.column_settings.show": "Show in column",
   "notifications.column_settings.sound": "Play sound",
diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json
index dcc565eb9..86bee46b1 100644
--- a/app/javascript/mastodon/locales/eo.json
+++ b/app/javascript/mastodon/locales/eo.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Novaj sekvantoj:",
   "notifications.column_settings.mention": "Mencioj:",
   "notifications.column_settings.push": "Puŝsciigoj",
-  "notifications.column_settings.push_meta": "Ĉi tiu aparato",
   "notifications.column_settings.reblog": "Diskonigoj:",
   "notifications.column_settings.show": "Montri en kolumno",
   "notifications.column_settings.sound": "Eligi sonon",
diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json
index 355c901fa..63f197c28 100644
--- a/app/javascript/mastodon/locales/es.json
+++ b/app/javascript/mastodon/locales/es.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Nuevos seguidores:",
   "notifications.column_settings.mention": "Menciones:",
   "notifications.column_settings.push": "Notificaciones push",
-  "notifications.column_settings.push_meta": "Este dispositivo",
   "notifications.column_settings.reblog": "Retoots:",
   "notifications.column_settings.show": "Mostrar en columna",
   "notifications.column_settings.sound": "Reproducir sonido",
diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json
index 1dc42ae68..e4b1154b7 100644
--- a/app/javascript/mastodon/locales/eu.json
+++ b/app/javascript/mastodon/locales/eu.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Jarraitzaile berriak:",
   "notifications.column_settings.mention": "Aipamenak:",
   "notifications.column_settings.push": "Push jakinarazpenak",
-  "notifications.column_settings.push_meta": "Gailu hau",
   "notifications.column_settings.reblog": "Bultzadak:",
   "notifications.column_settings.show": "Erakutsi zutabean",
   "notifications.column_settings.sound": "Jo soinua",
diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json
index 2e3999918..fb4ded11c 100644
--- a/app/javascript/mastodon/locales/fa.json
+++ b/app/javascript/mastodon/locales/fa.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "پیگیران تازه:",
   "notifications.column_settings.mention": "نام‌بردن‌ها:",
   "notifications.column_settings.push": "اعلان‌ها از سمت سرور",
-  "notifications.column_settings.push_meta": "این دستگاه",
   "notifications.column_settings.reblog": "بازبوق‌ها:",
   "notifications.column_settings.show": "نمایش در ستون",
   "notifications.column_settings.sound": "پخش صدا",
diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json
index f6c0469be..caf949e8c 100644
--- a/app/javascript/mastodon/locales/fi.json
+++ b/app/javascript/mastodon/locales/fi.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Uudet seuraajat:",
   "notifications.column_settings.mention": "Maininnat:",
   "notifications.column_settings.push": "Push-ilmoitukset",
-  "notifications.column_settings.push_meta": "Tämä laite",
   "notifications.column_settings.reblog": "Buustit:",
   "notifications.column_settings.show": "Näytä sarakkeessa",
   "notifications.column_settings.sound": "Äänimerkki",
diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json
index 075bdcf30..ff09a1402 100644
--- a/app/javascript/mastodon/locales/fr.json
+++ b/app/javascript/mastodon/locales/fr.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Nouveaux⋅elles abonné⋅e·s :",
   "notifications.column_settings.mention": "Mentions :",
   "notifications.column_settings.push": "Notifications",
-  "notifications.column_settings.push_meta": "Cet appareil",
   "notifications.column_settings.reblog": "Partages :",
   "notifications.column_settings.show": "Afficher dans la colonne",
   "notifications.column_settings.sound": "Émettre un son",
diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json
index 8b830ae7b..6afa21c9f 100644
--- a/app/javascript/mastodon/locales/gl.json
+++ b/app/javascript/mastodon/locales/gl.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Novos seguidores:",
   "notifications.column_settings.mention": "Mencións:",
   "notifications.column_settings.push": "Enviar notificacións",
-  "notifications.column_settings.push_meta": "Este aparello",
   "notifications.column_settings.reblog": "Promocións:",
   "notifications.column_settings.show": "Mostrar en columna",
   "notifications.column_settings.sound": "Reproducir son",
diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json
index 4aee82212..d670d8a55 100644
--- a/app/javascript/mastodon/locales/he.json
+++ b/app/javascript/mastodon/locales/he.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "עוקבים חדשים:",
   "notifications.column_settings.mention": "פניות:",
   "notifications.column_settings.push": "הודעות בדחיפה",
-  "notifications.column_settings.push_meta": "מכשיר זה",
   "notifications.column_settings.reblog": "הדהודים:",
   "notifications.column_settings.show": "הצגה בטור",
   "notifications.column_settings.sound": "שמע מופעל",
diff --git a/app/javascript/mastodon/locales/hr.json b/app/javascript/mastodon/locales/hr.json
index a138cf589..b76b82e1b 100644
--- a/app/javascript/mastodon/locales/hr.json
+++ b/app/javascript/mastodon/locales/hr.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Novi sljedbenici:",
   "notifications.column_settings.mention": "Spominjanja:",
   "notifications.column_settings.push": "Push notifications",
-  "notifications.column_settings.push_meta": "This device",
   "notifications.column_settings.reblog": "Boostovi:",
   "notifications.column_settings.show": "Prikaži u stupcu",
   "notifications.column_settings.sound": "Sviraj zvuk",
diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json
index 6a4d0ecf0..57a8b7cfa 100644
--- a/app/javascript/mastodon/locales/hu.json
+++ b/app/javascript/mastodon/locales/hu.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Új követők:",
   "notifications.column_settings.mention": "Megemítéseim:",
   "notifications.column_settings.push": "Push értesítések",
-  "notifications.column_settings.push_meta": "Ezen eszköz",
   "notifications.column_settings.reblog": "Rebloggolások:",
   "notifications.column_settings.show": "Oszlopban mutatás",
   "notifications.column_settings.sound": "Hang lejátszása",
diff --git a/app/javascript/mastodon/locales/hy.json b/app/javascript/mastodon/locales/hy.json
index 7d7090236..077748a0a 100644
--- a/app/javascript/mastodon/locales/hy.json
+++ b/app/javascript/mastodon/locales/hy.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Նոր հետեւողներ՝",
   "notifications.column_settings.mention": "Նշումներ՝",
   "notifications.column_settings.push": "Հրելու ծանուցումներ",
-  "notifications.column_settings.push_meta": "Այս սարքը",
   "notifications.column_settings.reblog": "Տարածածներից՝",
   "notifications.column_settings.show": "Ցուցադրել սյունում",
   "notifications.column_settings.sound": "Ձայն հանել",
diff --git a/app/javascript/mastodon/locales/id.json b/app/javascript/mastodon/locales/id.json
index c8ed00e9f..3d80c0949 100644
--- a/app/javascript/mastodon/locales/id.json
+++ b/app/javascript/mastodon/locales/id.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Pengikut baru:",
   "notifications.column_settings.mention": "Balasan:",
   "notifications.column_settings.push": "Push notifications",
-  "notifications.column_settings.push_meta": "This device",
   "notifications.column_settings.reblog": "Boost:",
   "notifications.column_settings.show": "Tampilkan dalam kolom",
   "notifications.column_settings.sound": "Mainkan suara",
diff --git a/app/javascript/mastodon/locales/io.json b/app/javascript/mastodon/locales/io.json
index c92ceccd1..9059b3a2b 100644
--- a/app/javascript/mastodon/locales/io.json
+++ b/app/javascript/mastodon/locales/io.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Nova sequanti:",
   "notifications.column_settings.mention": "Mencioni:",
   "notifications.column_settings.push": "Push notifications",
-  "notifications.column_settings.push_meta": "This device",
   "notifications.column_settings.reblog": "Repeti:",
   "notifications.column_settings.show": "Montrar en kolumno",
   "notifications.column_settings.sound": "Plear sono",
diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json
index e9eb62e71..5d8e3fe4a 100644
--- a/app/javascript/mastodon/locales/it.json
+++ b/app/javascript/mastodon/locales/it.json
@@ -3,7 +3,7 @@
   "account.block": "Blocca @{name}",
   "account.block_domain": "Nascondi tutto da {domain}",
   "account.blocked": "Bloccato",
-  "account.direct": "Direct Message @{name}",
+  "account.direct": "Invia messaggio diretto a @{name}",
   "account.disclaimer_full": "Il profilo dell'utente mostrato qui sotto potrebbe essere incompleto.",
   "account.domain_blocked": "Dominio nascosto",
   "account.edit_profile": "Modifica profilo",
@@ -54,7 +54,7 @@
   "column.lists": "Liste",
   "column.mutes": "Utenti silenziati",
   "column.notifications": "Notifiche",
-  "column.pins": "Pinned toot",
+  "column.pins": "Toot fissati in cima",
   "column.public": "Timeline federata",
   "column_back_button.label": "Indietro",
   "column_header.hide_settings": "Nascondi impostazioni",
@@ -79,11 +79,11 @@
   "compose_form.spoiler.unmarked": "Il testo non è nascosto",
   "compose_form.spoiler_placeholder": "Content warning",
   "confirmation_modal.cancel": "Annulla",
-  "confirmations.block.confirm": "Block",
+  "confirmations.block.confirm": "Blocca",
   "confirmations.block.message": "Sei sicuro di voler bloccare {name}?",
-  "confirmations.delete.confirm": "Delete",
+  "confirmations.delete.confirm": "Cancella",
   "confirmations.delete.message": "Sei sicuro di voler cancellare questo status?",
-  "confirmations.delete_list.confirm": "Delete",
+  "confirmations.delete_list.confirm": "Cancella",
   "confirmations.delete_list.message": "Sei sicuro di voler cancellare definitivamente questa lista?",
   "confirmations.domain_block.confirm": "Nascondi intero dominio",
   "confirmations.domain_block.message": "Sei davvero sicuro che vuoi bloccare l'intero {domain}? Nella maggior parte dei casi, pochi blocchi o silenziamenti mirati sono sufficienti e preferibili. Non vedrai nessun contenuto di quel dominio né nelle timeline pubbliche né nelle notifiche. I tuoi seguaci di quel dominio saranno eliminati.",
@@ -119,7 +119,7 @@
   "empty_column.hashtag": "Non c'è ancora nessun post con questo hashtag.",
   "empty_column.home": "Non stai ancora seguendo nessuno. Visita {public} o usa la ricerca per incontrare nuove persone.",
   "empty_column.home.public_timeline": "la timeline pubblica",
-  "empty_column.list": "Non c'è niente in questo elenco ancora. Quando i membri di questo elenco postano nuovi stati, questi appariranno qui.",
+  "empty_column.list": "Non c'è ancora niente in questa lista. Quando i membri di questa lista pubblicheranno nuovi stati, appariranno qui.",
   "empty_column.lists": "Non hai ancora nessuna lista. Quando ne creerai qualcuna, comparirà qui.",
   "empty_column.mutes": "Non hai ancora silenziato nessun utente.",
   "empty_column.notifications": "Non hai ancora nessuna notifica. Interagisci con altri per iniziare conversazioni.",
@@ -179,7 +179,7 @@
   "lists.new.title_placeholder": "Titolo della nuova lista",
   "lists.search": "Cerca tra le persone che segui",
   "lists.subheading": "Le tue liste",
-  "loading_indicator.label": "Carico...",
+  "loading_indicator.label": "Caricamento...",
   "media_gallery.toggle_visible": "Imposta visibilità",
   "missing_indicator.label": "Non trovato",
   "missing_indicator.sublabel": "Risorsa non trovata",
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Nuovi seguaci:",
   "notifications.column_settings.mention": "Menzioni:",
   "notifications.column_settings.push": "Notifiche push",
-  "notifications.column_settings.push_meta": "Questo dispositivo",
   "notifications.column_settings.reblog": "Post condivisi:",
   "notifications.column_settings.show": "Mostra in colonna",
   "notifications.column_settings.sound": "Riproduci suono",
@@ -242,7 +241,7 @@
   "onboarding.page_three.search": "Usa la barra di ricerca per trovare persone e hashtag, come {illustration} e {introductions}. Per trovare una persona che non è su questa istanza, usa il suo nome utente completo.",
   "onboarding.page_two.compose": "Puoi scrivere dei post dalla colonna di composizione. Puoi caricare immagini, modificare le impostazioni di privacy, e aggiungere avvisi sul contenuto con le icone qui sotto.",
   "onboarding.skip": "Salta",
-  "privacy.change": "Modifica privacy post",
+  "privacy.change": "Modifica privacy del post",
   "privacy.direct.long": "Invia solo a utenti menzionati",
   "privacy.direct.short": "Diretto",
   "privacy.private.long": "Invia solo ai seguaci",
@@ -261,7 +260,7 @@
   "reply_indicator.cancel": "Annulla",
   "report.forward": "Inoltra a {target}",
   "report.forward_hint": "Questo account appartiene a un altro server. Mandare anche là una copia anonima del rapporto?",
-  "report.hint": "La segnalazione sara' invata ai tuoi moderatori di istanza. Di seguito, puoi fornire  il motivo per il quale stai segnalando questo account:",
+  "report.hint": "La segnalazione sarà inviata ai moderatori della tua istanza. Di seguito, puoi fornire il motivo per il quale stai segnalando questo account:",
   "report.placeholder": "Commenti aggiuntivi",
   "report.submit": "Invia",
   "report.target": "Invio la segnalazione {target}",
@@ -328,10 +327,10 @@
   "video.close": "Chiudi video",
   "video.exit_fullscreen": "Esci da modalità a schermo intero",
   "video.expand": "Espandi video",
-  "video.fullscreen": "Full screen",
+  "video.fullscreen": "Schermo intero",
   "video.hide": "Nascondi video",
   "video.mute": "Silenzia suono",
-  "video.pause": "Pause",
+  "video.pause": "Pausa",
   "video.play": "Avvia",
   "video.unmute": "Riattiva suono"
 }
diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json
index 04a2e4692..c84387051 100644
--- a/app/javascript/mastodon/locales/ja.json
+++ b/app/javascript/mastodon/locales/ja.json
@@ -221,7 +221,6 @@
   "notifications.column_settings.follow": "新しいフォロワー:",
   "notifications.column_settings.mention": "返信:",
   "notifications.column_settings.push": "プッシュ通知",
-  "notifications.column_settings.push_meta": "このデバイス",
   "notifications.column_settings.reblog": "ブースト:",
   "notifications.column_settings.show": "カラムに表示",
   "notifications.column_settings.sound": "通知音を再生",
diff --git a/app/javascript/mastodon/locales/ka.json b/app/javascript/mastodon/locales/ka.json
index ec6e211c6..21cd7d644 100644
--- a/app/javascript/mastodon/locales/ka.json
+++ b/app/javascript/mastodon/locales/ka.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "ახალი მიმდევრები:",
   "notifications.column_settings.mention": "ხსენებები:",
   "notifications.column_settings.push": "ფუშ შეტყობინებები",
-  "notifications.column_settings.push_meta": "ეს მოწყობილობა",
   "notifications.column_settings.reblog": "ბუსტები:",
   "notifications.column_settings.show": "გამოჩნდეს სვეტში",
   "notifications.column_settings.sound": "ხმის დაკვრა",
diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json
index 15e8524e0..8e0f9f59f 100644
--- a/app/javascript/mastodon/locales/ko.json
+++ b/app/javascript/mastodon/locales/ko.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "새 팔로워:",
   "notifications.column_settings.mention": "답글:",
   "notifications.column_settings.push": "푸시 알림",
-  "notifications.column_settings.push_meta": "이 장치",
   "notifications.column_settings.reblog": "부스트:",
   "notifications.column_settings.show": "컬럼에 표시",
   "notifications.column_settings.sound": "효과음 재생",
diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json
index f829146f1..e6b85692c 100644
--- a/app/javascript/mastodon/locales/nl.json
+++ b/app/javascript/mastodon/locales/nl.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Nieuwe volgers:",
   "notifications.column_settings.mention": "Vermeldingen:",
   "notifications.column_settings.push": "Pushmeldingen",
-  "notifications.column_settings.push_meta": "Dit apparaat",
   "notifications.column_settings.reblog": "Boosts:",
   "notifications.column_settings.show": "In kolom tonen",
   "notifications.column_settings.sound": "Geluid afspelen",
diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json
index e531789a9..4a8176e82 100644
--- a/app/javascript/mastodon/locales/no.json
+++ b/app/javascript/mastodon/locales/no.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Nye følgere:",
   "notifications.column_settings.mention": "Nevnt:",
   "notifications.column_settings.push": "Push varsler",
-  "notifications.column_settings.push_meta": "Denne enheten",
   "notifications.column_settings.reblog": "Fremhevet:",
   "notifications.column_settings.show": "Vis i kolonne",
   "notifications.column_settings.sound": "Spill lyd",
diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json
index 182710038..64cbaef55 100644
--- a/app/javascript/mastodon/locales/oc.json
+++ b/app/javascript/mastodon/locales/oc.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Nòus seguidors :",
   "notifications.column_settings.mention": "Mencions :",
   "notifications.column_settings.push": "Notificacions",
-  "notifications.column_settings.push_meta": "Aqueste periferic",
   "notifications.column_settings.reblog": "Partatges :",
   "notifications.column_settings.show": "Mostrar dins la colomna",
   "notifications.column_settings.sound": "Emetre un son",
diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json
index aa2535bf7..0b9828813 100644
--- a/app/javascript/mastodon/locales/pl.json
+++ b/app/javascript/mastodon/locales/pl.json
@@ -221,7 +221,6 @@
   "notifications.column_settings.follow": "Nowi śledzący:",
   "notifications.column_settings.mention": "Wspomnienia:",
   "notifications.column_settings.push": "Powiadomienia push",
-  "notifications.column_settings.push_meta": "To urządzenie",
   "notifications.column_settings.reblog": "Podbicia:",
   "notifications.column_settings.show": "Pokaż w kolumnie",
   "notifications.column_settings.sound": "Odtwarzaj dźwięk",
diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json
index 9c48f0bc1..3e5b5da8e 100644
--- a/app/javascript/mastodon/locales/pt-BR.json
+++ b/app/javascript/mastodon/locales/pt-BR.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Novos seguidores:",
   "notifications.column_settings.mention": "Menções:",
   "notifications.column_settings.push": "Enviar notificações",
-  "notifications.column_settings.push_meta": "Este aparelho",
   "notifications.column_settings.reblog": "Compartilhamento:",
   "notifications.column_settings.show": "Mostrar nas colunas",
   "notifications.column_settings.sound": "Reproduzir som",
diff --git a/app/javascript/mastodon/locales/pt.json b/app/javascript/mastodon/locales/pt.json
index 096fded95..e9d91f631 100644
--- a/app/javascript/mastodon/locales/pt.json
+++ b/app/javascript/mastodon/locales/pt.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Novos seguidores:",
   "notifications.column_settings.mention": "Menções:",
   "notifications.column_settings.push": "Notificações Push",
-  "notifications.column_settings.push_meta": "Este dispositivo",
   "notifications.column_settings.reblog": "Partilhas:",
   "notifications.column_settings.show": "Mostrar nas colunas",
   "notifications.column_settings.sound": "Reproduzir som",
diff --git a/app/javascript/mastodon/locales/ro.json b/app/javascript/mastodon/locales/ro.json
index fda82136e..1d6e73bfd 100644
--- a/app/javascript/mastodon/locales/ro.json
+++ b/app/javascript/mastodon/locales/ro.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Noi urmăritori:",
   "notifications.column_settings.mention": "Mențiuni:",
   "notifications.column_settings.push": "Notificări push",
-  "notifications.column_settings.push_meta": "Acest dispozitiv",
   "notifications.column_settings.reblog": "Redistribuite:",
   "notifications.column_settings.show": "Arată în coloană",
   "notifications.column_settings.sound": "Redă sunet",
diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json
index 8961136a3..15fbfac3f 100644
--- a/app/javascript/mastodon/locales/ru.json
+++ b/app/javascript/mastodon/locales/ru.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Новые подписчики:",
   "notifications.column_settings.mention": "Упоминания:",
   "notifications.column_settings.push": "Push-уведомления",
-  "notifications.column_settings.push_meta": "Это устройство",
   "notifications.column_settings.reblog": "Продвижения:",
   "notifications.column_settings.show": "Показывать в колонке",
   "notifications.column_settings.sound": "Проигрывать звук",
diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json
index 1264b6d08..11a6b76c1 100644
--- a/app/javascript/mastodon/locales/sk.json
+++ b/app/javascript/mastodon/locales/sk.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Noví následujúci:",
   "notifications.column_settings.mention": "Zmienenia:",
   "notifications.column_settings.push": "Push notifikácie",
-  "notifications.column_settings.push_meta": "Toto zariadenie",
   "notifications.column_settings.reblog": "Boosty:",
   "notifications.column_settings.show": "Zobraziť v stĺpci",
   "notifications.column_settings.sound": "Prehrať zvuk",
diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json
index 6250aab62..f715abe85 100644
--- a/app/javascript/mastodon/locales/sl.json
+++ b/app/javascript/mastodon/locales/sl.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "New followers:",
   "notifications.column_settings.mention": "Mentions:",
   "notifications.column_settings.push": "Push notifications",
-  "notifications.column_settings.push_meta": "This device",
   "notifications.column_settings.reblog": "Boosts:",
   "notifications.column_settings.show": "Show in column",
   "notifications.column_settings.sound": "Play sound",
diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json
index 0ef07a170..7131d3044 100644
--- a/app/javascript/mastodon/locales/sr-Latn.json
+++ b/app/javascript/mastodon/locales/sr-Latn.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Novi pratioci:",
   "notifications.column_settings.mention": "Pominjanja:",
   "notifications.column_settings.push": "Guraj obaveštenja",
-  "notifications.column_settings.push_meta": "Ovaj uređaj",
   "notifications.column_settings.reblog": "Podrški:",
   "notifications.column_settings.show": "Prikaži u koloni",
   "notifications.column_settings.sound": "Puštaj zvuk",
diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json
index ca2c1b225..806c0acb3 100644
--- a/app/javascript/mastodon/locales/sr.json
+++ b/app/javascript/mastodon/locales/sr.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Нови пратиоци:",
   "notifications.column_settings.mention": "Помињања:",
   "notifications.column_settings.push": "Гурај обавештења",
-  "notifications.column_settings.push_meta": "Овај уређај",
   "notifications.column_settings.reblog": "Подршки:",
   "notifications.column_settings.show": "Прикажи у колони",
   "notifications.column_settings.sound": "Пуштај звук",
diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json
index c7df96cf5..f9129d368 100644
--- a/app/javascript/mastodon/locales/sv.json
+++ b/app/javascript/mastodon/locales/sv.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Nya följare:",
   "notifications.column_settings.mention": "Omnämningar:",
   "notifications.column_settings.push": "Push meddelanden",
-  "notifications.column_settings.push_meta": "Denna anordning",
   "notifications.column_settings.reblog": "Knuffar:",
   "notifications.column_settings.show": "Visa i kolumnen",
   "notifications.column_settings.sound": "Spela upp ljud",
diff --git a/app/javascript/mastodon/locales/ta.json b/app/javascript/mastodon/locales/ta.json
index e0237c023..427e9a3dc 100644
--- a/app/javascript/mastodon/locales/ta.json
+++ b/app/javascript/mastodon/locales/ta.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "New followers:",
   "notifications.column_settings.mention": "Mentions:",
   "notifications.column_settings.push": "Push notifications",
-  "notifications.column_settings.push_meta": "This device",
   "notifications.column_settings.reblog": "Boosts:",
   "notifications.column_settings.show": "Show in column",
   "notifications.column_settings.sound": "Play sound",
diff --git a/app/javascript/mastodon/locales/te.json b/app/javascript/mastodon/locales/te.json
index 49f3ce2d9..bc13b02f1 100644
--- a/app/javascript/mastodon/locales/te.json
+++ b/app/javascript/mastodon/locales/te.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "క్రొత్త అనుచరులు:",
   "notifications.column_settings.mention": "ప్రస్తావనలు:",
   "notifications.column_settings.push": "పుష్ ప్రకటనలు",
-  "notifications.column_settings.push_meta": "ఈ పరికరం",
   "notifications.column_settings.reblog": "బూస్ట్ లు:",
   "notifications.column_settings.show": "నిలువు వరుసలో చూపు",
   "notifications.column_settings.sound": "ధ్వనిని ప్లే చేయి",
diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json
index 2af5bfca1..3114bca60 100644
--- a/app/javascript/mastodon/locales/th.json
+++ b/app/javascript/mastodon/locales/th.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "New followers:",
   "notifications.column_settings.mention": "Mentions:",
   "notifications.column_settings.push": "Push notifications",
-  "notifications.column_settings.push_meta": "This device",
   "notifications.column_settings.reblog": "Boosts:",
   "notifications.column_settings.show": "Show in column",
   "notifications.column_settings.sound": "Play sound",
diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json
index 68dc37e6b..a661b022b 100644
--- a/app/javascript/mastodon/locales/tr.json
+++ b/app/javascript/mastodon/locales/tr.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Yeni takipçiler:",
   "notifications.column_settings.mention": "Bahsedilenler:",
   "notifications.column_settings.push": "Push notifications",
-  "notifications.column_settings.push_meta": "This device",
   "notifications.column_settings.reblog": "Boost’lar:",
   "notifications.column_settings.show": "Bildirimlerde göster",
   "notifications.column_settings.sound": "Ses çal",
diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json
index 5517abdf8..116dfc489 100644
--- a/app/javascript/mastodon/locales/uk.json
+++ b/app/javascript/mastodon/locales/uk.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "Нові підписники:",
   "notifications.column_settings.mention": "Згадки:",
   "notifications.column_settings.push": "Push-сповіщення",
-  "notifications.column_settings.push_meta": "Цей пристрій",
   "notifications.column_settings.reblog": "Передмухи:",
   "notifications.column_settings.show": "Показати в колонці",
   "notifications.column_settings.sound": "Відтворювати звуки",
diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json
index 254beab42..69ecd9431 100644
--- a/app/javascript/mastodon/locales/zh-CN.json
+++ b/app/javascript/mastodon/locales/zh-CN.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "当有人关注你时:",
   "notifications.column_settings.mention": "当有人在嘟文中提及你时:",
   "notifications.column_settings.push": "推送通知",
-  "notifications.column_settings.push_meta": "此设备",
   "notifications.column_settings.reblog": "当有人转嘟了你的嘟文时:",
   "notifications.column_settings.show": "在通知栏显示",
   "notifications.column_settings.sound": "播放音效",
diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json
index ce141a8a7..fc5376699 100644
--- a/app/javascript/mastodon/locales/zh-HK.json
+++ b/app/javascript/mastodon/locales/zh-HK.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "關注你:",
   "notifications.column_settings.mention": "提及你:",
   "notifications.column_settings.push": "推送通知",
-  "notifications.column_settings.push_meta": "這臺設備",
   "notifications.column_settings.reblog": "轉推你的文章:",
   "notifications.column_settings.show": "在通知欄顯示",
   "notifications.column_settings.sound": "播放音效",
diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json
index fe4a81170..458af6b95 100644
--- a/app/javascript/mastodon/locales/zh-TW.json
+++ b/app/javascript/mastodon/locales/zh-TW.json
@@ -216,7 +216,6 @@
   "notifications.column_settings.follow": "新的關注者:",
   "notifications.column_settings.mention": "提到:",
   "notifications.column_settings.push": "推送通知",
-  "notifications.column_settings.push_meta": "這臺設備",
   "notifications.column_settings.reblog": "轉嘟:",
   "notifications.column_settings.show": "顯示在欄位中",
   "notifications.column_settings.sound": "播放音效",
diff --git a/app/javascript/mastodon/service_worker/web_push_notifications.js b/app/javascript/mastodon/service_worker/web_push_notifications.js
index d61d916b1..80a4fb329 100644
--- a/app/javascript/mastodon/service_worker/web_push_notifications.js
+++ b/app/javascript/mastodon/service_worker/web_push_notifications.js
@@ -168,7 +168,7 @@ const openUrl = url =>
 
       if (webClients.length !== 0) {
         const client       = findBestClient(webClients);
-        const { pathname } = new URL(url);
+        const { pathname } = new URL(url, self.location);
 
         if (pathname.startsWith('/web/')) {
           return client.focus().then(client => client.postMessage({
diff --git a/app/javascript/styles/mailer.scss b/app/javascript/styles/mailer.scss
index dbe070f9a..d83bd4d96 100644
--- a/app/javascript/styles/mailer.scss
+++ b/app/javascript/styles/mailer.scss
@@ -169,7 +169,7 @@ p {
   font-family: Helvetica, Arial, sans-serif;
 
   @media only screen {
-    font-family: 'mastodon-font-sans-serif', sans-serif !important;
+    font-family: $font-sans-serif, sans-serif !important;
   }
 }
 
diff --git a/app/javascript/styles/mastodon/about.scss b/app/javascript/styles/mastodon/about.scss
index 228dd96f0..dc456be3e 100644
--- a/app/javascript/styles/mastodon/about.scss
+++ b/app/javascript/styles/mastodon/about.scss
@@ -16,7 +16,7 @@ $small-breakpoint: 960px;
 }
 
 .rich-formatting {
-  font-family: 'mastodon-font-sans-serif', sans-serif;
+  font-family: $font-sans-serif, sans-serif;
   font-size: 16px;
   font-weight: 400;
   font-size: 16px;
@@ -31,7 +31,7 @@ $small-breakpoint: 960px;
 
   p,
   li {
-    font-family: 'mastodon-font-sans-serif', sans-serif;
+    font-family: $font-sans-serif, sans-serif;
     font-size: 16px;
     font-weight: 400;
     font-size: 16px;
@@ -62,7 +62,7 @@ $small-breakpoint: 960px;
   }
 
   h1 {
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     font-size: 26px;
     line-height: 30px;
     font-weight: 500;
@@ -70,7 +70,7 @@ $small-breakpoint: 960px;
     color: $secondary-text-color;
 
     small {
-      font-family: 'mastodon-font-sans-serif', sans-serif;
+      font-family: $font-sans-serif, sans-serif;
       display: block;
       font-size: 18px;
       font-weight: 400;
@@ -79,7 +79,7 @@ $small-breakpoint: 960px;
   }
 
   h2 {
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     font-size: 22px;
     line-height: 26px;
     font-weight: 500;
@@ -88,7 +88,7 @@ $small-breakpoint: 960px;
   }
 
   h3 {
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     font-size: 18px;
     line-height: 24px;
     font-weight: 500;
@@ -97,7 +97,7 @@ $small-breakpoint: 960px;
   }
 
   h4 {
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     font-size: 16px;
     line-height: 24px;
     font-weight: 500;
@@ -106,7 +106,7 @@ $small-breakpoint: 960px;
   }
 
   h5 {
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     font-size: 14px;
     line-height: 24px;
     font-weight: 500;
@@ -115,7 +115,7 @@ $small-breakpoint: 960px;
   }
 
   h6 {
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     font-size: 12px;
     line-height: 24px;
     font-weight: 500;
@@ -180,7 +180,7 @@ $small-breakpoint: 960px;
 
   &__section {
     flex: 1 0 0;
-    font-family: 'mastodon-font-sans-serif', sans-serif;
+    font-family: $font-sans-serif, sans-serif;
     font-size: 16px;
     line-height: 28px;
     color: $primary-text-color;
@@ -221,7 +221,7 @@ $small-breakpoint: 960px;
     bottom: -40px;
 
     .panel-header {
-      font-family: 'mastodon-font-display', sans-serif;
+      font-family: $font-display, sans-serif;
       font-size: 14px;
       line-height: 24px;
       font-weight: 500;
@@ -450,7 +450,7 @@ $small-breakpoint: 960px;
 
   p,
   li {
-    font-family: 'mastodon-font-sans-serif', sans-serif;
+    font-family: $font-sans-serif, sans-serif;
     font-size: 16px;
     font-weight: 400;
     font-size: 16px;
@@ -499,7 +499,7 @@ $small-breakpoint: 960px;
   }
 
   h1 {
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     font-size: 26px;
     line-height: 30px;
     font-weight: 500;
@@ -507,7 +507,7 @@ $small-breakpoint: 960px;
     color: $secondary-text-color;
 
     small {
-      font-family: 'mastodon-font-sans-serif', sans-serif;
+      font-family: $font-sans-serif, sans-serif;
       display: block;
       font-size: 18px;
       font-weight: 400;
@@ -516,7 +516,7 @@ $small-breakpoint: 960px;
   }
 
   h2 {
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     font-size: 22px;
     line-height: 26px;
     font-weight: 500;
@@ -525,7 +525,7 @@ $small-breakpoint: 960px;
   }
 
   h3 {
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     font-size: 18px;
     line-height: 24px;
     font-weight: 500;
@@ -534,7 +534,7 @@ $small-breakpoint: 960px;
   }
 
   h4 {
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     font-size: 16px;
     line-height: 24px;
     font-weight: 500;
@@ -543,7 +543,7 @@ $small-breakpoint: 960px;
   }
 
   h5 {
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     font-size: 14px;
     line-height: 24px;
     font-weight: 500;
@@ -552,7 +552,7 @@ $small-breakpoint: 960px;
   }
 
   h6 {
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     font-size: 12px;
     line-height: 24px;
     font-weight: 500;
@@ -619,7 +619,7 @@ $small-breakpoint: 960px;
 
       .hero .heading {
         padding-bottom: 20px;
-        font-family: 'mastodon-font-sans-serif', sans-serif;
+        font-family: $font-sans-serif, sans-serif;
         font-size: 16px;
         font-weight: 400;
         font-size: 16px;
@@ -670,7 +670,7 @@ $small-breakpoint: 960px;
         text-decoration: none;
         padding: 12px 16px;
         line-height: 32px;
-        font-family: 'mastodon-font-display', sans-serif;
+        font-family: $font-display, sans-serif;
         font-weight: 500;
         font-size: 14px;
 
@@ -743,7 +743,7 @@ $small-breakpoint: 960px;
   .about-short {
     background: darken($ui-base-color, 4%);
     padding: 50px 0 30px;
-    font-family: 'mastodon-font-sans-serif', sans-serif;
+    font-family: $font-sans-serif, sans-serif;
     font-size: 16px;
     font-weight: 400;
     font-size: 16px;
@@ -1012,7 +1012,7 @@ $small-breakpoint: 960px;
     display: flex;
     -webkit-overflow-scrolling: touch;
     -ms-overflow-style: -ms-autohiding-scrollbar;
-    font-family: 'mastodon-font-sans-serif', sans-serif;
+    font-family: $font-sans-serif, sans-serif;
     font-size: 13px;
     line-height: 18px;
     font-weight: 400;
diff --git a/app/javascript/styles/mastodon/admin.scss b/app/javascript/styles/mastodon/admin.scss
index 9dfd89dc2..b6c771abf 100644
--- a/app/javascript/styles/mastodon/admin.scss
+++ b/app/javascript/styles/mastodon/admin.scss
@@ -432,7 +432,7 @@ $no-columns-breakpoint: 600px;
     border-radius: 0 0 4px 4px;
     padding: 10px;
     color: $darker-text-color;
-    font-family: 'mastodon-font-monospace', monospace;
+    font-family: $font-monospace, monospace;
     font-size: 12px;
     word-wrap: break-word;
     min-height: 20px;
diff --git a/app/javascript/styles/mastodon/basics.scss b/app/javascript/styles/mastodon/basics.scss
index 3bbb31e6e..746def625 100644
--- a/app/javascript/styles/mastodon/basics.scss
+++ b/app/javascript/styles/mastodon/basics.scss
@@ -6,7 +6,7 @@
 }
 
 body {
-  font-family: 'mastodon-font-sans-serif', sans-serif;
+  font-family: $font-sans-serif, sans-serif;
   background: darken($ui-base-color, 8%);
   font-size: 13px;
   line-height: 18px;
@@ -29,8 +29,8 @@ body {
     // Fira Sans => Firefox OS
     // Droid Sans => Older Androids (<4.0)
     // Helvetica Neue => Older macOS <10.11
-    // mastodon-font-sans-serif => web-font (Roboto) fallback and newer Androids (>=4.0)
-    font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", mastodon-font-sans-serif, sans-serif;
+    // $font-sans-serif => web-font (Roboto) fallback and newer Androids (>=4.0)
+    font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", $font-sans-serif, sans-serif;
   }
 
   &.app-body {
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index 490e26ccc..ecd1a8063 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -552,7 +552,7 @@
 
       .character-counter {
         cursor: default;
-        font-family: 'mastodon-font-sans-serif', sans-serif;
+        font-family: $font-sans-serif, sans-serif;
         font-size: 14px;
         font-weight: 600;
         color: $lighter-text-color;
@@ -631,11 +631,13 @@
 
 .status__content,
 .reply-indicator__content {
+  position: relative;
   font-size: 15px;
   line-height: 20px;
   word-wrap: break-word;
   font-weight: 400;
   overflow: hidden;
+  text-overflow: ellipsis;
   white-space: pre-wrap;
   padding-top: 2px;
   color: $primary-text-color;
@@ -721,6 +723,26 @@
   }
 }
 
+.status__content.status__content--collapsed {
+  max-height: 20px * 15; // 15 lines is roughly above 500 characters
+}
+
+.status__content__read-more-button {
+  display: block;
+  font-size: 15px;
+  line-height: 20px;
+  color: lighten($ui-highlight-color, 8%);
+  border: 0;
+  background: transparent;
+  padding: 0;
+  padding-top: 8px;
+
+  &:hover,
+  &:active {
+    text-decoration: underline;
+  }
+}
+
 .status__content__spoiler-link {
   display: inline-block;
   border-radius: 2px;
@@ -3009,8 +3031,7 @@ a.status-card {
   line-height: 24px;
 }
 
-.setting-toggle__label,
-.setting-meta__label {
+.setting-toggle__label {
   color: $darker-text-color;
   display: inline-block;
   margin-bottom: 14px;
@@ -3018,10 +3039,6 @@ a.status-card {
   vertical-align: middle;
 }
 
-.setting-meta__label {
-  float: right;
-}
-
 .empty-column-indicator,
 .error-column {
   color: $dark-text-color;
@@ -5122,7 +5139,7 @@ noscript {
       width: 100%;
       border: none;
       padding: 10px;
-      font-family: 'mastodon-font-monospace', monospace;
+      font-family: $font-monospace, monospace;
       background: $ui-base-color;
       color: $primary-text-color;
       font-size: 14px;
diff --git a/app/javascript/styles/mastodon/containers.scss b/app/javascript/styles/mastodon/containers.scss
index 47582f323..44fc1e538 100644
--- a/app/javascript/styles/mastodon/containers.scss
+++ b/app/javascript/styles/mastodon/containers.scss
@@ -37,7 +37,7 @@
       outline: 0;
       padding: 12px 16px;
       line-height: 32px;
-      font-family: 'mastodon-font-display', sans-serif;
+      font-family: $font-display, sans-serif;
       font-weight: 500;
       font-size: 14px;
     }
@@ -627,7 +627,7 @@
             font-size: 18px;
             margin-bottom: 5px;
             color: $primary-text-color;
-            font-family: 'mastodon-font-display', sans-serif;
+            font-family: $font-display, sans-serif;
           }
         }
 
diff --git a/app/javascript/styles/mastodon/dashboard.scss b/app/javascript/styles/mastodon/dashboard.scss
index 949ca733f..86cf6c61b 100644
--- a/app/javascript/styles/mastodon/dashboard.scss
+++ b/app/javascript/styles/mastodon/dashboard.scss
@@ -35,7 +35,7 @@
     font-weight: 500;
     font-size: 24px;
     color: $primary-text-color;
-    font-family: 'mastodon-font-display', sans-serif;
+    font-family: $font-display, sans-serif;
     margin-bottom: 20px;
   }
 
diff --git a/app/javascript/styles/mastodon/forms.scss b/app/javascript/styles/mastodon/forms.scss
index cbd3de94c..be2bf7cea 100644
--- a/app/javascript/styles/mastodon/forms.scss
+++ b/app/javascript/styles/mastodon/forms.scss
@@ -1,7 +1,7 @@
 $no-columns-breakpoint: 600px;
 
 code {
-  font-family: 'mastodon-font-monospace', monospace;
+  font-family: $font-monospace, monospace;
   font-weight: 400;
 }
 
@@ -474,7 +474,7 @@ code {
     width: 100%;
     border: none;
     padding: 10px;
-    font-family: 'mastodon-font-monospace', monospace;
+    font-family: $font-monospace, monospace;
     background: $ui-base-color;
     color: $primary-text-color;
     font-size: 14px;
@@ -718,7 +718,7 @@ code {
 .form_admin_settings_custom_css,
 .form_admin_settings_closed_registrations_message {
   textarea {
-    font-family: 'mastodon-font-monospace', monospace;
+    font-family: $font-monospace, monospace;
   }
 }
 
@@ -742,7 +742,7 @@ code {
     border: 0;
     padding: 10px;
     font-size: 14px;
-    font-family: 'mastodon-font-monospace', monospace;
+    font-family: $font-monospace, monospace;
   }
 
   button {
diff --git a/app/javascript/styles/mastodon/rtl.scss b/app/javascript/styles/mastodon/rtl.scss
index b8c0efad8..ffc875b88 100644
--- a/app/javascript/styles/mastodon/rtl.scss
+++ b/app/javascript/styles/mastodon/rtl.scss
@@ -46,8 +46,8 @@ body.rtl {
   .column-header__buttons {
     left: 0;
     right: auto;
-    margin-left: -15px;
-    margin-right: 0;
+    margin-left: 0;
+    margin-right: -15px;
   }
 
   .column-inline-form .icon-button {
@@ -78,10 +78,6 @@ body.rtl {
     margin-right: 8px;
   }
 
-  .setting-meta__label {
-    float: left;
-  }
-
   .status__avatar {
     left: auto;
     right: 10px;
@@ -145,6 +141,19 @@ body.rtl {
     margin-right: 6px;
   }
 
+  .status__action-bar {
+
+    &__counter {
+      margin-right: 0;
+      margin-left: 11px;
+
+      .status__action-bar-button {
+        margin-right: 0;
+        margin-left: 4px;
+      }
+    }
+  }
+
   .status__action-bar-button {
     float: right;
     margin-right: 0;
@@ -285,4 +294,13 @@ body.rtl {
       }
     }
   }
+
+  .public-layout {
+    .header {
+      .nav-button {
+        margin-left: 8px;
+        margin-right: 0;
+      }
+    }
+  }
 }
diff --git a/app/javascript/styles/mastodon/tables.scss b/app/javascript/styles/mastodon/tables.scss
index c2206cf55..adb75afe5 100644
--- a/app/javascript/styles/mastodon/tables.scss
+++ b/app/javascript/styles/mastodon/tables.scss
@@ -90,7 +90,7 @@
 }
 
 samp {
-  font-family: 'mastodon-font-monospace', monospace;
+  font-family: $font-monospace, monospace;
 }
 
 button.table-action-link {
diff --git a/app/javascript/styles/mastodon/variables.scss b/app/javascript/styles/mastodon/variables.scss
index 009f0a3c9..a82c44229 100644
--- a/app/javascript/styles/mastodon/variables.scss
+++ b/app/javascript/styles/mastodon/variables.scss
@@ -48,3 +48,7 @@ $media-modal-media-max-width: 100%;
 $media-modal-media-max-height: 80%;
 
 $no-gap-breakpoint: 415px;
+
+$font-sans-serif: 'mastodon-font-sans-serif' !default;
+$font-display: 'mastodon-font-display' !default;
+$font-monospace: 'mastodon-font-monospace' !default;
diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb
index f40e1fa3e..978289788 100644
--- a/app/lib/activitypub/activity/create.rb
+++ b/app/lib/activitypub/activity/create.rb
@@ -92,7 +92,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
     return if tag['href'].blank?
 
     account = account_from_uri(tag['href'])
-    account = FetchRemoteAccountService.new.call(tag['href'], id: false) if account.nil?
+    account = ::FetchRemoteAccountService.new.call(tag['href'], id: false) if account.nil?
     return if account.nil?
     account.mentions.create(status: status)
   end
diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb
index b59a9f1cd..b10e5dd24 100644
--- a/app/lib/feed_manager.rb
+++ b/app/lib/feed_manager.rb
@@ -40,6 +40,7 @@ class FeedManager
   end
 
   def push_to_list(list, status)
+    return false if status.reply? && status.in_reply_to_account_id != status.account_id
     return false unless add_to_feed(:list, list.id, status)
     trim(:list, list.id)
     PushUpdateWorker.perform_async(list.account_id, status.id, "timeline:list:#{list.id}") if push_update_required?("timeline:list:#{list.id}")
diff --git a/app/lib/user_settings_decorator.rb b/app/lib/user_settings_decorator.rb
index 4bedfd680..e5b168502 100644
--- a/app/lib/user_settings_decorator.rb
+++ b/app/lib/user_settings_decorator.rb
@@ -15,23 +15,24 @@ class UserSettingsDecorator
   private
 
   def process_update
-    user.settings['notification_emails']     = merged_notification_emails if change?('notification_emails')
-    user.settings['interactions']            = merged_interactions if change?('interactions')
-    user.settings['default_privacy']         = default_privacy_preference if change?('setting_default_privacy')
-    user.settings['default_sensitive']       = default_sensitive_preference if change?('setting_default_sensitive')
-    user.settings['default_language']        = default_language_preference if change?('setting_default_language')
-    user.settings['unfollow_modal']          = unfollow_modal_preference if change?('setting_unfollow_modal')
-    user.settings['boost_modal']             = boost_modal_preference if change?('setting_boost_modal')
-    user.settings['favourite_modal']         = favourite_modal_preference if change?('setting_favourite_modal')
-    user.settings['delete_modal']            = delete_modal_preference if change?('setting_delete_modal')
-    user.settings['auto_play_gif']           = auto_play_gif_preference if change?('setting_auto_play_gif')
-    user.settings['display_sensitive_media'] = display_sensitive_media_preference if change?('setting_display_sensitive_media')
-    user.settings['reduce_motion']           = reduce_motion_preference if change?('setting_reduce_motion')
-    user.settings['system_font_ui']          = system_font_ui_preference if change?('setting_system_font_ui')
-    user.settings['noindex']                 = noindex_preference if change?('setting_noindex')
-    user.settings['flavour']                 = flavour_preference if change?('setting_flavour')
-    user.settings['skin']                    = skin_preference if change?('setting_skin')
-    user.settings['hide_network']            = hide_network_preference if change?('setting_hide_network')
+    user.settings['notification_emails'] = merged_notification_emails if change?('notification_emails')
+    user.settings['interactions']        = merged_interactions if change?('interactions')
+    user.settings['default_privacy']     = default_privacy_preference if change?('setting_default_privacy')
+    user.settings['default_sensitive']   = default_sensitive_preference if change?('setting_default_sensitive')
+    user.settings['default_language']    = default_language_preference if change?('setting_default_language')
+    user.settings['unfollow_modal']      = unfollow_modal_preference if change?('setting_unfollow_modal')
+    user.settings['boost_modal']         = boost_modal_preference if change?('setting_boost_modal')
+    user.settings['favourite_modal']     = favourite_modal_preference if change?('setting_favourite_modal')
+    user.settings['delete_modal']        = delete_modal_preference if change?('setting_delete_modal')
+    user.settings['auto_play_gif']       = auto_play_gif_preference if change?('setting_auto_play_gif')
+    user.settings['display_media']       = display_media_preference if change?('setting_display_media')
+    user.settings['expand_spoilers']     = expand_spoilers_preference if change?('setting_expand_spoilers')
+    user.settings['reduce_motion']       = reduce_motion_preference if change?('setting_reduce_motion')
+    user.settings['system_font_ui']      = system_font_ui_preference if change?('setting_system_font_ui')
+    user.settings['noindex']             = noindex_preference if change?('setting_noindex')
+    user.settings['flavour']             = flavour_preference if change?('setting_flavour')
+    user.settings['skin']                = skin_preference if change?('setting_skin')
+    user.settings['hide_network']        = hide_network_preference if change?('setting_hide_network')
   end
 
   def merged_notification_emails
@@ -57,7 +58,7 @@ class UserSettingsDecorator
   def boost_modal_preference
     boolean_cast_setting 'setting_boost_modal'
   end
-  
+
   def favourite_modal_preference
     boolean_cast_setting 'setting_favourite_modal'
   end
@@ -74,8 +75,12 @@ class UserSettingsDecorator
     boolean_cast_setting 'setting_auto_play_gif'
   end
 
-  def display_sensitive_media_preference
-    boolean_cast_setting 'setting_display_sensitive_media'
+  def display_media_preference
+    settings['setting_display_media']
+  end
+
+  def expand_spoilers_preference
+    boolean_cast_setting 'setting_expand_spoilers'
   end
 
   def reduce_motion_preference
diff --git a/app/models/concerns/paginable.rb b/app/models/concerns/paginable.rb
index 66695677e..8863094f7 100644
--- a/app/models/concerns/paginable.rb
+++ b/app/models/concerns/paginable.rb
@@ -19,5 +19,13 @@ module Paginable
       query = query.where(arel_table[:id].gt(min_id)) if min_id.present?
       query
     }
+
+    scope :paginate_by_id, ->(limit, options = {}) {
+      if options[:min_id].present?
+        paginate_by_min_id(limit, options[:min_id]).reverse
+      else
+        paginate_by_max_id(limit, options[:max_id], options[:since_id])
+      end
+    }
   end
 end
diff --git a/app/models/feed.rb b/app/models/feed.rb
index d99f1ffb2..5bce88f25 100644
--- a/app/models/feed.rb
+++ b/app/models/feed.rb
@@ -6,16 +6,20 @@ class Feed
     @id   = id
   end
 
-  def get(limit, max_id = nil, since_id = nil)
-    from_redis(limit, max_id, since_id)
+  def get(limit, max_id = nil, since_id = nil, min_id = nil)
+    from_redis(limit, max_id, since_id, min_id)
   end
 
   protected
 
-  def from_redis(limit, max_id, since_id)
-    max_id     = '+inf' if max_id.blank?
-    since_id   = '-inf' if since_id.blank?
-    unhydrated = redis.zrevrangebyscore(key, "(#{max_id}", "(#{since_id}", limit: [0, limit], with_scores: true).map(&:first).map(&:to_i)
+  def from_redis(limit, max_id, since_id, min_id)
+    if min_id.blank?
+      max_id     = '+inf' if max_id.blank?
+      since_id   = '-inf' if since_id.blank?
+      unhydrated = redis.zrevrangebyscore(key, "(#{max_id}", "(#{since_id}", limit: [0, limit], with_scores: true).map(&:first).map(&:to_i)
+    else
+      unhydrated = redis.zrangebyscore(key, "(#{min_id}", '+inf', limit: [0, limit], with_scores: true).map(&:first).map(&:to_i)
+    end
 
     Status.where(id: unhydrated).cache_ids
   end
diff --git a/app/models/home_feed.rb b/app/models/home_feed.rb
index b943a34ce..ba7564983 100644
--- a/app/models/home_feed.rb
+++ b/app/models/home_feed.rb
@@ -7,9 +7,9 @@ class HomeFeed < Feed
     @account = account
   end
 
-  def get(limit, max_id = nil, since_id = nil)
+  def get(limit, max_id = nil, since_id = nil, min_id = nil)
     if redis.exists("account:#{@account.id}:regeneration")
-      from_database(limit, max_id, since_id)
+      from_database(limit, max_id, since_id, min_id)
     else
       super
     end
@@ -17,9 +17,9 @@ class HomeFeed < Feed
 
   private
 
-  def from_database(limit, max_id, since_id)
+  def from_database(limit, max_id, since_id, min_id)
     Status.as_home_timeline(@account)
-          .paginate_by_max_id(limit, max_id, since_id)
+          .paginate_by_id(limit, max_id: max_id, since_id: since_id, min_id: min_id)
           .reject { |status| FeedManager.instance.filter?(:home, status, @account.id) }
   end
 end
diff --git a/app/models/user.rb b/app/models/user.rb
index 6022a5eb0..b9e18eecd 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -95,8 +95,8 @@ class User < ApplicationRecord
   has_many :session_activations, dependent: :destroy
 
   delegate :auto_play_gif, :default_sensitive, :unfollow_modal, :boost_modal, :favourite_modal, :delete_modal,
-           :reduce_motion, :system_font_ui, :noindex, :flavour, :skin, :display_sensitive_media, :hide_network,
-           :default_language, to: :settings, prefix: :setting, allow_nil: false
+           :reduce_motion, :system_font_ui, :noindex, :flavour, :skin, :display_media, :hide_network,
+           :expand_spoilers, :default_language, to: :settings, prefix: :setting, allow_nil: false
 
   attr_reader :invite_code
 
@@ -316,6 +316,14 @@ class User < ApplicationRecord
     super
   end
 
+  def show_all_media?
+    setting_display_media == 'show_all'
+  end
+
+  def hide_all_media?
+    setting_display_media == 'hide_all'
+  end
+
   protected
 
   def send_devise_notification(notification, *args)
diff --git a/app/serializers/initial_state_serializer.rb b/app/serializers/initial_state_serializer.rb
index 0845d0210..ac08a3f1e 100644
--- a/app/serializers/initial_state_serializer.rb
+++ b/app/serializers/initial_state_serializer.rb
@@ -24,15 +24,16 @@ class InitialStateSerializer < ActiveModel::Serializer
     }
 
     if object.current_account
-      store[:me]                      = object.current_account.id.to_s
-      store[:unfollow_modal]          = object.current_account.user.setting_unfollow_modal
-      store[:boost_modal]             = object.current_account.user.setting_boost_modal
-      store[:favourite_modal]         = object.current_account.user.setting_favourite_modal
-      store[:delete_modal]            = object.current_account.user.setting_delete_modal
-      store[:auto_play_gif]           = object.current_account.user.setting_auto_play_gif
-      store[:display_sensitive_media] = object.current_account.user.setting_display_sensitive_media
-      store[:reduce_motion]           = object.current_account.user.setting_reduce_motion
-      store[:is_staff]                = object.current_account.user.staff?
+      store[:me]              = object.current_account.id.to_s
+      store[:unfollow_modal]  = object.current_account.user.setting_unfollow_modal
+      store[:boost_modal]     = object.current_account.user.setting_boost_modal
+      store[:favourite_modal] = object.current_account.user.setting_favourite_modal
+      store[:delete_modal]    = object.current_account.user.setting_delete_modal
+      store[:auto_play_gif]   = object.current_account.user.setting_auto_play_gif
+      store[:display_media]   = object.current_account.user.setting_display_media
+      store[:expand_spoilers] = object.current_account.user.setting_expand_spoilers
+      store[:reduce_motion]   = object.current_account.user.setting_reduce_motion
+      store[:is_staff]        = object.current_account.user.staff?
     end
 
     store
diff --git a/app/views/accounts/_header.html.haml b/app/views/accounts/_header.html.haml
index 3da270d27..9ceae007d 100644
--- a/app/views/accounts/_header.html.haml
+++ b/app/views/accounts/_header.html.haml
@@ -16,7 +16,7 @@
             = fa_icon('lock') if account.locked?
       .public-account-header__tabs__tabs
         .details-counters
-          .counter{ class: active_nav_class(short_account_url(account)) + active_nav_class(short_account_with_replies_url(account)) + active_nav_class(short_account_media_url(account)) }
+          .counter{ class: active_nav_class(short_account_url(account), short_account_with_replies_url(account), short_account_media_url(account)) }
             = link_to short_account_url(account), class: 'u-url u-uid', title: number_with_delimiter(account.statuses_count) do
               %span.counter-number= number_to_human account.statuses_count, strip_insignificant_zeros: true
               %span.counter-label= t('accounts.posts', count: account.statuses_count)
diff --git a/app/views/accounts/_moved.html.haml b/app/views/accounts/_moved.html.haml
index f99328dbd..7a777bfea 100644
--- a/app/views/accounts/_moved.html.haml
+++ b/app/views/accounts/_moved.html.haml
@@ -6,7 +6,7 @@
     = t('accounts.moved_html', name: content_tag(:bdi, content_tag(:strong, display_name(account, custom_emojify: true), class: :emojify)), new_profile_link: link_to(content_tag(:strong, safe_join(['@', content_tag(:span, moved_to_account.acct)])), TagManager.instance.url_for(moved_to_account), class: 'mention'))
 
   .moved-account-widget__card
-    = link_to TagManager.instance.url_for(moved_to_account), class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'noopener' do
+    = link_to TagManager.instance.url_for(moved_to_account), class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'me noopener' do
       .detailed-status__display-avatar
         .account__avatar-overlay
           .account__avatar-overlay-base{ style: "background-image: url('#{moved_to_account.avatar.url(:original)}')" }
diff --git a/app/views/admin/reports/_status.html.haml b/app/views/admin/reports/_status.html.haml
index 4d557b071..b3c145120 100644
--- a/app/views/admin/reports/_status.html.haml
+++ b/app/views/admin/reports/_status.html.haml
@@ -14,9 +14,9 @@
     - unless status.proper.media_attachments.empty?
       - if status.proper.media_attachments.first.video?
         - video = status.proper.media_attachments.first
-        = react_component :video, src: video.file.url(:original), preview: video.file.url(:small), sensitive: status.proper.sensitive? && !current_account&.user&.setting_display_sensitive_media, width: 610, height: 343, inline: true, alt: video.description
+        = react_component :video, src: video.file.url(:original), preview: video.file.url(:small), sensitive: !current_account&.user&.show_all_media? && status.proper.sensitive? || current_account&.user&.hide_all_media?, width: 610, height: 343, inline: true, alt: video.description
       - else
-        = react_component :media_gallery, height: 343, sensitive: status.proper.sensitive? && !current_account&.user&.setting_display_sensitive_media, 'autoPlayGif': current_account&.user&.setting_auto_play_gif, media: status.proper.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }
+        = react_component :media_gallery, height: 343, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, 'autoPlayGif': current_account&.user&.setting_auto_play_gif, media: status.proper.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }
 
     .detailed-status__meta
       = link_to TagManager.instance.url_for(status), class: 'detailed-status__datetime', target: stream_link_target, rel: 'noopener' do
diff --git a/app/views/settings/preferences/show.html.haml b/app/views/settings/preferences/show.html.haml
index bb267db8a..751a6e50b 100644
--- a/app/views/settings/preferences/show.html.haml
+++ b/app/views/settings/preferences/show.html.haml
@@ -44,7 +44,8 @@
 
   .fields-group
     = f.input :setting_auto_play_gif, as: :boolean, wrapper: :with_label
-    = f.input :setting_display_sensitive_media, as: :boolean, wrapper: :with_label
+    = f.input :setting_display_media, collection: ['default', 'show_all', 'hide_all'], wrapper: :with_label, include_blank: false, label_method: lambda { |item| safe_join([t("simple_form.labels.defaults.setting_display_media_#{item}"), content_tag(:span, t("simple_form.hints.defaults.setting_display_media_#{item}"), class: 'hint')]) }, required: false, as: :radio_buttons, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li'
+    = f.input :setting_expand_spoilers, as: :boolean, wrapper: :with_label
     = f.input :setting_reduce_motion, as: :boolean, wrapper: :with_label
     = f.input :setting_system_font_ui, as: :boolean, wrapper: :with_label
 
diff --git a/app/views/stream_entries/_detailed_status.html.haml b/app/views/stream_entries/_detailed_status.html.haml
index d0d9cc5fc..6cedfb337 100644
--- a/app/views/stream_entries/_detailed_status.html.haml
+++ b/app/views/stream_entries/_detailed_status.html.haml
@@ -16,17 +16,17 @@
 
   .status__content.emojify<
     - if status.spoiler_text?
-      %p{ style: 'margin-bottom: 0' }<
+      %p{ :style => ('margin-bottom: 0' unless current_account&.user&.setting_expand_spoilers) }<
         %span.p-summary> #{Formatter.instance.format_spoiler(status, autoplay: autoplay)}&nbsp;
         %a.status__content__spoiler-link{ href: '#' }= t('statuses.show_more')
-    .e-content{ lang: status.language, style: "display: #{status.spoiler_text? ? 'none' : 'block'}; direction: #{rtl_status?(status) ? 'rtl' : 'ltr'}" }= Formatter.instance.format(status, custom_emojify: true, autoplay: autoplay)
+    .e-content{ lang: status.language, style: "display: #{!current_account&.user&.setting_expand_spoilers && status.spoiler_text? ? 'none' : 'block'}; direction: #{rtl_status?(status) ? 'rtl' : 'ltr'}" }= Formatter.instance.format(status, custom_emojify: true, autoplay: autoplay)
 
   - if !status.media_attachments.empty?
     - if status.media_attachments.first.video?
       - video = status.media_attachments.first
-      = react_component :video, src: video.file.url(:original), preview: video.file.url(:small), sensitive: status.sensitive? && !current_account&.user&.setting_display_sensitive_media, width: 670, height: 380, detailed: true, inline: true, alt: video.description
+      = react_component :video, src: video.file.url(:original), preview: video.file.url(:small), sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, width: 670, height: 380, detailed: true, inline: true, alt: video.description
     - else
-      = react_component :media_gallery, height: 380, sensitive: status.sensitive? && !current_account&.user&.setting_display_sensitive_media, standalone: true, 'autoPlayGif': current_account&.user&.setting_auto_play_gif || autoplay, 'reduceMotion': current_account&.user&.setting_reduce_motion, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }
+      = react_component :media_gallery, height: 380, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, standalone: true, 'autoPlayGif': current_account&.user&.setting_auto_play_gif || autoplay, 'reduceMotion': current_account&.user&.setting_reduce_motion, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }
   - elsif status.preview_cards.first
     = react_component :card, 'maxDescription': 160, card: ActiveModelSerializers::SerializableResource.new(status.preview_cards.first, serializer: REST::PreviewCardSerializer).as_json
 
diff --git a/app/views/stream_entries/_simple_status.html.haml b/app/views/stream_entries/_simple_status.html.haml
index 4484a7e62..5d7e2ad82 100644
--- a/app/views/stream_entries/_simple_status.html.haml
+++ b/app/views/stream_entries/_simple_status.html.haml
@@ -19,18 +19,18 @@
           = fa_icon('lock') if status.account.locked?
   .status__content.emojify<
     - if status.spoiler_text?
-      %p{ style: 'margin-bottom: 0' }<
+      %p{ :style => ('margin-bottom: 0' unless current_account&.user&.setting_expand_spoilers) }<
         %span.p-summary> #{Formatter.instance.format_spoiler(status, autoplay: autoplay)}&nbsp;
         %a.status__content__spoiler-link{ href: '#' }= t('statuses.show_more')
-    .e-content{ lang: status.language, style: "display: #{status.spoiler_text? ? 'none' : 'block'}; direction: #{rtl_status?(status) ? 'rtl' : 'ltr'}" }<
+    .e-content{ lang: status.language, style: "display: #{!current_account&.user&.setting_expand_spoilers && status.spoiler_text? ? 'none' : 'block'}; direction: #{rtl_status?(status) ? 'rtl' : 'ltr'}" }<
       = Formatter.instance.format(status, custom_emojify: true, autoplay: autoplay)
 
   - unless status.media_attachments.empty?
     - if status.media_attachments.first.video?
       - video = status.media_attachments.first
-      = react_component :video, src: video.file.url(:original), preview: video.file.url(:small), sensitive: status.sensitive? && !current_account&.user&.setting_display_sensitive_media, width: 610, height: 343, inline: true, alt: video.description
+      = react_component :video, src: video.file.url(:original), preview: video.file.url(:small), sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, width: 610, height: 343, inline: true, alt: video.description
     - else
-      = react_component :media_gallery, height: 343, sensitive: status.sensitive? && !current_account&.user&.setting_display_sensitive_media, 'autoPlayGif': current_account&.user&.setting_auto_play_gif || autoplay, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }
+      = react_component :media_gallery, height: 343, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, 'autoPlayGif': current_account&.user&.setting_auto_play_gif || autoplay, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }
 
   .status__action-bar
     .status__action-bar__counter
diff --git a/config/boot.rb b/config/boot.rb
index 0a3cd4ebe..593f575e9 100644
--- a/config/boot.rb
+++ b/config/boot.rb
@@ -1,14 +1,14 @@
 ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
 
-require 'bundler/setup' # Set up gems listed in the Gemfile.
+require 'bundler/setup'  # Set up gems listed in the Gemfile.
 require 'bootsnap' # Speed up boot time by caching expensive operations.
 
 Bootsnap.setup(
   cache_dir:            'tmp/cache',
-  development_mode:     ENV['RAILS_ENV'] == 'development',
+  development_mode:     ENV.fetch('RAILS_ENV', 'development') == 'development',
   load_path_cache:      true,
   autoload_paths_cache: true,
-  disable_trace:        true,
+  disable_trace:        false,
   compile_cache_iseq:   false,
   compile_cache_yaml:   false
 )
diff --git a/config/initializers/statsd.rb b/config/initializers/statsd.rb
index 45702ac94..ce83fd9de 100644
--- a/config/initializers/statsd.rb
+++ b/config/initializers/statsd.rb
@@ -9,7 +9,7 @@ if ENV['STATSD_ADDR'].present?
   ::NSA.inform_statsd(statsd) do |informant|
     informant.collect(:action_controller, :web)
     informant.collect(:active_record, :db)
-    informant.collect(:cache, :cache)
+    informant.collect(:active_support_cache, :cache)
     informant.collect(:sidekiq, :sidekiq)
   end
 end
diff --git a/config/locales/ar.yml b/config/locales/ar.yml
index 94f0cbf8a..b684ff922 100644
--- a/config/locales/ar.yml
+++ b/config/locales/ar.yml
@@ -618,6 +618,7 @@ ar:
       mention: "%{name} أشار إليك في :"
       new_followers_summary:
         one: و لقد تحصّلت أيضا على متابِع جديد أثناء فترة غيابك! يا للروعة!
+        other: رائع، لقد قام بمتابعتك %{count} مُتابِعون جُدد أثناء فترة غيابك عن ماستدون !
       subject:
         one: "إشعار جديد واحد منذ آخر زيارة لك لـ \U0001F418"
         other: "%{count} إشعارات جديدة منذ آخر زيارة لك إلى \U0001F418"
diff --git a/config/locales/cy.yml b/config/locales/cy.yml
index 1cdba065b..f78ce26c5 100644
--- a/config/locales/cy.yml
+++ b/config/locales/cy.yml
@@ -1,7 +1,7 @@
 ---
 cy:
   about:
-    about_hashtag_html: Dyma dwtiau cyhoeddus wedi eu tagio gyda <strong>#%{hashtag}</strong>. Gallwch ryngweithio gyda nhw os oes gennych gyfrif yn unrhyw le yn y bydysawd.
+    about_hashtag_html: Dyma dŵtiau cyhoeddus wedi eu tagio gyda <strong>#%{hashtag}</strong>. Gallwch ryngweithio gyda nhw os oes gennych gyfrif yn unrhyw le yn y bydysawd.
     about_mastodon_html: Mae Mastodon yn rwydwaith cymdeithasol sy'n seiliedig ar brotocolau gwe a meddalwedd cod agored rhad ac am ddim. Yn debyg i e-bost mae'n ddatganoledig.
     about_this: Ynghylch
     administered_by: 'Gweinyddir gan:'
@@ -20,15 +20,19 @@ cy:
       humane_approach_title: Agwedd fwy dynol
       not_a_product_body: Nid yw Mastodon yn rhwydwaith fasnachol. Nid oes hysbysebion, cloddio data na gerddi caeedig. Nid oes awdurdod canolog.
       not_a_product_title: Rwyt yn berson, nid yn gynnyrch
-      real_conversation_title: Wedi ei adeiladu ar gyfer trafodaeth go iawn
+      real_conversation_body: Gyda'r modd i ddefnyddio hyd at 500 o nodau a chefnogaeth ar gyfer cynnwys gronynnol a rhybuddion cyfryngau, mae modd i chi fynegi'ch hun yn y ffordd yr hoffech chi.
+      real_conversation_title: Wedi ei adeiladu ar gyfer sgyrsiau go iawn
+      within_reach_body: Nifer o apiau ar gyfer iOS, Android, a nifer blatfformau eraill diolch i amgylchedd API hygyrch i ddatblygwyr sy'n caniatau i chi gadw mewn cysylltiad a'ch ffrindiau o unrhywle.
       within_reach_title: Bob tro o fewn gafael
     generic_description: Mae %{domain} yn un gweinydd yn y rhwydwaith
     hosted_on: Mastodon wedi ei weinyddu ar %{domain}
-    learn_more: Dysgu mwy
+    learn_more: Dysgwch fwy
+    other_instances: Rhestr achosion
     privacy_policy: Polisi preifatrwydd
     source_code: Cod ffynhonnell
     status_count_after:
       one: statws
+      other: statws
     status_count_before: Pwy ysgrifennodd
     terms: Telerau gwasanaeth
     user_count_after:
@@ -122,13 +126,14 @@ cy:
         most_recent: Mwyaf diweddaraf
         title: Trefn
       outbox_url: Allflwch URL
+      perform_full_suspension: Ataliwch yn llwyr
       profile_url: URL proffil
       promote: Hyrwyddo
       protocol: Protocol
       public: Cyhoeddus
-      push_subscription_expires: Tanysgrifiad PUSH yn dod i ben
+      push_subscription_expires: Tanysgrifiad PuSH yn dod i ben
       redownload: Adnewyddwch afatar
-      remove_avatar: Dilewch afatar
+      remove_avatar: Dilëwch afatar
       resend_confirmation:
         already_confirmed: Mae'r defnyddiwr hwn wedi ei gadarnhau yn barod
         send: Ailanfonwch e-bost cadarnhad
@@ -150,6 +155,7 @@ cy:
         report: adrodd
         targeted_reports: Adroddiadau am y cyfri hwn
       silence: Tawelu
+      statuses: ''
       subscribe: Tanysgrifio
       title: Cyfrifon
       unconfirmed_email: E-bost heb ei gadarnhau
@@ -168,6 +174,25 @@ cy:
         create_email_domain_block: Cosbrestrwyd parth e-bost %{target} gan %{name}
         demote_user: Diraddiodd %{name} y defnyddiwr %{target}
         destroy_domain_block: Dadflociodd %{name} y parth %{target}
+        destroy_status: Cafodd %{name} wared ar statws gan %{target}
+        disable_2fa_user: Diffoddodd %{name} ar ofyniad dau gam ar gyfer y defnyddiwr %{target}
+        disable_custom_emoji: Diffoddodd %{name} emoji %{target}
+        disable_user: Diffoddodd %{name} mewngofnodi ar gyfer y defnyddiwr %{target}
+        enable_custom_emoji: Galluogodd %{name} emoji %{target}
+        enable_user: Galluogodd %{name} mewngofnodi ar gyfer y defnyddiwr %{target}
+        memorialize_account: Newidodd %{name} gyfrif %{target} i dudalen goffau
+        promote_user: Dyrchafodd %{name} y defnyddiwr %{target}
+        remove_avatar_user: Cafodd %{name} wared ar afatar %{target}
+        reopen_report: Ailagorodd %{name} adroddiad %{target}
+        reset_password_user: Ailosododd %{name} gyfrinair y defnyddiwr %{target}
+        resolve_report: Datrusodd %{name} adroddiad %{target}
+        silence_account: Tawelodd %{name} gyfrif %{target}
+        suspend_account: Ataliodd %{name} gyfrif %{target}
+        unassigned_report: Dadbenododd %{name} adroddiad %{target}
+        unsilence_account: Terfynodd %{name} dawelu cyfrif %{target}
+        unsuspend_account: Terfynodd %{name} yr ataliad ar gyfrif %{target}
+        update_custom_emoji: Diweddarodd %{name} emoji %{target}
+        update_status: Diweddarodd %{name} statws gan %{taget}
       deleted_status: "(statws wedi ei ddileu)"
       title: Log archwilio
     custom_emojis:
@@ -188,20 +213,25 @@ cy:
       new:
         title: Ychwanegu emoji personol newydd
       overwrite: Trosysgrifio
-      shortcode_hint: O leiaf 2 lythyren, dim ond llythrennau alffaniwmerig a tanlinellau
+      shortcode_hint: O leiaf 2 nodyn, dim ond nodau alffaniwmerig a tanlinellau
       title: Emoji personol
       unlisted: Heb ei restru
       update_failed_msg: Ni allwyd diweddaru'r emoji hwnnw
       updated_msg: Llwyddwyd i ddiweddaru'r emoji!
       upload: Lanlwytho
     dashboard:
+      backlog: tasgau heb eu cwblhau
       config: Cyfluniad
+      feature_deletions: Dileadau cyfrif
       feature_invites: Dolenni gwahodd
       feature_registrations: Cofrestriadau
+      feature_relay: Relái ffederasiwn
       features: Nodweddion
+      hidden_service: Ffedarasiwn a gwasanaethau cudd
       open_reports: adroddiadau agored
       recent_users: Defnyddwyr diweddar
       search: Chwilio testun llawn
+      single_user_mode: Modd un defnyddiwr
       software: Meddalwedd
       space: Defnydd o ofod
       title: Dangosfwrdd
@@ -211,14 +241,21 @@ cy:
       week_users_active: gweithredol yr wythnos hon
       week_users_new: defnyddwyr yr wythnos hon
     domain_blocks:
+      add_new: Ychwanegu
+      created_msg: Mae'r bloc parth nawr yn cael ei brosesu
+      destroyed_msg: Mae'r bloc parth wedi ei ddadwneud
       domain: Parth
       new:
         create: Creu bloc
+        hint: Ni fydd y bloc parth yn atal cread cofnodion cyfrif yn y bas data, ond mi fydd yn gosod dulliau cymedroli penodol ôl-weithredol ac awtomatig ar y cyfrifau hynny.
         severity:
+          desc_html: Mae <strong>Tawelu</strong> yn gwneud twtiau y cyfrif yn anweledig i unrhyw un nad yw'n dilyn y cyfrif. Mae <strong>Atal</strong> yn cael gwared ar holl gynnwys, cyfryngau a data proffil y cyfrif. Defnyddiwch <strong>Dim</strong> os ydych chi ond am wrthod dogfennau cyfryngau.
           noop: Dim
           silence: Tawelwch
           suspend: Atal
+        title: Bloc parth newydd
       reject_media: Gwrthod dogfennau cyfryngau
+      reject_media_hint: Dileu dogfennau cyfryngau wedi eu cadw yn lleol ac yn gwrthod i lawrlwytho unrhyw rai yn y dyfodol. Amherthnasol i ataliadau
       severities:
         noop: Dim
         silence: Tawelwch
@@ -230,7 +267,10 @@ cy:
           other: "%{count} o gyfrifoedd yn y bas data wedi eu hefeithio"
         retroactive:
           silence: Dad-dawelu pob cyfri presennol o'r parth hwn
+          suspend: Dad-atal pob cyfrif o'r parth hwn sy'n bodoli
+        title: Dadwneud bloc parth ar gyfer %{domain}
         undo: Dadwneud
+      title: Blociau parth
       undo: Dadwneud
     email_domain_blocks:
       add_new: Ychwanegu
@@ -240,9 +280,10 @@ cy:
       domain: Parth
       new:
         create: Ychwanegu parth
+        title: Cofnod newydd yng nghosbrestr e-byst
       title: Cosbrestr e-bost
     instances:
-      account_count: Cyfrifoedd hysbys
+      account_count: Cyfrifon hysbys
       domain_name: Parth
       reset: Ailosod
       search: Chwilio
@@ -255,12 +296,20 @@ cy:
         title: Hidlo
       title: Gwahoddiadau
     relays:
+      add_new: Ychwanegau relái newydd
+      inbox_url: URL relái
+      pending: Aros am gymeradywaeth i'r relái
       save_and_enable: Cadw a galluogi
+      setup: Sefydlu cysylltiad relái
       status: Statws
+    report_notes:
+      created_msg: Llwyddwyd i greu nodyn adroddiad!
+      destroyed_msg: Llwyddwyd i ddileu nodyn adroddiad!
     reports:
       account:
         note: nodyn
         report: adroddiad
+      action_taken_by: Gwnathpwyd hyn gan
       are_you_sure: Ydych chi'n sicr?
       comment:
         none: Dim
@@ -272,6 +321,7 @@ cy:
         create_and_resolve: Datruswch a nodyn
         create_and_unresolve: Ailagorwch a nodyn
         delete: Dilëwch
+        placeholder: Disgrifiwch pa weithredoedd sydd wedi eu cymryd, neu unrhyw ddiweddariadau eraill...
       reopen: Ailagorwch adroddiad
       report: 'Adroddiad #%{id}'
       reported_by: Adroddwyd gan
@@ -288,6 +338,8 @@ cy:
         title: Cyhoeddwch ystatedgau agregau am weithgaredd defnyddwyr
       contact_information:
         email: E-bost busnes
+      hero:
+        title: Delwedd arwr
       registrations:
         deletion:
           desc_html: Caniatewch i unrhywun i ddileu eu cyfrif
@@ -296,12 +348,159 @@ cy:
           title: Caniatewch wahoddiadau gan
         open:
           desc_html: Caniatewch i unrhywun greu cyfrif
+          title: Agorwch cofrestru
+      show_staff_badge:
+        title: Dangos bathodyn staff
+      timeline_preview:
+        title: Rhagolwg o'r ffrwd
+      title: Gosodiadau'r wefan
+    statuses:
+      back_to_account: Yn ôl i dudalen y cyfrif
+      batch:
+        delete: Dileu
+        nsfw_off: Marcio fel nad yw'n sensitif
+        nsfw_on: Marcio'n sensitif
+      failed_to_execute: Methwyd a gweithredu
+      media:
+        title: Cyfryngau
+      no_media: Dim cyfryngau
+      no_status_selected: Ni newidwyd dim statws achos ni ddewiswyd dim un
+      with_media: A chyfryngau
+    subscriptions:
+      confirmed: Wedi'i gadarnhau
+      expires_in: Dod i ben ymhen
+      title: WebSub
+      topic: Pwnc
+    suspensions:
+      proceed: Parhau
+    title: Gweinyddiaeth
+  admin_mailer:
+    new_report:
+      body: Mae %{reporter} wedi cwyno am %{target}
+      body_remote: Mae rhywun o %{domain} wedi cwyno . am %{target}
+      subject: Cwyn newydd am %{instance} {#%{id}}
+  application_mailer:
+    notification_preferences: Newid gosodiadau e-bost
+    salutation: "%{name},"
+    view_profile: Gweld proffil
+    view_status: Gweld statws
+  applications:
+    created: Cais wedi ei greu'n llwyddiannus
+    destroyed: Cais wedi ei ddileu'n llwyddiannus
+    regenerate_token: Adfywio tocyn mynediad
+    token_regenerated: Adfywiwyd y tocyn mynediad yn llwyddiannus
+    warning: Byddwch yn ofalus a'r data hyn. Peidiwch a'i rannu byth!
+    your_token: Eich tocyn mynediad
   auth:
     change_password: Cyfrinair
+    confirm_email: Cadarnhau e-bost
+    delete_account: Dileu cyfrif
+    delete_account_html: Os hoffech chi ddileu eich cyfrif, mae modd <a href="%{path}">parhau yma</a>. Bydd gofyn i chi gadarnhau.
+    didnt_get_confirmation: Heb dderbyn cyfarwyddiadau cadarnhau?
+    forgot_password: Wedi anghofio'ch cyfrinair?
+    invalid_reset_password_token: Tocyn ailosod cyfrinair yn annilys neu wedi dod i ben. Gwnewch gais am un newydd os gwelwch yn dda.
+    login: Mewngofnodwch
+    logout: Allgofnodwch
+    migrate_account: Symud i gyfrif gwahanol
+    migrate_account_html: Os hoffech chi ailgyfeirio'r cyfrif hwn at un gwahanol, mae modd <a href="%{path}">ei ffurfweddu yma</a>.
+    or: neu
+    or_log_in_with: Neu logiwch mewn a
+    providers:
+      cas: CAS
+      saml: SAML
+    register: Cofrestrwch
+    register_elsewhere: Cofrestrwch ar weinydd gwahanol
+    resend_confirmation: Ailanfon cyfarwyddiadau cadarnhau
+    reset_password: Ailosodwch eich cyfrinair
+    security: Diogelwch
+    set_new_password: Gosodwch gyfrinair newydd
   authorize_follow:
+    already_following: Yr ydych yn dilyn y cyfrif hwn yn barod
+    error: Yn anffodus, roedd gwall tra'n edrych am y cyfrif anghysbell
     follow: Dilynwch
+    follow_request: 'Yr ydych wedi anfon cais dilyn at:'
+    following: 'Llwyddiant! Yr ydych yn awr yn dilyn:'
+    post_follow:
+      close: Neu, gallwch gau'r ffenest hon.
+      return: Dangoswch broffil y defnyddiwr
+      web: I'r wê
     title: Dilynwch %{acct}
+  datetime:
+    distance_in_words:
+      about_x_hours: "%{count}h"
+      about_x_months: "%{count}mo"
+      about_x_years: "%{count}y"
+      almost_x_years: "%{count}y"
+      half_a_minute: Newydd fod
+      less_than_x_minutes: "%{count}m"
+      less_than_x_seconds: Newydd fod
+      over_x_years: "%{count}y"
+      x_days: "%{count}d"
+      x_minutes: "%{count}m"
+      x_months: "%{count}mo"
+      x_seconds: "%{count}s"
+  deletes:
+    bad_password_msg: Go dda, hacwyr! Cyfrinair anghywir
+    confirm_password: Mewnbynnwch eich cyfrinair presennol i gadarnhau mai chi sydd yno
+    proceed: Dileu cyfrif
+    success_msg: Llwyddwyd i ddileu eich cyfrif
+  errors:
+    '403': Nid oes gennych ganiatad i weld y dudalen hon.
+    '404': Nid yw'r dudalen yr oeddech yn chwilio amdani'n bodoli.
+    '410': Nid yw'r dudalen yr oeddech yn chwilio amdani'n bodoli mwyach.
+    '422':
+      content: Methwyd i ddilysu diogelwch. A ydych chi'n blocio cwcîs?
+      title: Methwyd i ddilysu diogelwch
+    '500':
+      content: Mae'n ddrwg gennym ni, ond fe aeth rhywbeth o'i le ar ein rhan ni.
+      title: Nid yw'r dudalen hon yn gywir
+    noscript_html: I ddefnyddio ap gwê Mastodon, caniatewch JavaScript os gwlwch yn dda. Fel arall, gallwch drio un o'r <a href="https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md">apiau cynhenid</a> ar gyfer Mastodon ar eich platfform.
+  exports:
+    archive_takeout:
+      date: Dyddiad
+      download: Lawrlwythwch eich archif
+      size: Maint
+    blocks: Yr ydych yn blocio
+    csv: CSV
+    follows: Yr ydych yn dilyn
+    mutes: Yr ydych yn tawelu
+  filters:
+    contexts:
+      home: Ffrwd gartref
+      notifications: Hysbysiadau
+      public: Ffrwd gyhoeddus
+      thread: Sgyrsiau
+    edit:
+      title: Golygu hidlydd
+    index:
+      delete: Dileu
+      title: Hidlyddion
+    new:
+      title: Ychwanegu hidlydd newydd
+  followers:
+    domain: Parth
+    followers_count: Nifer y dilynwyr
+    lock_link: Cloi eich cyfri
+    unlocked_warning_title: Nid yw eich cyfrif wedi ei gloi
+  footer:
+    developers: Datblygwyr
+    more: Mwy…
+    resources: Adnoddau
+  generic:
+    changes_saved_msg: Llwyddwyd i gadw y newidiadau!
+    save_changes: Cadw newidiadau
+    validation_errors:
+      one: Mae rhywbeth o'i le o hyd! Edrychwch ar y gwall isod os gwelwch yn dda
+      other: Mae rhywbeth o'i le o hyd! Edrychwch ar y %{count} gwall isod os gwelwch yn dda
+  imports:
+    types:
+      blocking: Rhestr blocio
+      following: Rhestr dilyn
+      muting: Rhestr tawelu
+    upload: Uwchlwytho
+  in_memoriam_html: ''
   invites:
+    delete: Dadactifadu
     expires_in:
       '86400': 1 dydd
     max_uses_prompt: Dim terfyn
diff --git a/config/locales/devise.cy.yml b/config/locales/devise.cy.yml
index 51ab6a3c7..9cf8b96f0 100644
--- a/config/locales/devise.cy.yml
+++ b/config/locales/devise.cy.yml
@@ -34,19 +34,32 @@ cy:
         title: Newidwyd cyfrinair
       reconfirmation_instructions:
         explanation: Cadarnhewch y cyferiad newydd i newid eich e-bost.
+        extra: Os nad chi wnaeth y newid hwn, anwybyddwch yr e-bost hwn os gwelwch yn dda. Ni fydd y cyfeiriad e-bost ar gyfer y cyfrif Mastodon yn newid nes eich bod yn mynd at y ddolen uchod.
         subject: 'Mastodon: Cadarnhewch e-bost i %{instance}'
         title: Gwiriwch cyfeiriad e-bost
       reset_password_instructions:
         action: Newid cyfrinair
         explanation: Gofynnoch am gyfrinair newydd i'ch cyfrif.
+        extra: Os na wnaethoch gais am hyn, anwybyddwch yr e-bost hwn os gwelwch yn dda. Ni fydd eich cyfrinair yn newid nes i chi fynd at y ddolen uchod a chreu un newydd.
         subject: 'Mastodon: Ailosodwch cyfarwyddiadau cyfrinair'
         title: Ailosod cyfrinair
       unlock_instructions:
         subject: 'Mastodon: Cyfarwyddiadau datgloi'
     omniauth_callbacks:
       failure: Methu eich dilysu o %{kind} oherwydd "%{reason}".
+      success: Dilyswyd yn llwyddiannus o gyfrif %{kind}.
+    passwords:
+      no_token: Nid oes modd cael mynediad i'r dudalen hon heb ddod drwy e-bost ailosod cyfrinair. Os ydych yn dod o e-bost ailosod cyfrinair, gwnewch yn siŵr y defnyddioch chi'r URL a ddarparwyd yn ei gyfanrwydd.
+      send_instructions: Os yw eich cyfeiriad e-bost yn bresennol yn ein bas data, mi fyddwch yn derbyn dolen yn eich blwch e-bost ymhen cwpl o funudau. Os nad ydych yn derbyn yr e-bost hwn, edrychwch yn eich ffolder spam os gwelwch yn dda.
+      send_paranoid_instructions: Os yw eich cyfeiriad e-bost yn bresennol yn ein bas data, mi fyddwch yn derbyn dolen yn eich blwch e-bost ymhen cwpl o funudau. Os nad ydych yn derbyn yr e-bost hwn, edrychwch yn eich ffolder spam os gwelwch yn dda.
+      updated: Mae eich cyfrinair wedi ei newid yn llwyddiannus. Yr ydych wedi mewngofnodi.
+      updated_not_active: Mae eich cyfrinair wedi ei newid yn llwyddiannus.
     registrations:
+      destroyed: Hwyl fawr! Mae eich cyfrif wedi ei ganslo'n llwyddiannus. Gobeithiwn eich gweld eto'n fuan.
       signed_up: Croeso! Rydych wedi llwyddo i ymuno.
+      signed_up_but_inactive: Yr ydych wedi cofrestru'n llwyddiannus. Fodd bynnag, ni allwn eich mewngofnodi achos nid yw eich cyfrif wedi ei actifadu eto.
+      signed_up_but_locked: Yr ydych wedi cofrestru'n llwyddiannus. Fodd bynnag, ni allwn eich mewngofnodi achos fod eich cyfrif wedi ei gloi.
+      signed_up_but_unconfirmed: Mae neges gyda dolen cadarnhau wedi ei anfon i'ch cyfeiriad e-bost. Dilynwch y ddolen er mwyn actifadu eich cyfrif. Edrychwch yn eich ffolder sbam os na dderbynioch chi'r e-bost hwn os gwelwch yn dda.
       update_needs_confirmation: Rydych wedi diweddaru eich cyfrif yn llwyddiannus, ond mae angen i ni wirio eich cyfeiriad e-bost newydd. Edrychwch ar eich e-byst a dilynwch y ddolen gadarnhau er mwyn cadarnhau eich cyfeiriad e-bost newydd. Edrychwch ar eich ffolder sbam os na dderbynioch chi yr e-bost hwn.
       updated: Mae eich cyfrif wedi ei ddiweddaru yn llwyddiannus.
     sessions:
@@ -54,6 +67,8 @@ cy:
       signed_in: Mewngofnodwyd yn llwyddiannus.
       signed_out: Allgofnodwyd yn llwyddiannus.
     unlocks:
+      send_instructions: Mi fyddwch yn derbyn e-bost a cyfarwyddiadau ynghylch sut i ddatgloi eich cyfrif ymhen cwpl o funudau. Edrychwch yn eich ffolder sbam os na dderbynioch chi'r e-bost hwn os gwelwch yn dda.
+      send_paranoid_instructions: Os yw eich cyfrif yn bodoli, mi fyddwch yn derbyn e-bost a cyfarwyddiadau o sut i ddatgloi eich cyfrif ymhen cwpl o funudau. Edrychwch yn eich ffolder sbam os na dderbynioch chi'r e-bost hwn os gwelwch yn dda.
       unlocked: Mae eich cyfrif wedi ei ddatgloi'n llwyddiannus. Mewngofnodwch i barhau.
   errors:
     messages:
@@ -62,3 +77,6 @@ cy:
       expired: wedi dod i ben, gwnewch gais am un newydd os gwelwch yn dda
       not_found: heb ei ganfod
       not_locked: heb ei gloi
+      not_saved:
+        one: 'Gwaharddwyd yr %{resource} rhag cael ei arbed oherwydd 1 gwall:'
+        other: 'Gwaharddwyd yr %{resource} rhag cael ei arbed oherwydd %{count} gwall:'
diff --git a/config/locales/doorkeeper.cy.yml b/config/locales/doorkeeper.cy.yml
index 2c0e5d243..050af3a0a 100644
--- a/config/locales/doorkeeper.cy.yml
+++ b/config/locales/doorkeeper.cy.yml
@@ -4,7 +4,18 @@ cy:
     attributes:
       doorkeeper/application:
         name: Enw rhaglen
+        redirect_uri: Ailgyfeirio URI
         scopes: Cwmpasau
+        website: Gwefan cais
+    errors:
+      models:
+        doorkeeper/application:
+          attributes:
+            redirect_uri:
+              fragment_present: ni all gynnwys dernyn.
+              invalid_uri: rhaid iddo fod yn URI cyfredol.
+              relative_uri: rhaid iddo fod yn URI absoliwt.
+              secured_uri: rhaid iddo fod yn URI HTTPS/SSL.
   doorkeeper:
     applications:
       buttons:
@@ -19,6 +30,9 @@ cy:
         title: Golygwch rhaglen
       form:
         error: Wps! Gwiriwch eich ffurflen am gamgymeriadau posib
+      help:
+        native_redirect_uri: Defnyddiwch %{native_redirect_uri} ar gyfer profion lleol
+        redirect_uri: Defnyddiwch un llinell i bob URI
       index:
         application: Rhaglen
         delete: Dileu
@@ -30,11 +44,15 @@ cy:
       new:
         title: Rhaglen newydd
       show:
+        actions: Gweithredoedd
+        application_id: Allwedd cleient
         scopes: Cwmpasau
+        secret: Cyfrinach Cleient
         title: 'Rhaglen: %{name}'
     authorizations:
       buttons:
         authorize: Awdurdodi
+        deny: Gwrthod
       error:
         title: Mae rhywbeth wedi mynd o'i le
       new:
@@ -43,6 +61,8 @@ cy:
       show:
         title: Copiwch y côd awdurdodi a gludiwch i'r rhaglen
     authorized_applications:
+      buttons:
+        revoke: Diddymu
       confirmations:
         revoke: Ydych chi'n sicr?
       index:
@@ -53,6 +73,8 @@ cy:
     errors:
       messages:
         access_denied: Mae perchennog yr adnodd neu'r gweinydd awdurdodi wedi atal y cais.
+        invalid_redirect_uri: Nid yw'r uri ailgyfeirio cynnwysiedig yn gyfredol.
+        invalid_request: Nid yw'r cais yn cynnwys paramedr angenrheidiol, yn cynnwys paramader paramedr nad yw'n cael ei gefnogi, neu wedi ei gamffurfio mewn rhyw fodd arall.
     flash:
       applications:
         create:
@@ -72,11 +94,14 @@ cy:
       application:
         title: Mae awdurdodiad OAuth yn ofynnol
     scopes:
+      follow: addaswch berthnasau cyfrif
       push: derbyniwch eich hysbysiadau PUSH
       read: darllenwch holl ddata eich cyfrif
       read:accounts: gwelwch wybodaeth y cyfrif
+      read:blocks: gwlewch eich blociau
       read:favourites: gwelwch eich ffefrynnau
       read:filters: gwelwch eich hidlwyr
+      read:follows: gwelwch eich dilynwyr
       read:lists: gwelwch eich rhestrau
       read:notifications: gwelwch eich hysbysiadau
       read:reports: gwelwch eich adroddiadau
@@ -88,4 +113,5 @@ cy:
       write:follows: dilynwch bobl
       write:lists: crëwch restrau
       write:media: uwchlwythwch ffeiliau cyfryngau
+      write:mutes: tawelwch bobl a sgyrsiau
       write:notifications: cliriwch eich hysbysiadau
diff --git a/config/locales/es.yml b/config/locales/es.yml
index 4501dc28d..8072f526f 100644
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -41,7 +41,7 @@ es:
     user_count_before: Tenemos
     what_is_mastodon: "¿Qué es Mastodon?"
   accounts:
-    choices_html: 'Elecciones de %{nombre}:'
+    choices_html: 'Elecciones de %{name}:'
     follow: Seguir
     followers:
       one: Seguidor
diff --git a/config/locales/it.yml b/config/locales/it.yml
index 8222cedbb..0b8c01741 100644
--- a/config/locales/it.yml
+++ b/config/locales/it.yml
@@ -415,7 +415,7 @@ it:
     didnt_get_confirmation: Non hai ricevuto le istruzioni di conferma?
     forgot_password: Hai dimenticato la tua password?
     login: Entra
-    logout: Sloggati
+    logout: Esci da Mastodon
     migrate_account: Sposta ad un account differente
     migrate_account_html: Se vuoi che questo account sia reindirizzato a uno diverso, puoi <a href="%{path}">configurarlo qui</a>.
     or: o
@@ -464,6 +464,9 @@ it:
     '422':
       content: Verifica di sicurezza non riuscita. Stai bloccando i cookies?
       title: Verifica di sicurezza non riuscita
+    '500':
+      content: Siamo spiacenti, ma qualcosa non ha funzionato dal nostro lato.
+      title: Questa pagina non è corretta
     noscript_html: Per usare l'interfaccia web di Mastodon dovi abilitare JavaScript. In alternativa puoi provare una delle <a href="https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md">app native</a> per Mastodon per la tua piattaforma.
   exports:
     archive_takeout:
@@ -484,6 +487,10 @@ it:
       notifications: Notifiche
       public: Timeline pubbliche
       thread: Conversazioni
+    edit:
+      title: Modifica filtro
+    errors:
+      invalid_context: Contesto mancante o non valido
     index:
       delete: Cancella
       title: Filtri
@@ -608,6 +615,7 @@ it:
   remote_follow:
     acct: Inserisci il tuo username@dominio da cui vuoi seguire questo utente
     missing_resource: Impossibile trovare l'URL di reindirizzamento richiesto per il tuo account
+    no_account_html: Non hai un account? Puoi <a href='%{sign_up_path}' target='_blank'>iscriverti qui</a>
     proceed: Conferma
     prompt: 'Stai per seguire:'
   remote_unfollow:
@@ -619,6 +627,7 @@ it:
     browsers:
       blackberry: Blackberry
       chrome: Chrome
+      firefox: Firefox
       generic: Browser sconosciuto
     current_session: Sessione corrente
     description: "%{browser} su %{platform}"
diff --git a/config/locales/pl.yml b/config/locales/pl.yml
index 9afc666d1..c246dc032 100644
--- a/config/locales/pl.yml
+++ b/config/locales/pl.yml
@@ -54,7 +54,6 @@ pl:
       other: Śledzących
     following: Śledzonych
     joined: Dołączył(a) %{date}
-    link_verified_on: Własność tego odnośnika została potwierdzona %{date}
     media: Zawartość multimedialna
     moved_html: "%{name} korzysta teraz z konta %{new_profile_link}:"
     network_hidden: Ta informacja nie jest dostępna
@@ -129,7 +128,6 @@ pl:
       moderation_notes: Notatki moderacyjne
       most_recent_activity: Najnowsza aktywność
       most_recent_ip: Ostatnie IP
-      no_limits_imposed: Nie nałożono ograniczeń
       not_subscribed: Nie zasubskrybowano
       order:
         alphabetic: Alfabetycznie
@@ -165,10 +163,8 @@ pl:
         report: zgłoszeń
         targeted_reports: Zgłoszenia dotyczące tego użytkownika
       silence: Wycisz
-      silenced: Wyciszono
       statuses: Wpisy
       subscribe: Subskrybuj
-      suspended: Wywieszono
       title: Konta
       unconfirmed_email: Niepotwierdzony adres e-mail
       undo_silenced: Cofnij wyciszenie
@@ -313,13 +309,8 @@ pl:
       title: Zaproszenia
     relays:
       add_new: Dodaj nowy
-      delete: Usuń
       description_html: "<strong>Przekaźnik federacji</strong> jest pośredniczącym serwerem wymieniającym duże ilości publicznych wpisów pomiędzy serwerami które subskrybują je i publikują na nich. <strong>Pomaga to małym i średnim instancją poznawać nową zawartość z Fediwersum</strong>, co w innym przypadku wymagałoby od użytkowników ręcznego śledzenia osób z innych serwerów."
-      disable: Dezaktuwuj
-      disabled: Nieaktywny
-      enable: Aktywuj
       enable_hint: Jeżeli włączone, Twój serwer zasubskrybuje wszystkie publiczne wpisy z tego przekaźnika i zacznie wysyłać tam publiczne wpisy z tego serwera.
-      enabled: Aktywny
       inbox_url: Adres przekaźnika
       pending: Oczekiwanie na przyjęcie przez przekaźnik
       save_and_enable: Zapisz i aktywuj
@@ -470,7 +461,7 @@ pl:
     warning: Przechowuj te dane ostrożnie. Nie udostępniaj ich nikomu!
     your_token: Twój token dostępu
   auth:
-    agreement_html: Klikając „Rejestracja”, oświadczasz, że zapoznałeś(-aś) się z <a href="%{rules_path}">informacjami o instancji</a> i <a href="%{terms_path}">zasadami korzystania z usługi</a>.
+    agreement_html: Rejestrując się, oświadczasz, że zapoznałeś(-aś) się z <a href="%{rules_path}">informacjami o instancji</a> i <a href="%{terms_path}">zasadami korzystania z usługi</a>.
     change_password: Hasło
     confirm_email: Potwierdź adres e-mail
     delete_account: Usunięcie konta
@@ -941,6 +932,3 @@ pl:
     otp_lost_help_html: Jeżeli utracisz dostęp do obu, możesz skontaktować się z %{email}
     seamless_external_login: Zalogowano z użyciem zewnętrznej usługi, więc ustawienia hasła i adresu e-mail nie są dostępne.
     signed_in_as: 'Zalogowany jako:'
-  verification:
-    explanation_html: 'Możesz <strong>zweryfikować siebie jako właściciela odnośników w metadanych</strong>. Aby to zrobić, strona musi zawierać odnośnik do Twojego profilu na Mastodonie. Odnośnik <strong>musi</strong> zawierać atrybut <code>rel="me"</code>. Treść odnośnika nie ma znaczenia. Przykład:'
-    verification: Weryfikacja
diff --git a/config/locales/simple_form.ar.yml b/config/locales/simple_form.ar.yml
index 3e0c671cb..783e545e1 100644
--- a/config/locales/simple_form.ar.yml
+++ b/config/locales/simple_form.ar.yml
@@ -64,7 +64,6 @@ ar:
         setting_default_privacy: خصوصية المنشور
         setting_default_sensitive: إعتبر الوسائط دائما كمحتوى حساس
         setting_delete_modal: إظهار مربع حوار للتأكيد قبل حذف أي تبويق
-        setting_display_sensitive_media: دائمًا إظهار الوسائط الحساسة
         setting_hide_network: إخفِ شبكتك
         setting_noindex: عدم السماح لمحركات البحث بفهرسة ملفك الشخصي
         setting_reduce_motion: تخفيض عدد الصور في الوسائط المتحركة
diff --git a/config/locales/simple_form.ca.yml b/config/locales/simple_form.ca.yml
index d45b84971..53cf6db8e 100644
--- a/config/locales/simple_form.ca.yml
+++ b/config/locales/simple_form.ca.yml
@@ -65,7 +65,6 @@ ca:
         setting_default_privacy: Privacitat de les publicacions
         setting_default_sensitive: Marca sempre els elements multimèdia com a sensibles
         setting_delete_modal: Mostra la finestra de confirmació abans de suprimir un toot
-        setting_display_sensitive_media: Mostra sempre els elements multimèdia marcats com a sensibles
         setting_hide_network: Amaga la teva xarxa
         setting_noindex: Desactivació de la indexació del motor de cerca
         setting_reduce_motion: Redueix el moviment en animacions
diff --git a/config/locales/simple_form.co.yml b/config/locales/simple_form.co.yml
index ad4258dab..6f1630e6a 100644
--- a/config/locales/simple_form.co.yml
+++ b/config/locales/simple_form.co.yml
@@ -69,7 +69,6 @@ co:
         setting_default_privacy: Cunfidenzialità di i statuti
         setting_default_sensitive: Sempre cunsiderà media cum’è sensibili
         setting_delete_modal: Mustrà une cunfirmazione per toglie un statutu
-        setting_display_sensitive_media: Sempre mustrà media marcati cum’è sensibili
         setting_hide_network: Piattà a vostra rete
         setting_noindex: Dumandà à i motori di ricerca internet d’un pudè micca esse truvatu·a cusì
         setting_reduce_motion: Fà chì l’animazione vanu più pianu
diff --git a/config/locales/simple_form.cs.yml b/config/locales/simple_form.cs.yml
index 6625e2638..dbff52644 100644
--- a/config/locales/simple_form.cs.yml
+++ b/config/locales/simple_form.cs.yml
@@ -69,7 +69,6 @@ cs:
         setting_default_privacy: Soukromí příspěvků
         setting_default_sensitive: Vždy označovat média jako citlivá
         setting_delete_modal: Zobrazovat před smazáním tootu potvrzovací okno
-        setting_display_sensitive_media: Vždy zobrazovat média označená jako citlivá
         setting_hide_network: Skrýt svou síť
         setting_noindex: Neindexovat svůj profil vyhledávači
         setting_reduce_motion: Redukovat pohyb v animacích
diff --git a/config/locales/simple_form.cy.yml b/config/locales/simple_form.cy.yml
index bc8f7e0e9..5a301f775 100644
--- a/config/locales/simple_form.cy.yml
+++ b/config/locales/simple_form.cy.yml
@@ -1,21 +1,75 @@
 ---
 cy:
   simple_form:
+    hints:
+      defaults:
+        autofollow: Bydd pobl sy'n cofrestru drwy'r gwahoddiad yn eich dilyn yn awtomatig
+        avatar: PNG, GIF neu JPG. %{size} ar y mwyaf. Ceith ei israddio i %{dimensions}px
+        bot: Mae'r cyfrif hwn yn perfformio gweithredoedd awtomataidd yn bennaf ac mae'n bosib nad yw'n cael ei fonitro
+        context: Un neu fwy cyd-destun lle dylai'r hidlydd weithio
+        digest: Dim ond yn cael eu hanfon ar ôl cyfnod hir o anweithgarwch ac ond os ydych wedi derbyn unrhyw negeseuon personol yn eich absenoldeb
+        display_name:
+          one: <span class="name-counter">1</span> nodyn ar ôl
+          other: <span class="name-counter">%{count}</span> nodyn ar ôl
+        fields: Mae modd i chi arddangos hyd at 4 eitem fel tabl ar eich proffil
+        header: PNG, GIF neu JPG. %{size} ar y mwyaf. Ceith ei israddio i %{dimensions}px
+        inbox_url: Copïwch yr URL o dudalen flaen y relái yr ydych am ei ddefnyddio
+        irreversible: Bydd tŵtiau wedi eu hidlo yn diflannu am byth, hyd yn oed os ceith yr hidlydd ei ddileu'n hwyrach
+        locale: Iaith y rhyngwyneb, e-byst a hysbysiadau push
+        locked: Ei wneud yn ofynnol arnoch chi i ganiatau dilynwyr a llaw
+        note:
+          one: <span class="note-counter">1</span> cymeriad ar ôl
+          other: <span class="note-counter">%{count}</span> o gymeriadau ar ôl
+        scopes: Pa APIau y bydd gan y rhaglen ganiatad i gael mynediad iddynt. Os dewiswch maes lefel uchaf, yna nid oes angen dewis rhai unigol.
+        setting_default_language: Mae modd adnabod iaith eich tŵtiau yn awtomatig, ond nid yw bob tro'n gywir
+        setting_hide_network: Ni fydd pwy yr ydych yn ei ddilyn a phwy sy'n eich dilyn chi yn cael ei ddangos ar eich proffil
+        setting_noindex: Mae hyn yn effeithio ar eich proffil cyhoeddus a'ch tudalennau statws
+        setting_theme: Mae hyn yn effeithio ar sut olwg sydd ar Matododn pan yr ydych wedi mewngofnodi o unrhyw ddyfais.
+        whole_word: Os yw'r allweddair neu'r ymadrodd yn alffaniwmerig yn unig, mi fydd ond yn cael ei osod os yw'n cyfateb a'r gair cyfan
+      imports:
+        data: Allforiwyd dogfen CSV o INSTANCE Mastodon arall
+      sessions:
+        otp: 'Mewnbynnwch y côd dau gam a gynhyrchwyd gan eich ap ffôn neu defnyddiwch un o''ch codau adfer:'
+      user:
+        chosen_languages: Wedi ei ddethol, dim ond tŵtiau mewn ieithoedd dewisiedig bydd yn cael eu harddangos mewn ffrydiau cyhoeddus
     labels:
+      account:
+        fields:
+          name: Label
+          value: Cynnwys
       defaults:
+        autofollow: Gwahoddwch i ddilyn eich cyfrif
+        avatar: Afatar
+        bot: Cyfrif bot yw hwn
+        chosen_languages: Hidlwch ieithoedd
+        confirm_new_password: Cadarnhewch gyfrinair newydd
         confirm_password: Cadarnhau cyfrinair
+        context: Hidlwch cyd-destunau
+        current_password: Cyfrinair presennol
+        data: Data
+        display_name: Enw arddangos
         email: Cyfeiriad e-bost
+        expires_in: Yn dod i ben ar ôl
+        fields: Metadata proffil
         header: Pennyn
+        inbox_url: URL y mewnflwch relái
+        irreversible: Gollwng yn hytrach na chuddio
         locale: Iaith y rhyngwyneb
+        locked: Cloi cyfrif
         max_uses: Uchafswm y nifer o ddefnyddiau
         new_password: Cyfrinair newydd
+        otp_attempt: Côd dau gam
         password: Cyfrinair
         phrase: Allweddair neu ymadrodd
         setting_default_language: Cyhoeddi iaith
+        setting_default_privacy: Cyfrinachedd cyhoeddi
+        setting_default_sensitive: Marciwch cyfryngau fel ei fod yn sensitif bob tro
+        setting_delete_modal: Dangoswch ddeialog cadarnhau cyn dileu tŵt
         setting_hide_network: Cuddiwch eich rhwydwaith
         setting_reduce_motion: ''
         setting_system_font_ui: Defnyddiwch ffont rhagosodedig y system
         setting_theme: Thema'r wefan
+        setting_unfollow_modal: Dangoswch ddeialog cadarnhau cyn dad-ddilyn rhywun
         severity: Difrifoldeb
         type: Modd mewnforio
         username: Enw defnyddiwr
@@ -26,10 +80,13 @@ cy:
         must_be_following: Blociwch hysbysiadau o bobl nad ydych yn eu dilyn
         must_be_following_dm: Blociwch negeseuon uniongyrchol o bobl nad ydych yn eu dilyn
       notification_emails:
+        digest: Anfonwch e-byst crynhoi
         favourite: Anfonwch e-bost pan mae rhywun yn ffefrynnu eich statws
         follow: Anfonwch e-bost pan mae rhywun yn eich dilyn chi
         follow_request: Anfonwch e-bost pan mae rhywun yn gofyn i chi i'w dilyn
         mention: Anfonwch e-bost pan mae rhywun yn eich crybwyll
+        reblog: Anfonwch e-bost pan mae rhywun yn bŵstio eich statws
+        report: Anfonwch e-bost pan y cyflwynir adroddiad newydd
     'no': Na
     required:
       mark: "*"
diff --git a/config/locales/simple_form.da.yml b/config/locales/simple_form.da.yml
index dfa440aae..7550122fc 100644
--- a/config/locales/simple_form.da.yml
+++ b/config/locales/simple_form.da.yml
@@ -69,7 +69,6 @@ da:
         setting_default_privacy: Privatliv
         setting_default_sensitive: Marker altid medier som værende følsomt
         setting_delete_modal: Vis bekræftelses dialog før du sletter et trut
-        setting_display_sensitive_media: Vis altid multimedier markeret som værende følsomt
         setting_hide_network: Skjul dit netværk
         setting_noindex: Frameld dig søgemaskiners indeksering
         setting_reduce_motion: Reducer animationers bevægelse
diff --git a/config/locales/simple_form.de.yml b/config/locales/simple_form.de.yml
index 69e707c4c..e13eece79 100644
--- a/config/locales/simple_form.de.yml
+++ b/config/locales/simple_form.de.yml
@@ -69,7 +69,6 @@ de:
         setting_default_privacy: Beitragssichtbarkeit
         setting_default_sensitive: Medien immer als heikel markieren
         setting_delete_modal: Bestätigungsdialog anzeigen, bevor ein Beitrag gelöscht wird
-        setting_display_sensitive_media: Medien, die als heikel markiert sind, immer anzeigen
         setting_hide_network: Blende dein Netzwerk aus
         setting_noindex: Suchmaschinen-Indexierung verhindern
         setting_reduce_motion: Bewegung in Animationen verringern
diff --git a/config/locales/simple_form.el.yml b/config/locales/simple_form.el.yml
index 95869c786..96a7547e4 100644
--- a/config/locales/simple_form.el.yml
+++ b/config/locales/simple_form.el.yml
@@ -69,7 +69,6 @@ el:
         setting_default_privacy: Ιδιωτικότητα δημοσιεύσεων
         setting_default_sensitive: Σημείωνε πάντα τα πολυμέσα ως ευαίσθητου περιεχομένου
         setting_delete_modal: Εμφάνιση ερώτησης επιβεβαίωσης πριν διαγράψεις ένα τουτ
-        setting_display_sensitive_media: Εμφάνιση πάντα των πολυμέσων σημειωμένων ως ευαίσθητων
         setting_hide_network: Κρύψε τις διασυνδέσεις σου
         setting_noindex: Επέλεξε να μην συμμετέχεις στα αποτελέσματα μηχανών αναζήτησης
         setting_reduce_motion: Μείωση κίνησης κινουμένων στοιχείων
diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml
index 3ef992ef0..b25ff26f4 100644
--- a/config/locales/simple_form.en.yml
+++ b/config/locales/simple_form.en.yml
@@ -25,6 +25,9 @@ en:
         phrase: Will be matched regardless of casing in text or content warning of a toot
         scopes: Which APIs the application will be allowed to access. If you select a top-level scope, you don't need to select individual ones.
         setting_default_language: The language of your toots can be detected automatically, but it's not always accurate
+        setting_display_media_default: Hide media marked as sensitive
+        setting_display_media_hide_all: Always hide all media
+        setting_display_media_show_all: Always show media marked as sensitive
         setting_hide_network: Who you follow and who follows you will not be shown on your profile
         setting_noindex: Affects your public profile and status pages
         setting_skin: Reskins the selected Mastodon flavour
@@ -72,7 +75,11 @@ en:
         setting_default_privacy: Post privacy
         setting_default_sensitive: Always mark media as sensitive
         setting_delete_modal: Show confirmation dialog before deleting a toot
-        setting_display_sensitive_media: Always show media marked as sensitive
+        setting_display_media: Media display
+        setting_display_media_default: Default
+        setting_display_media_hide_all: Hide all
+        setting_display_media_show_all: Show all
+        setting_expand_spoilers: Always expand toots marked with content warnings
         setting_favourite_modal: Show confirmation dialog before favouriting (applies to Glitch flavour only)
         setting_hide_network: Hide your network
         setting_noindex: Opt-out of search engine indexing
diff --git a/config/locales/simple_form.eo.yml b/config/locales/simple_form.eo.yml
index 9b6e7cd9e..36f26035f 100644
--- a/config/locales/simple_form.eo.yml
+++ b/config/locales/simple_form.eo.yml
@@ -68,7 +68,6 @@ eo:
         setting_default_privacy: Mesaĝa videbleco
         setting_default_sensitive: Ĉiam marki aŭdovidaĵojn tiklaj
         setting_delete_modal: Montri fenestron por konfirmi antaŭ ol forigi mesaĝon
-        setting_display_sensitive_media: Ĉiam montri aŭdovidaĵojn markitajn tiklaj
         setting_hide_network: Kaŝi viajn sekvantojn kaj sekvatojn
         setting_noindex: Ellistiĝi de retserĉila indeksado
         setting_reduce_motion: Malrapidigi animaciojn
diff --git a/config/locales/simple_form.es.yml b/config/locales/simple_form.es.yml
index 0a39e01b8..8c528144e 100644
--- a/config/locales/simple_form.es.yml
+++ b/config/locales/simple_form.es.yml
@@ -69,7 +69,6 @@ es:
         setting_default_privacy: Privacidad de publicaciones
         setting_default_sensitive: Marcar siempre imágenes como sensibles
         setting_delete_modal: Mostrar diálogo de confirmación antes de borrar un toot
-        setting_display_sensitive_media: Mostrar siempre material marcado como sensible
         setting_hide_network: Ocultar tu red
         setting_noindex: Excluirse del indexado de motores de búsqueda
         setting_reduce_motion: Reducir el movimiento de las animaciones
diff --git a/config/locales/simple_form.eu.yml b/config/locales/simple_form.eu.yml
index 1e3b2d4f0..7fa8319ae 100644
--- a/config/locales/simple_form.eu.yml
+++ b/config/locales/simple_form.eu.yml
@@ -69,7 +69,6 @@ eu:
         setting_default_privacy: Mezuen pribatutasuna
         setting_default_sensitive: Beti markatu edukiak hunkigarri gisa
         setting_delete_modal: Erakutsi baieztapen elkarrizketa-koadroa toot bat ezabatu aurretik
-        setting_display_sensitive_media: Beti erakutsi hunkigarri gisa markatutako edukia
         setting_hide_network: Ezkutatu zure sarea
         setting_noindex: Atera bilaketa motorraren indexaziotik
         setting_reduce_motion: Murriztu animazioen mugimenduak
diff --git a/config/locales/simple_form.fa.yml b/config/locales/simple_form.fa.yml
index 38f95e1b7..418b308b1 100644
--- a/config/locales/simple_form.fa.yml
+++ b/config/locales/simple_form.fa.yml
@@ -69,7 +69,6 @@ fa:
         setting_default_privacy: حریم خصوصی نوشته‌ها
         setting_default_sensitive: همیشه تصاویر را به عنوان حساس علامت بزن
         setting_delete_modal: نمایش پیغام تأیید پیش از پاک کردن یک نوشته
-        setting_display_sensitive_media: همیشه تصویرهای علامت‌زده‌شده به عنوان حساس را نمایش بده
         setting_hide_network: نهفتن شبکهٔ ارتباطی
         setting_noindex: درخواست از موتورهای جستجوگر برای ظاهر نشدن در نتایج جستجو
         setting_reduce_motion: کاستن از حرکت در پویانمایی‌ها
diff --git a/config/locales/simple_form.fi.yml b/config/locales/simple_form.fi.yml
index 190790ca5..e90bd2e0b 100644
--- a/config/locales/simple_form.fi.yml
+++ b/config/locales/simple_form.fi.yml
@@ -47,7 +47,6 @@ fi:
         setting_default_privacy: Julkaisun näkyvyys
         setting_default_sensitive: Merkitse media aina arkaluontoiseksi
         setting_delete_modal: Kysy vahvistusta ennen tuuttauksen poistamista
-        setting_display_sensitive_media: Näytä aina arkaluontoiseksi merkitty media
         setting_noindex: Jättäydy pois hakukoneindeksoinnista
         setting_reduce_motion: Vähennä animaatioiden liikettä
         setting_system_font_ui: Käytä järjestelmän oletusfonttia
diff --git a/config/locales/simple_form.fr.yml b/config/locales/simple_form.fr.yml
index 7495a9425..1e0c4d3e6 100644
--- a/config/locales/simple_form.fr.yml
+++ b/config/locales/simple_form.fr.yml
@@ -69,7 +69,6 @@ fr:
         setting_default_privacy: Confidentialité des statuts
         setting_default_sensitive: Toujours marquer les médias comme sensibles
         setting_delete_modal: Afficher une fenêtre de confirmation avant de supprimer un pouet
-        setting_display_sensitive_media: Toujours afficher les médias marqués comme sensibles
         setting_hide_network: Cacher votre réseau
         setting_noindex: Demander aux moteurs de recherche de ne pas indexer vos informations personnelles
         setting_reduce_motion: Réduire la vitesse des animations
diff --git a/config/locales/simple_form.gl.yml b/config/locales/simple_form.gl.yml
index 8df441c36..935545b0e 100644
--- a/config/locales/simple_form.gl.yml
+++ b/config/locales/simple_form.gl.yml
@@ -69,7 +69,6 @@ gl:
         setting_default_privacy: Intimidade da publicación
         setting_default_sensitive: Marcar sempre multimedia como sensible
         setting_delete_modal: Solicitar confirmación antes de eliminar unha mensaxe
-        setting_display_sensitive_media: Mostrar sempre os medios marcados como sensibles
         setting_hide_network: Agochar a súa rede
         setting_noindex: Pedir non aparecer nas buscas dos motores de busca
         setting_reduce_motion: Reducir o movemento nas animacións
diff --git a/config/locales/simple_form.it.yml b/config/locales/simple_form.it.yml
index 2eaf04a70..841e65faa 100644
--- a/config/locales/simple_form.it.yml
+++ b/config/locales/simple_form.it.yml
@@ -69,7 +69,6 @@ it:
         setting_default_privacy: Privacy dei post
         setting_default_sensitive: Segna sempre i media come sensibili
         setting_delete_modal: Mostra dialogo di conferma prima di eliminare un toot
-        setting_display_sensitive_media: Mostra sempre i media segnati come sensibili
         setting_hide_network: Nascondi la tua rete
         setting_noindex: Non indicizzare dai motori di ricerca
         setting_reduce_motion: Riduci movimento nelle animazioni
diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml
index d79dd75d1..71e2f935e 100644
--- a/config/locales/simple_form.ja.yml
+++ b/config/locales/simple_form.ja.yml
@@ -19,6 +19,9 @@ ja:
         phrase: トゥートの大文字小文字や閲覧注意に関係なく一致
         scopes: アプリの API に許可するアクセス権を選択してください。最上位のスコープを選択する場合、個々のスコープを選択する必要はありません。
         setting_default_language: トゥートの言語は自動的に検出されますが、必ずしも正確とは限りません
+        setting_display_media_default: 閲覧注意としてマークされたメディアは隠す
+        setting_display_media_hide_all: 全てのメディアを常に隠す
+        setting_display_media_show_all: 閲覧注意としてマークされたメディアも常に表示する
         setting_hide_network: フォローとフォロワーの情報がプロフィールページで見られないようにします
         setting_noindex: 公開プロフィールおよび各投稿ページに影響します
         setting_theme: ログインしている全てのデバイスで適用されるデザインです。
@@ -65,7 +68,10 @@ ja:
         setting_default_privacy: 投稿の公開範囲
         setting_default_sensitive: メディアを常に閲覧注意としてマークする
         setting_delete_modal: トゥートを削除する前に確認ダイアログを表示する
-        setting_display_sensitive_media: 閲覧注意としてマークされたメディアも常に表示する
+        setting_display_media: メディアの表示
+        setting_display_media_default: 標準
+        setting_display_media_hide_all: 非表示
+        setting_display_media_show_all: 表示
         setting_favourite_modal: お気に入りをする前に確認ダイアログを表示する
         setting_hide_network: 繋がりを隠す
         setting_noindex: 検索エンジンによるインデックスを拒否する
diff --git a/config/locales/simple_form.ka.yml b/config/locales/simple_form.ka.yml
index eb6d82bb2..b1b29a7ce 100644
--- a/config/locales/simple_form.ka.yml
+++ b/config/locales/simple_form.ka.yml
@@ -69,7 +69,6 @@ ka:
         setting_default_privacy: პოსტის კონფიდენციალურობა
         setting_default_sensitive: ყოველთვის მოინიშნოს მედია მგრძნობიარედ
         setting_delete_modal: ტუტის გაუქმებამდე გამოჩნდეს დადასტურების ფანჯარა
-        setting_display_sensitive_media: ყოველთვის გამოჩნდეს მგრძნობიარე მედია
         setting_hide_network: თქვენი ქსელის დამალვა
         setting_noindex: საძოები სისტემების ინდექსაციის შეჩერება
         setting_reduce_motion: მოძრაობის შემცირება ანიმაციებში
diff --git a/config/locales/simple_form.ko.yml b/config/locales/simple_form.ko.yml
index 97baf7856..232844df8 100644
--- a/config/locales/simple_form.ko.yml
+++ b/config/locales/simple_form.ko.yml
@@ -69,7 +69,6 @@ ko:
         setting_default_privacy: 툿 프라이버시
         setting_default_sensitive: 미디어를 언제나 민감한 컨텐츠로 설정
         setting_delete_modal: 툿 삭제 전 확인 창을 표시
-        setting_display_sensitive_media: 열람주의로 설정 된 이미지도 항상 보여주기
         setting_hide_network: 내 네트워크 숨기기
         setting_noindex: 검색엔진의 인덱싱을 거절
         setting_reduce_motion: 애니메이션 줄이기
diff --git a/config/locales/simple_form.nl.yml b/config/locales/simple_form.nl.yml
index 33ab60161..32ad8d52c 100644
--- a/config/locales/simple_form.nl.yml
+++ b/config/locales/simple_form.nl.yml
@@ -69,7 +69,6 @@ nl:
         setting_default_privacy: Standaardzichtbaarheid van jouw toots
         setting_default_sensitive: Media altijd als gevoelig markeren
         setting_delete_modal: Vraag voor het verwijderen van een toot een bevestiging
-        setting_display_sensitive_media: Als gevoelig gemarkeerde media altijd tonen
         setting_hide_network: Jouw volgers en wie je volgt verbergen
         setting_noindex: Jouw toots niet door zoekmachines laten indexeren
         setting_reduce_motion: Langzamere animaties
diff --git a/config/locales/simple_form.oc.yml b/config/locales/simple_form.oc.yml
index 98ec01219..5363aa02a 100644
--- a/config/locales/simple_form.oc.yml
+++ b/config/locales/simple_form.oc.yml
@@ -69,7 +69,6 @@ oc:
         setting_default_privacy: Confidencialitat dels tuts
         setting_default_sensitive: Totjorn marcar los mèdias coma sensibles
         setting_delete_modal: Mostrar una fenèstra de confirmacion abans de suprimir un estatut
-        setting_display_sensitive_media: Totjorn mostrar los mèdias coma sensibles
         setting_hide_network: Amagar vòstre malhum
         setting_noindex: Èsser pas indexat pels motors de recèrca
         setting_reduce_motion: Reduire la velocitat de las animacions
diff --git a/config/locales/simple_form.pl.yml b/config/locales/simple_form.pl.yml
index 2fb99ccd7..d994eb6f5 100644
--- a/config/locales/simple_form.pl.yml
+++ b/config/locales/simple_form.pl.yml
@@ -74,7 +74,6 @@ pl:
         setting_default_privacy: Widoczność wpisów
         setting_default_sensitive: Zawsze oznaczaj zawartość multimedialną jako wrażliwą
         setting_delete_modal: Pytaj o potwierdzenie przed usunięciem wpisu
-        setting_display_sensitive_media: Zawsze oznaczaj zawartość multimedialną jako wrażliwą
         setting_favourite_modal: Pytaj o potwierdzenie przed dodaniem do ulubionych
         setting_hide_network: Ukryj swoją sieć
         setting_noindex: Nie indeksuj mojego profilu w wyszukiwarkach internetowych
diff --git a/config/locales/simple_form.pt-BR.yml b/config/locales/simple_form.pt-BR.yml
index 013b26066..23272c41f 100644
--- a/config/locales/simple_form.pt-BR.yml
+++ b/config/locales/simple_form.pt-BR.yml
@@ -69,7 +69,6 @@ pt-BR:
         setting_default_privacy: Privacidade das postagens
         setting_default_sensitive: Sempre marcar mídia como sensível
         setting_delete_modal: Mostrar diálogo de confirmação antes de deletar uma postagem
-        setting_display_sensitive_media: Sempre exibir mídia marcada como sensível
         setting_hide_network: Esconder as suas redes
         setting_noindex: Não quero ser indexado por mecanismos de busca
         setting_reduce_motion: Reduz movimento em animações
diff --git a/config/locales/simple_form.ro.yml b/config/locales/simple_form.ro.yml
index 8cac6d606..fcccd1a10 100644
--- a/config/locales/simple_form.ro.yml
+++ b/config/locales/simple_form.ro.yml
@@ -63,7 +63,6 @@ ro:
         setting_default_privacy: Cine vede postările tale
         setting_default_sensitive: Întotdeauna marchează conținutul media ca sensibil
         setting_delete_modal: Arată dialogul de confirmare înainte de a șterge o postare
-        setting_display_sensitive_media: Întotdeauna arată conținutul media sensibil
         setting_hide_network: Ascunde rețeaua
         setting_noindex: Nu permite motoarelor de căutare să indexeze rețeaua ta
         setting_reduce_motion: Redu mișcarea în animații
diff --git a/config/locales/simple_form.ru.yml b/config/locales/simple_form.ru.yml
index d1066b054..daeb7300a 100644
--- a/config/locales/simple_form.ru.yml
+++ b/config/locales/simple_form.ru.yml
@@ -73,7 +73,6 @@ ru:
         setting_default_privacy: Видимость постов
         setting_default_sensitive: Всегда отмечать медиаконтент как чувствительный
         setting_delete_modal: Показывать диалог подтверждения перед удалением
-        setting_display_sensitive_media: Всегда показывать медиаконтент, отмеченный как чувствительный
         setting_hide_network: Скрыть свои связи
         setting_noindex: Отказаться от индексации в поисковых машинах
         setting_reduce_motion: Уменьшить движение в анимации
diff --git a/config/locales/simple_form.sk.yml b/config/locales/simple_form.sk.yml
index d92e2dd83..0fd8f66b6 100644
--- a/config/locales/simple_form.sk.yml
+++ b/config/locales/simple_form.sk.yml
@@ -26,8 +26,8 @@ sk:
         scopes: Ktoré API budú povolené aplikácii pre prístup. Ak vyberieš vrcholný stupeň, nemusíš už potom vyberať po jednom.
         setting_default_language: Jazyk tvojích príspevkov môže byť zistený automaticky, ale nieje to vždy presné
         setting_hide_network: Koho následuješ, a kto následuje teba nebude zobrazené na tvojom profile
-        setting_noindex: Ovplyvňuje verejný profil a statusy
-        setting_theme: Toto ovplyvňuje ako Mastodon vyzerá pri prihlásení z hociakého zariadenia.
+        setting_noindex: Ovplyvňuje verejný profil a stránky s príspevkami
+        setting_theme: Ovplyvňuje ako Mastodon vyzerá pri prihlásení z hociakého zariadenia.
         whole_word: Ak je kľúčové slovo, alebo fráza poskladaná iba s písmen a čísel, bude použité iba ak sa zhoduje s celým výrazom
       imports:
         data: CSV súbor vyexportovaný z inej Mastodon inštancie
@@ -71,7 +71,6 @@ sk:
         setting_default_privacy: Súkromie príspevkov
         setting_default_sensitive: Označ všetky mediálne súbory ako chúlostivé
         setting_delete_modal: Zobrazuj potvrdzovacie okno pred vymazaním toot-u
-        setting_display_sensitive_media: Vždy zobrazuj médiá ktoré sú označené ako chúlostivé
         setting_hide_network: Ukri svoju sieť kontaktov
         setting_noindex: Nezaraďuj príspevky do indexu pre vyhľadávče
         setting_reduce_motion: Redukovať pohyb v animáciách
diff --git a/config/locales/simple_form.sr.yml b/config/locales/simple_form.sr.yml
index 3fac11eb8..333685ed5 100644
--- a/config/locales/simple_form.sr.yml
+++ b/config/locales/simple_form.sr.yml
@@ -73,7 +73,6 @@ sr:
         setting_default_privacy: Приватност објава
         setting_default_sensitive: Увек означи мултимедију као осетљиву
         setting_delete_modal: Прикажи дијалог за потврду пре брисања тута
-        setting_display_sensitive_media: Увек покажи означен садржај као осетљив
         setting_hide_network: Сакриј своју мрежу
         setting_noindex: Одјави се од индексирања search engine-а
         setting_reduce_motion: Смањи покрете у анимацијама
diff --git a/config/locales/simple_form.sv.yml b/config/locales/simple_form.sv.yml
index 7a10aa1e2..6f2e4b58f 100644
--- a/config/locales/simple_form.sv.yml
+++ b/config/locales/simple_form.sv.yml
@@ -59,7 +59,6 @@ sv:
         setting_default_privacy: Postintegritet
         setting_default_sensitive: Markera alltid media som känsligt
         setting_delete_modal: Visa bekräftelsedialog innan du raderar en toot
-        setting_display_sensitive_media: Visa alltid media märkt som känsligt
         setting_hide_network: Göm ditt nätverk
         setting_noindex: Uteslutning av sökmotorindexering
         setting_reduce_motion: Minska rörelser i animationer
diff --git a/config/locales/simple_form.zh-CN.yml b/config/locales/simple_form.zh-CN.yml
index b84f7107d..36b5a3f66 100644
--- a/config/locales/simple_form.zh-CN.yml
+++ b/config/locales/simple_form.zh-CN.yml
@@ -55,7 +55,6 @@ zh-CN:
         setting_default_privacy: 嘟文默认可见范围
         setting_default_sensitive: 总是将我发送的媒体文件标记为敏感内容
         setting_delete_modal: 在删除嘟文前询问我
-        setting_display_sensitive_media: 总是显示标记为敏感的媒体文件
         setting_hide_network: 隐藏你的社交网络
         setting_noindex: 禁止搜索引擎建立索引
         setting_reduce_motion: 降低过渡动画效果
diff --git a/config/locales/simple_form.zh-HK.yml b/config/locales/simple_form.zh-HK.yml
index abe6b7e06..447b9ce7a 100644
--- a/config/locales/simple_form.zh-HK.yml
+++ b/config/locales/simple_form.zh-HK.yml
@@ -59,7 +59,6 @@ zh-HK:
         setting_default_privacy: 文章預設為
         setting_default_sensitive: 預設我的內容為敏感內容
         setting_delete_modal: 刪推前詢問我
-        setting_display_sensitive_media: 預設我的媒體為敏感內容
         setting_hide_network: 隱藏你的社交網絡
         setting_noindex: 阻止搜尋引擎檢索
         setting_reduce_motion: 減低動畫效果
diff --git a/config/locales/simple_form.zh-TW.yml b/config/locales/simple_form.zh-TW.yml
index 7b3101239..7eae7e190 100644
--- a/config/locales/simple_form.zh-TW.yml
+++ b/config/locales/simple_form.zh-TW.yml
@@ -69,7 +69,6 @@ zh-TW:
         setting_default_privacy: 嘟文預設為
         setting_default_sensitive: 總是將媒體標記為敏感內容
         setting_delete_modal: 刪除嘟文前先詢問我
-        setting_display_sensitive_media: 總是顯示標記為敏感內容的媒體
         setting_hide_network: 隱藏你的社交網路
         setting_noindex: 阻止搜尋引擎收錄
         setting_reduce_motion: 減低動畫效果
diff --git a/config/locales/sk.yml b/config/locales/sk.yml
index 8e6e128d8..31698ac5e 100644
--- a/config/locales/sk.yml
+++ b/config/locales/sk.yml
@@ -37,7 +37,7 @@ sk:
     terms: Podmienky užívania
     user_count_after:
       one: užívateľ
-      other: užívatelia
+      other: užívateľov
     user_count_before: Domov pre
     what_is_mastodon: Čo je Mastodon?
   accounts:
@@ -45,8 +45,8 @@ sk:
     follow: Sledovať
     followers:
       one: Následovateľ
-      other: Následovatelia
-    following: Sleduje
+      other: Sledovatelia
+    following: Sledovaní
     joined: Pridal/a sa %{date}
     media: Médiá
     moved_html: "%{name} účet bol presunutý na %{new_profile_link}:"
@@ -93,9 +93,9 @@ sk:
       disabled: Blokovaný
       display_name: Zobraziť meno
       domain: Doména
-      edit: Upraviť
-      email: Email
-      email_status: Stav Email
+      edit: Uprav
+      email: Emailová adresa
+      email_status: Stav emailu
       enable: Povoliť
       enabled: Povolený
       feed_url: URL časovej osi
diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml
index 0e8f21821..9bb8124be 100644
--- a/config/locales/zh-CN.yml
+++ b/config/locales/zh-CN.yml
@@ -11,7 +11,7 @@ zh-CN:
     contact: 联系方式
     contact_missing: 未设定
     contact_unavailable: 未公开
-    documentation: 文件
+    documentation: 文档
     extended_description_html: |
       <h3>这里可以写一些规定</h3>
       <p>本站尚未设置详细介绍。</p>
@@ -28,15 +28,15 @@ zh-CN:
     hosted_on: 一个在 %{domain} 上运行的 Mastodon 实例
     learn_more: 了解详情
     other_instances: 其他实例
-    privacy_policy: 隐私条款
+    privacy_policy: 隐私政策
     source_code: 源代码
     status_count_after:
-      one: 状态
+      one: 条嘟文
     status_count_before: 他们共嘟出了
     terms: 使用条款
     user_count_after:
-      one: 用户
-      other: 用户
+      one: 位用户
+      other: 位用户
     user_count_before: 这里共注册有
     what_is_mastodon: Mastodon 是什么?
   accounts:
@@ -53,7 +53,7 @@ zh-CN:
     people_followed_by: "%{name} 关注的人"
     people_who_follow: 关注 %{name} 的人
     posts:
-      one: 嘟嘟
+      one: 嘟文
       other: 嘟文
     posts_tab_heading: 嘟文
     posts_with_replies: 嘟文和回复
@@ -190,7 +190,7 @@ zh-CN:
         unsuspend_account: "%{name} 解除了用户 %{target} 的封禁状态"
         update_custom_emoji: "%{name} 更新了自定义表情 %{target}"
         update_status: "%{name} 刷新了 %{target} 的嘟文"
-      deleted_status: "(状态已删除)"
+      deleted_status: "(嘟文已删除)"
       title: 运营日志
     custom_emojis:
       by_domain: 域名
@@ -218,24 +218,26 @@ zh-CN:
       updated_msg: 表情更新成功!
       upload: 上传新表情
     dashboard:
-      config: 设置
-      feature_deletions: 帐号删除
+      backlog: 未处理任务数
+      config: 服务器配置
+      feature_deletions: 帐户删除
       feature_invites: 邀请链接
-      feature_registrations: 注册
-      features: 特性
-      hidden_service: 与暗网互联
-      open_reports: 待处理举报
+      feature_registrations: 公开注册
+      feature_relay: 同步中继
+      features: 功能
+      hidden_service: 匿名服务连通性
+      open_reports: 待处理举报数
       recent_users: 新用户
       search: 全文搜索
       single_user_mode: 单用户模式
       software: 软件
-      space: 空间用量
-      title: 大盘
+      space: 存储使用情况
+      title: 仪表盘
       total_users: 总用户数
       trends: 趋势
-      week_interactions: 本周互动
-      week_users_active: 本周活跃用户
-      week_users_new: 本周新用户
+      week_interactions: 本周互动数
+      week_users_active: 本周活跃用户数
+      week_users_new: 本周新用户数
     domain_blocks:
       add_new: 添加新条目
       created_msg: 正在进行域名屏蔽
@@ -259,8 +261,8 @@ zh-CN:
       severity: 屏蔽级别
       show:
         affected_accounts:
-          one: 影响数据库中 1 位用户
-          other: 影响数据库中 %{count} 位用户
+          one: 将会影响到数据库中的 1 个帐户
+          other: 将会影响到数据库中的 %{count} 个帐户
         retroactive:
           silence: 对此域名的所有帐户解除隐藏
           suspend: 对此域名的所有帐户解除封禁
@@ -285,7 +287,7 @@ zh-CN:
       search: 搜索
       title: 已知实例
     invites:
-      deactivate_all: 全部禁用
+      deactivate_all: 撤销所有邀请链接
       filter:
         all: 全部
         available: 可用
@@ -293,12 +295,13 @@ zh-CN:
         title: 筛选
       title: 邀请用户
     relays:
-      add_new: 添加中继
-      description_html: "<strong>消息中继</strong>是一种中间服务器,用于在订阅它和向它推送消息的服务器之间大量交换嘟文。<strong>它可以帮助中小型实例发现长毛象宇宙中的内容</strong>,而无需本地用户手动关注其他远程实例上的用户。"
-      enable_hint: 一经启用,你的服务器会订阅此中继的所有嘟文,并向其发送本服务器的公共嘟文。
+      add_new: 添加新的中继
+      description_html: "<strong>同步中继</strong>是一种中间服务器,各实例可以通过订阅中继和向中继推送信息的方式来大量交换公开嘟文。<strong>它可以帮助中小型实例发现网络中的内容</strong>,而无需本地用户手动关注其他远程实例上的用户。"
+      enable_hint: 启用此功能后,你的实例会订阅此中继的所有公开嘟文,并同时向其推送本服务器的公开嘟文。
       inbox_url: 中继 URL
       pending: 等待中继确认
       save_and_enable: 保存并启用
+      setup: 设置中继连接
       status: 状态
       title: 中继
     report_notes:
@@ -347,6 +350,7 @@ zh-CN:
         email: 用于联系的公开电子邮件地址
         username: 用于联系的公开用户名
       custom_css:
+        desc_html: 通过 CSS 代码调整所有页面的显示效果
         title: 自定义 CSS
       hero:
         desc_html: 用于在首页展示。推荐分辨率 600×100px 以上。未指定的情况下将默认使用本站缩略图
@@ -355,8 +359,8 @@ zh-CN:
         desc_html: 截至目前本实例在网络中已发现的域名
         title: 公开已知实例的列表
       preview_sensitive_media:
-        desc_html: 即使媒体文件被标记为敏感内容,其他站点上的链接预览仍会显示其缩略图
-        title: 在 OpenGraph 预览中显示敏感内容
+        desc_html: 始终在站外链接预览中展示缩略图,无论媒体内容是否标记为敏感
+        title: 在 OpenGraph 预览中显示敏感媒体内容
       registrations:
         closed_message:
           desc_html: 本站关闭注册期间的提示信息。可以使用 HTML 标签
@@ -517,16 +521,19 @@ zh-CN:
     storage: 媒体文件存储
   filters:
     contexts:
+      home: 主页时间轴
       notifications: 通知
-      public: 公共时间线
+      public: 公共时间轴
       thread: 对话
     edit:
       title: 编辑过滤器
+    errors:
+      invalid_irreversible: 此功能只适用于主页时间轴或通知
     index:
       delete: 删除
       title: 过滤器
     new:
-      title: 添加过滤器
+      title: 添加新的过滤器
   followers:
     domain: 域名
     explanation_html: 为保证你的嘟文的隐私安全,你应当经常检查你的关注者列表。<strong>受保护的嘟文将会发送到所有关注者所在的实例上</strong>。有些实例使用的软件代码或其管理员可能不会尊重你的隐私设置,因此你应当复查一下关注者列表,并移除那些你无法信任的关注者。
diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml
index ad73c5583..e2b9b520e 100644
--- a/config/locales/zh-TW.yml
+++ b/config/locales/zh-TW.yml
@@ -12,7 +12,9 @@ zh-TW:
     contact_missing: 未設定
     contact_unavailable: 未公開
     documentation: 文件
-    extended_description_html: "<h3>這裡可以寫一些網站規則</h3> <p>本站點未有詳細介紹</p>\n"
+    extended_description_html: |
+      <h3>這裡可以寫一些網站規則</h3>
+      <p>本站點未有詳細介紹</p>
     features:
       humane_approach_body: Mastodon 從其他網路的失敗經驗中汲取教訓,以合乎道德的設計對抗社交媒體的濫用問題。
       humane_approach_title: 以人為本
diff --git a/config/routes.rb b/config/routes.rb
index 90333daab..db79fc323 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -21,6 +21,7 @@ Rails.application.routes.draw do
 
   get '.well-known/host-meta', to: 'well_known/host_meta#show', as: :host_meta, defaults: { format: 'xml' }
   get '.well-known/webfinger', to: 'well_known/webfinger#show', as: :webfinger
+  get '.well-known/change-password', to: redirect('/auth/edit')
   get 'manifest', to: 'manifests#show', defaults: { format: 'json' }
   get 'intent', to: 'intents#show'
   get 'custom.css', to: 'custom_css#show', as: :custom_css
@@ -279,7 +280,7 @@ Rails.application.routes.draw do
       end
       resources :favourites,   only: [:index]
       resources :bookmarks,    only: [:index]
-      resources :reports,      only: [:index, :create]
+      resources :reports,      only: [:create]
       resources :filters,      only: [:index, :create, :show, :update, :destroy]
       resources :endorsements, only: [:index]
 
diff --git a/config/settings.yml b/config/settings.yml
index 304271910..48639e9a8 100644
--- a/config/settings.yml
+++ b/config/settings.yml
@@ -27,7 +27,8 @@ defaults: &defaults
   favourite_modal: false
   delete_modal: true
   auto_play_gif: false
-  display_sensitive_media: false
+  display_media: 'default'
+  expand_spoilers: false
   preview_sensitive_media: false
   reduce_motion: false
   system_font_ui: false
diff --git a/config/sidekiq.yml b/config/sidekiq.yml
index 59dfeaf97..6a09bb6e9 100644
--- a/config/sidekiq.yml
+++ b/config/sidekiq.yml
@@ -1,10 +1,10 @@
 ---
 :concurrency: 5
 :queues:
-  - default
-  - push
-  - mailers
-  - pull
+  - [default, 6]
+  - [push, 4]
+  - [mailers, 2]
+  - [pull]
 :schedule:
   subscriptions_scheduler:
     cron: '<%= Random.rand(0..59) %> <%= Random.rand(4..6) %> * * *'
diff --git a/dist/mastodon-sidekiq.service b/dist/mastodon-sidekiq.service
new file mode 100644
index 000000000..721a86609
--- /dev/null
+++ b/dist/mastodon-sidekiq.service
@@ -0,0 +1,17 @@
+[Unit]
+Description=mastodon-sidekiq
+After=network.target
+
+[Service]
+Type=simple
+User=mastodon
+WorkingDirectory=/home/mastodon/live
+Environment="RAILS_ENV=production"
+Environment="DB_POOL=25"
+Environment="MALLOC_ARENA_MAX=2"
+ExecStart=/home/mastodon/.rbenv/shims/bundle exec sidekiq -c 25
+TimeoutSec=15
+Restart=always
+
+[Install]
+WantedBy=multi-user.target
diff --git a/dist/mastodon-streaming.service b/dist/mastodon-streaming.service
new file mode 100644
index 000000000..5d7c129df
--- /dev/null
+++ b/dist/mastodon-streaming.service
@@ -0,0 +1,17 @@
+[Unit]
+Description=mastodon-streaming
+After=network.target
+
+[Service]
+Type=simple
+User=mastodon
+WorkingDirectory=/home/mastodon/live
+Environment="NODE_ENV=production"
+Environment="PORT=4000"
+Environment="STREAMING_CLUSTER_NUM=1"
+ExecStart=/usr/bin/npm run start
+TimeoutSec=15
+Restart=always
+
+[Install]
+WantedBy=multi-user.target
diff --git a/dist/mastodon-web.service b/dist/mastodon-web.service
new file mode 100644
index 000000000..30fcbec1e
--- /dev/null
+++ b/dist/mastodon-web.service
@@ -0,0 +1,17 @@
+[Unit]
+Description=mastodon-web
+After=network.target
+
+[Service]
+Type=simple
+User=mastodon
+WorkingDirectory=/home/mastodon/live
+Environment="RAILS_ENV=production"
+Environment="PORT=3000"
+ExecStart=/home/mastodon/.rbenv/shims/bundle exec puma -C config/puma.rb
+ExecReload=/bin/kill -SIGUSR1 $MAINPID
+TimeoutSec=15
+Restart=always
+
+[Install]
+WantedBy=multi-user.target
diff --git a/dist/nginx.conf b/dist/nginx.conf
new file mode 100644
index 000000000..3d5741765
--- /dev/null
+++ b/dist/nginx.conf
@@ -0,0 +1,106 @@
+map $http_upgrade $connection_upgrade {
+  default upgrade;
+  ''      close;
+}
+
+proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=1g;
+
+server {
+  listen 80;
+  listen [::]:80;
+  server_name example.com;
+  root /home/mastodon/live/public;
+  location /.well-known/acme-challenge/ { allow all; }
+  location / { return 301 https://$host$request_uri; }
+}
+
+server {
+  listen 443 ssl http2;
+  listen [::]:443 ssl http2;
+  server_name example.com;
+
+  ssl_protocols TLSv1.2;
+  ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA;
+  ssl_prefer_server_ciphers on;
+  ssl_session_cache shared:SSL:10m;
+
+  # Uncomment these lines once you acquire a certificate:
+  # ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
+  # ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
+
+  keepalive_timeout    70;
+  sendfile             on;
+  client_max_body_size 80m;
+
+  root /home/mastodon/live/public;
+
+  gzip on;
+  gzip_disable "msie6";
+  gzip_vary on;
+  gzip_proxied any;
+  gzip_comp_level 6;
+  gzip_buffers 16 8k;
+  gzip_http_version 1.1;
+  gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
+
+  add_header Strict-Transport-Security "max-age=31536000";
+
+  location / {
+    try_files $uri @proxy;
+  }
+
+  location ~ ^/(emoji|packs|system/accounts/avatars|system/media_attachments/files) {
+    add_header Cache-Control "public, max-age=31536000, immutable";
+    add_header Strict-Transport-Security "max-age=31536000";
+    try_files $uri @proxy;
+  }
+
+  location /sw.js {
+    add_header Cache-Control "public, max-age=0";
+    add_header Strict-Transport-Security "max-age=31536000";
+    try_files $uri @proxy;
+  }
+
+  location @proxy {
+    proxy_set_header Host $host;
+    proxy_set_header X-Real-IP $remote_addr;
+    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+    proxy_set_header X-Forwarded-Proto https;
+    proxy_set_header Proxy "";
+    proxy_pass_header Server;
+
+    proxy_pass http://127.0.0.1:3000;
+    proxy_buffering on;
+    proxy_redirect off;
+    proxy_http_version 1.1;
+    proxy_set_header Upgrade $http_upgrade;
+    proxy_set_header Connection $connection_upgrade;
+
+    proxy_cache CACHE;
+    proxy_cache_valid 200 7d;
+    proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
+    add_header X-Cached $upstream_cache_status;
+    add_header Strict-Transport-Security "max-age=31536000";
+
+    tcp_nodelay on;
+  }
+
+  location /api/v1/streaming {
+    proxy_set_header Host $host;
+    proxy_set_header X-Real-IP $remote_addr;
+    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+    proxy_set_header X-Forwarded-Proto https;
+    proxy_set_header Proxy "";
+
+    proxy_pass http://127.0.0.1:4000;
+    proxy_buffering off;
+    proxy_redirect off;
+    proxy_http_version 1.1;
+    proxy_set_header Upgrade $http_upgrade;
+    proxy_set_header Connection $connection_upgrade;
+
+    tcp_nodelay on;
+  }
+
+  error_page 500 501 502 503 504 /500.html;
+}
diff --git a/docs/Contributing-to-Mastodon/Sponsors.md b/docs/Contributing-to-Mastodon/Sponsors.md
deleted file mode 100644
index 8fc22b6bb..000000000
--- a/docs/Contributing-to-Mastodon/Sponsors.md
+++ /dev/null
@@ -1 +0,0 @@
-[The documentation has moved to its own repository](https://github.com/tootsuite/documentation/blob/master/Contributing-to-Mastodon/Sponsors.md)
diff --git a/docs/Contributing-to-Mastodon/Translating.md b/docs/Contributing-to-Mastodon/Translating.md
deleted file mode 100644
index 1671645ee..000000000
--- a/docs/Contributing-to-Mastodon/Translating.md
+++ /dev/null
@@ -1 +0,0 @@
-[The documentation has moved to its own repository](https://github.com/tootsuite/documentation/blob/master/Contributing-to-Mastodon/Translating.md)
diff --git a/docs/Extensions.md b/docs/Extensions.md
deleted file mode 100644
index be4c6eabd..000000000
--- a/docs/Extensions.md
+++ /dev/null
@@ -1 +0,0 @@
-[The documentation has moved to its own repository](https://github.com/tootsuite/documentation/blob/master/Extensions.md)
diff --git a/docs/README.md b/docs/README.md
deleted file mode 100644
index 63bcf5a24..000000000
--- a/docs/README.md
+++ /dev/null
@@ -1 +0,0 @@
-[The documentation has moved to its own repository](https://github.com/tootsuite/documentation/blob/master/README.md)
diff --git a/docs/Running-Mastodon/Administration-guide.md b/docs/Running-Mastodon/Administration-guide.md
deleted file mode 100644
index e7571be3a..000000000
--- a/docs/Running-Mastodon/Administration-guide.md
+++ /dev/null
@@ -1 +0,0 @@
-[The documentation has moved to its own repository](https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Administration-guide.md)
diff --git a/docs/Running-Mastodon/Development-guide.md b/docs/Running-Mastodon/Development-guide.md
deleted file mode 100644
index 10ed64087..000000000
--- a/docs/Running-Mastodon/Development-guide.md
+++ /dev/null
@@ -1 +0,0 @@
-[The documentation has moved to its own repository](https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Development-guide.md)
diff --git a/docs/Running-Mastodon/Heroku-guide.md b/docs/Running-Mastodon/Heroku-guide.md
deleted file mode 100644
index aa5abc1f5..000000000
--- a/docs/Running-Mastodon/Heroku-guide.md
+++ /dev/null
@@ -1 +0,0 @@
-[The documentation has moved to its own repository](https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Heroku-guide.md)
diff --git a/docs/Running-Mastodon/Production-guide.md b/docs/Running-Mastodon/Production-guide.md
deleted file mode 100644
index 08649e9ce..000000000
--- a/docs/Running-Mastodon/Production-guide.md
+++ /dev/null
@@ -1 +0,0 @@
-[The documentation has moved to its own repository](https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Production-guide.md)
diff --git a/docs/Running-Mastodon/Scalingo-guide.md b/docs/Running-Mastodon/Scalingo-guide.md
deleted file mode 100644
index 8c986f750..000000000
--- a/docs/Running-Mastodon/Scalingo-guide.md
+++ /dev/null
@@ -1 +0,0 @@
-[The documentation has moved to its own repository](https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Scalingo-guide.md)
diff --git a/docs/Running-Mastodon/Tuning.md b/docs/Running-Mastodon/Tuning.md
deleted file mode 100644
index 5e5474194..000000000
--- a/docs/Running-Mastodon/Tuning.md
+++ /dev/null
@@ -1 +0,0 @@
-[The documentation has moved to its own repository](https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Tuning.md)
diff --git a/docs/Running-Mastodon/Vagrant-guide.md b/docs/Running-Mastodon/Vagrant-guide.md
deleted file mode 100644
index c5823b09b..000000000
--- a/docs/Running-Mastodon/Vagrant-guide.md
+++ /dev/null
@@ -1 +0,0 @@
-[The documentation has moved to its own repository](https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Vagrant-guide.md)
diff --git a/docs/Specs-and-RFCs-used.md b/docs/Specs-and-RFCs-used.md
deleted file mode 100644
index 89a4dd313..000000000
--- a/docs/Specs-and-RFCs-used.md
+++ /dev/null
@@ -1 +0,0 @@
-[The documentation has moved to its own repository](https://github.com/tootsuite/documentation/blob/master/Specs-and-RFCs-used.md)
diff --git a/docs/Using-Mastodon/2FA.md b/docs/Using-Mastodon/2FA.md
deleted file mode 100644
index d5c6985b7..000000000
--- a/docs/Using-Mastodon/2FA.md
+++ /dev/null
@@ -1 +0,0 @@
-[The documentation has moved to its own repository](https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/2FA.md)
diff --git a/docs/Using-Mastodon/Apps.md b/docs/Using-Mastodon/Apps.md
deleted file mode 100644
index c2ced4457..000000000
--- a/docs/Using-Mastodon/Apps.md
+++ /dev/null
@@ -1 +0,0 @@
-[The documentation has moved to its own repository](https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md)
diff --git a/docs/Using-Mastodon/FAQ.md b/docs/Using-Mastodon/FAQ.md
deleted file mode 100644
index d50e63b93..000000000
--- a/docs/Using-Mastodon/FAQ.md
+++ /dev/null
@@ -1 +0,0 @@
-[The documentation has moved to its own repository](https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/FAQ.md)
diff --git a/docs/Using-Mastodon/List-of-Mastodon-instances.md b/docs/Using-Mastodon/List-of-Mastodon-instances.md
deleted file mode 100644
index 0e2d08643..000000000
--- a/docs/Using-Mastodon/List-of-Mastodon-instances.md
+++ /dev/null
@@ -1 +0,0 @@
-[The documentation has moved to its own repository](https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/List-of-Mastodon-instances.md)
diff --git a/docs/Using-Mastodon/User-guide.md b/docs/Using-Mastodon/User-guide.md
deleted file mode 100644
index 7ef5a117b..000000000
--- a/docs/Using-Mastodon/User-guide.md
+++ /dev/null
@@ -1 +0,0 @@
-[The documentation has moved to its own repository](https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/User-guide.md)
diff --git a/docs/Using-the-API/API.md b/docs/Using-the-API/API.md
deleted file mode 100644
index 6de61e196..000000000
--- a/docs/Using-the-API/API.md
+++ /dev/null
@@ -1 +0,0 @@
-[The documentation has moved to its own repository](https://github.com/tootsuite/documentation/blob/master/Using-the-API/API.md)
diff --git a/docs/Using-the-API/OAuth-details.md b/docs/Using-the-API/OAuth-details.md
deleted file mode 100644
index 6a6926bb9..000000000
--- a/docs/Using-the-API/OAuth-details.md
+++ /dev/null
@@ -1 +0,0 @@
-[The documentation has moved to its own repository](https://github.com/tootsuite/documentation/blob/master/Using-the-API/OAuth-details.md)
diff --git a/docs/Using-the-API/Push-notifications.md b/docs/Using-the-API/Push-notifications.md
deleted file mode 100644
index 3292c0a6e..000000000
--- a/docs/Using-the-API/Push-notifications.md
+++ /dev/null
@@ -1 +0,0 @@
-[The documentation has moved to its own repository](https://github.com/tootsuite/documentation/blob/master/Using-the-API/Push-notifications.md)
diff --git a/docs/Using-the-API/Streaming-API.md b/docs/Using-the-API/Streaming-API.md
deleted file mode 100644
index 482f901c0..000000000
--- a/docs/Using-the-API/Streaming-API.md
+++ /dev/null
@@ -1 +0,0 @@
-[The documentation has moved to its own repository](https://github.com/tootsuite/documentation/blob/master/Using-the-API/Streaming-API.md)
diff --git a/docs/Using-the-API/Testing-with-cURL.md b/docs/Using-the-API/Testing-with-cURL.md
deleted file mode 100644
index 04c7c87b2..000000000
--- a/docs/Using-the-API/Testing-with-cURL.md
+++ /dev/null
@@ -1 +0,0 @@
-[The documentation has moved to its own repository](https://github.com/tootsuite/documentation/blob/master/Using-the-API/Testing-with-cURL.md)
diff --git a/docs/Using-the-API/Tips-for-app-developers.md b/docs/Using-the-API/Tips-for-app-developers.md
deleted file mode 100644
index 36a28da2e..000000000
--- a/docs/Using-the-API/Tips-for-app-developers.md
+++ /dev/null
@@ -1 +0,0 @@
-[The documentation has moved to its own repository](https://github.com/tootsuite/documentation/blob/master/Using-the-API/Tips-for-app-developers.md)
diff --git a/lib/mastodon/accounts_cli.rb b/lib/mastodon/accounts_cli.rb
index 65c1b395a..704cf474b 100644
--- a/lib/mastodon/accounts_cli.rb
+++ b/lib/mastodon/accounts_cli.rb
@@ -83,7 +83,8 @@ module Mastodon
         end
       end
 
-      user.account = account
+      account.suspended = false
+      user.account      = account
 
       if user.save
         if options[:confirmed]
@@ -170,11 +171,32 @@ module Mastodon
         exit(1)
       end
 
-      say("Deleting user with #{account.statuses_count}, this might take a while...")
+      say("Deleting user with #{account.statuses_count} statuses, this might take a while...")
       SuspendAccountService.new.call(account, remove_user: true)
       say('OK', :green)
     end
 
+    desc 'backup USERNAME', 'Request a backup for a user'
+    long_desc <<-LONG_DESC
+      Request a new backup for an account with a given USERNAME.
+
+      The backup will be created in Sidekiq asynchronously, and
+      the user will receive an e-mail with a link to it once
+      it's done.
+    LONG_DESC
+    def backup(username)
+      account = Account.find_local(username)
+
+      if account.nil?
+        say('No user with such username', :red)
+        exit(1)
+      end
+
+      backup = account.user.backups.create!
+      BackupWorker.perform_async(backup.id)
+      say('OK', :green)
+    end
+
     option :dry_run, type: :boolean
     desc 'cull', 'Remove remote accounts that no longer exist'
     long_desc <<-LONG_DESC
diff --git a/spec/controllers/api/v1/favourites_controller_spec.rb b/spec/controllers/api/v1/favourites_controller_spec.rb
index 2bdf927f2..231f76500 100644
--- a/spec/controllers/api/v1/favourites_controller_spec.rb
+++ b/spec/controllers/api/v1/favourites_controller_spec.rb
@@ -64,7 +64,7 @@ RSpec.describe Api::V1::FavouritesController, type: :controller do
           get :index, params: { limit: 1 }
 
           expect(response.headers['Link'].find_link(['rel', 'next']).href).to eq "http://test.host/api/v1/favourites?limit=1&max_id=#{favourite.id}"
-          expect(response.headers['Link'].find_link(['rel', 'prev']).href).to eq "http://test.host/api/v1/favourites?limit=1&since_id=#{favourite.id}"
+          expect(response.headers['Link'].find_link(['rel', 'prev']).href).to eq "http://test.host/api/v1/favourites?limit=1&min_id=#{favourite.id}"
         end
 
         it 'does not add pagination headers if not necessary' do
diff --git a/spec/controllers/api/v1/reports_controller_spec.rb b/spec/controllers/api/v1/reports_controller_spec.rb
index ac93998c6..a3596cf8a 100644
--- a/spec/controllers/api/v1/reports_controller_spec.rb
+++ b/spec/controllers/api/v1/reports_controller_spec.rb
@@ -12,16 +12,6 @@ RSpec.describe Api::V1::ReportsController, type: :controller do
     allow(controller).to receive(:doorkeeper_token) { token }
   end
 
-  describe 'GET #index' do
-    let(:scopes) { 'read:reports' }
-
-    it 'returns http success' do
-      get :index
-
-      expect(response).to have_http_status(200)
-    end
-  end
-
   describe 'POST #create' do
     let(:scopes)  { 'write:reports' }
     let!(:status) { Fabricate(:status) }
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index 3ccd96f44..61780b46b 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -9,6 +9,14 @@ describe ApplicationHelper do
       expect(result).to eq "active"
     end
 
+    it 'returns active when on a current page' do
+      allow(helper).to receive(:current_page?).with('/foo').and_return(false)
+      allow(helper).to receive(:current_page?).with('/test').and_return(true)
+
+      result = helper.active_nav_class('/foo', '/test')
+      expect(result).to eq "active"
+    end
+
     it 'returns empty string when not on current page' do
       allow(helper).to receive(:current_page?).and_return(false)