about summary refs log tree commit diff
diff options
context:
space:
mode:
authorThibG <thib@sitedethib.com>2018-10-24 11:28:25 +0200
committerGitHub <noreply@github.com>2018-10-24 11:28:25 +0200
commit0e8de56a22aee089da8aa1c64bab941bc5911e5d (patch)
treeac3f4100e27a9341c32c15e07661af841c547ec0
parent4739e0f090a04235669ef81fa432ae90bb62f4c4 (diff)
parented8d06212f439b9fe2f170a6f43d6be6d586ff80 (diff)
Merge pull request #792 from ThibG/glitch-soc/merge-upstream
Merge upstream changes
-rw-r--r--.circleci/config.yml3
-rw-r--r--.env.test4
-rw-r--r--.github/ISSUE_TEMPLATE/feature_request.md14
-rw-r--r--.github/ISSUE_TEMPLATE/support.md10
-rw-r--r--.ruby-version2
-rw-r--r--AUTHORS.md83
-rw-r--r--CHANGELOG.md107
-rw-r--r--CONTRIBUTING.md62
-rw-r--r--Dockerfile2
-rw-r--r--Gemfile10
-rw-r--r--Gemfile.lock34
-rw-r--r--app/controllers/admin/domain_blocks_controller.rb2
-rw-r--r--app/controllers/admin/reports_controller.rb9
-rw-r--r--app/controllers/api/v1/conversations_controller.rb20
-rw-r--r--app/controllers/api/v1/reports_controller.rb1
-rw-r--r--app/helpers/application_helper.rb6
-rw-r--r--app/javascript/core/admin.js21
-rw-r--r--app/javascript/flavours/glitch/components/display_name.js2
-rw-r--r--app/javascript/flavours/glitch/features/account_timeline/components/moved_note.js2
-rw-r--r--app/javascript/flavours/glitch/features/composer/options/dropdown/index.js2
-rw-r--r--app/javascript/flavours/glitch/features/notifications/components/follow.js4
-rw-r--r--app/javascript/flavours/glitch/styles/forms.scss17
-rw-r--r--app/javascript/flavours/glitch/styles/rtl.scss59
-rw-r--r--app/javascript/flavours/glitch/styles/stream_entries.scss1
-rw-r--r--app/javascript/mastodon/actions/compose.js27
-rw-r--r--app/javascript/mastodon/actions/conversations.js22
-rw-r--r--app/javascript/mastodon/actions/suggestions.js52
-rw-r--r--app/javascript/mastodon/components/account.js13
-rw-r--r--app/javascript/mastodon/components/avatar_composite.js96
-rw-r--r--app/javascript/mastodon/components/display_name.js19
-rw-r--r--app/javascript/mastodon/components/status.js23
-rw-r--r--app/javascript/mastodon/features/compose/components/compose_form.js6
-rw-r--r--app/javascript/mastodon/features/compose/components/privacy_dropdown.js2
-rw-r--r--app/javascript/mastodon/features/compose/components/search_results.js43
-rw-r--r--app/javascript/mastodon/features/compose/components/upload.js6
-rw-r--r--app/javascript/mastodon/features/compose/containers/compose_form_container.js4
-rw-r--r--app/javascript/mastodon/features/compose/containers/search_results_container.js9
-rw-r--r--app/javascript/mastodon/features/compose/containers/upload_container.js4
-rw-r--r--app/javascript/mastodon/features/compose/index.js3
-rw-r--r--app/javascript/mastodon/features/direct_timeline/components/conversation.js62
-rw-r--r--app/javascript/mastodon/features/direct_timeline/containers/conversation_container.js12
-rw-r--r--app/javascript/mastodon/features/direct_timeline/index.js5
-rw-r--r--app/javascript/mastodon/features/status/index.js2
-rw-r--r--app/javascript/mastodon/features/ui/index.js2
-rw-r--r--app/javascript/mastodon/initial_state.js1
-rw-r--r--app/javascript/mastodon/locales/ar.json16
-rw-r--r--app/javascript/mastodon/locales/ast.json4
-rw-r--r--app/javascript/mastodon/locales/bg.json4
-rw-r--r--app/javascript/mastodon/locales/ca.json4
-rw-r--r--app/javascript/mastodon/locales/co.json4
-rw-r--r--app/javascript/mastodon/locales/cs.json8
-rw-r--r--app/javascript/mastodon/locales/cy.json671
-rw-r--r--app/javascript/mastodon/locales/da.json4
-rw-r--r--app/javascript/mastodon/locales/de.json4
-rw-r--r--app/javascript/mastodon/locales/defaultMessages.json9
-rw-r--r--app/javascript/mastodon/locales/el.json6
-rw-r--r--app/javascript/mastodon/locales/en.json1
-rw-r--r--app/javascript/mastodon/locales/eo.json4
-rw-r--r--app/javascript/mastodon/locales/es.json4
-rw-r--r--app/javascript/mastodon/locales/eu.json4
-rw-r--r--app/javascript/mastodon/locales/fa.json6
-rw-r--r--app/javascript/mastodon/locales/fi.json4
-rw-r--r--app/javascript/mastodon/locales/fr.json6
-rw-r--r--app/javascript/mastodon/locales/gl.json4
-rw-r--r--app/javascript/mastodon/locales/he.json4
-rw-r--r--app/javascript/mastodon/locales/hr.json4
-rw-r--r--app/javascript/mastodon/locales/hu.json4
-rw-r--r--app/javascript/mastodon/locales/hy.json4
-rw-r--r--app/javascript/mastodon/locales/id.json4
-rw-r--r--app/javascript/mastodon/locales/io.json4
-rw-r--r--app/javascript/mastodon/locales/it.json4
-rw-r--r--app/javascript/mastodon/locales/ja.json9
-rw-r--r--app/javascript/mastodon/locales/ka.json4
-rw-r--r--app/javascript/mastodon/locales/ko.json4
-rw-r--r--app/javascript/mastodon/locales/nl.json4
-rw-r--r--app/javascript/mastodon/locales/no.json4
-rw-r--r--app/javascript/mastodon/locales/oc.json4
-rw-r--r--app/javascript/mastodon/locales/pl.json1
-rw-r--r--app/javascript/mastodon/locales/pt-BR.json4
-rw-r--r--app/javascript/mastodon/locales/pt.json4
-rw-r--r--app/javascript/mastodon/locales/ro.json4
-rw-r--r--app/javascript/mastodon/locales/ru.json4
-rw-r--r--app/javascript/mastodon/locales/sk.json4
-rw-r--r--app/javascript/mastodon/locales/sl.json4
-rw-r--r--app/javascript/mastodon/locales/sr-Latn.json4
-rw-r--r--app/javascript/mastodon/locales/sr.json4
-rw-r--r--app/javascript/mastodon/locales/sv.json4
-rw-r--r--app/javascript/mastodon/locales/ta.json4
-rw-r--r--app/javascript/mastodon/locales/te.json4
-rw-r--r--app/javascript/mastodon/locales/th.json4
-rw-r--r--app/javascript/mastodon/locales/tr.json4
-rw-r--r--app/javascript/mastodon/locales/uk.json4
-rw-r--r--app/javascript/mastodon/locales/zh-CN.json4
-rw-r--r--app/javascript/mastodon/locales/zh-HK.json4
-rw-r--r--app/javascript/mastodon/locales/zh-TW.json4
-rw-r--r--app/javascript/mastodon/reducers/conversations.js17
-rw-r--r--app/javascript/mastodon/reducers/index.js2
-rw-r--r--app/javascript/mastodon/reducers/suggestions.js30
-rw-r--r--app/javascript/styles/mastodon-light/diff.scss14
-rw-r--r--app/javascript/styles/mastodon/components.scss57
-rw-r--r--app/javascript/styles/mastodon/forms.scss17
-rw-r--r--app/javascript/styles/mastodon/rtl.scss59
-rw-r--r--app/javascript/styles/mastodon/stream_entries.scss1
-rw-r--r--app/lib/activitypub/activity.rb2
-rw-r--r--app/lib/activitypub/activity/create.rb107
-rw-r--r--app/lib/activitypub/activity/flag.rb8
-rw-r--r--app/lib/activitypub/tag_manager.rb6
-rw-r--r--app/lib/feed_manager.rb8
-rw-r--r--app/lib/formatter.rb2
-rw-r--r--app/lib/ostatus/atom_serializer.rb2
-rw-r--r--app/models/account_conversation.rb4
-rw-r--r--app/models/domain_block.rb13
-rw-r--r--app/models/mention.rb8
-rw-r--r--app/models/notification.rb2
-rw-r--r--app/models/status.rb19
-rw-r--r--app/models/stream_entry.rb2
-rw-r--r--app/policies/status_policy.rb8
-rw-r--r--app/serializers/activitypub/note_serializer.rb2
-rw-r--r--app/serializers/initial_state_serializer.rb7
-rw-r--r--app/serializers/rest/conversation_serializer.rb7
-rw-r--r--app/serializers/rest/status_serializer.rb13
-rw-r--r--app/services/batched_remove_status_service.rb2
-rw-r--r--app/services/fan_out_on_write_service.rb4
-rw-r--r--app/services/notify_service.rb5
-rw-r--r--app/services/remove_status_service.rb2
-rw-r--r--app/views/admin/accounts/show.html.haml6
-rw-r--r--app/views/admin/domain_blocks/_domain_block.html.haml5
-rw-r--r--app/views/admin/domain_blocks/index.html.haml1
-rw-r--r--app/views/admin/domain_blocks/new.html.haml3
-rw-r--r--app/views/admin/email_domain_blocks/_email_domain_block.html.haml2
-rw-r--r--app/views/admin/instances/_instance.html.haml2
-rw-r--r--app/views/admin/reports/show.html.haml6
-rw-r--r--app/views/admin/settings/edit.html.haml2
-rw-r--r--app/views/layouts/embedded.html.haml8
-rw-r--r--app/views/settings/preferences/show.html.haml2
-rw-r--r--app/views/stream_entries/_detailed_status.html.haml27
-rw-r--r--app/views/stream_entries/_simple_status.html.haml27
-rw-r--r--app/views/stream_entries/show.html.haml2
-rw-r--r--app/workers/activitypub/distribution_worker.rb2
-rw-r--r--app/workers/activitypub/reply_distribution_worker.rb6
-rw-r--r--config/environments/production.rb2
-rw-r--r--config/initializers/content_security_policy.rb1
-rw-r--r--config/initializers/doorkeeper.rb2
-rw-r--r--config/locales/ar.yml13
-rw-r--r--config/locales/ca.yml2
-rw-r--r--config/locales/co.yml16
-rw-r--r--config/locales/cs.yml30
-rw-r--r--config/locales/cy.yml33
-rw-r--r--config/locales/da.yml2
-rw-r--r--config/locales/de.yml42
-rw-r--r--config/locales/el.yml14
-rw-r--r--config/locales/en.yml9
-rw-r--r--config/locales/eo.yml2
-rw-r--r--config/locales/es.yml2
-rw-r--r--config/locales/eu.yml2
-rw-r--r--config/locales/fa.yml2
-rw-r--r--config/locales/fi.yml4
-rw-r--r--config/locales/fr.yml18
-rw-r--r--config/locales/gl.yml16
-rw-r--r--config/locales/he.yml2
-rw-r--r--config/locales/hu.yml2
-rw-r--r--config/locales/id.yml2
-rw-r--r--config/locales/io.yml2
-rw-r--r--config/locales/it.yml3
-rw-r--r--config/locales/ja.yml11
-rw-r--r--config/locales/ka.yml2
-rw-r--r--config/locales/ko.yml2
-rw-r--r--config/locales/nl.yml2
-rw-r--r--config/locales/no.yml2
-rw-r--r--config/locales/oc.yml3
-rw-r--r--config/locales/pl.yml2
-rw-r--r--config/locales/pt-BR.yml2
-rw-r--r--config/locales/pt.yml2
-rw-r--r--config/locales/ru.yml2
-rw-r--r--config/locales/simple_form.ar.yml11
-rw-r--r--config/locales/simple_form.co.yml11
-rw-r--r--config/locales/simple_form.cs.yml11
-rw-r--r--config/locales/simple_form.de.yml11
-rw-r--r--config/locales/simple_form.el.yml11
-rw-r--r--config/locales/simple_form.fa.yml11
-rw-r--r--config/locales/simple_form.fr.yml11
-rw-r--r--config/locales/simple_form.gl.yml11
-rw-r--r--config/locales/simple_form.ja.yml3
-rw-r--r--config/locales/sk.yml2
-rw-r--r--config/locales/sr-Latn.yml2
-rw-r--r--config/locales/sr.yml2
-rw-r--r--config/locales/sv.yml2
-rw-r--r--config/locales/th.yml2
-rw-r--r--config/locales/tr.yml2
-rw-r--r--config/locales/uk.yml2
-rw-r--r--config/locales/zh-CN.yml2
-rw-r--r--config/locales/zh-HK.yml2
-rw-r--r--config/locales/zh-TW.yml2
-rw-r--r--config/routes.rb7
-rw-r--r--db/migrate/20181010141500_add_silent_to_mentions.rb23
-rw-r--r--db/migrate/20181017170937_add_reject_reports_to_domain_blocks.rb17
-rw-r--r--db/migrate/20181018205649_add_unread_to_account_conversations.rb23
-rw-r--r--db/schema.rb5
-rw-r--r--docker-compose.yml17
-rw-r--r--lib/mastodon/accounts_cli.rb16
-rw-r--r--lib/mastodon/feeds_cli.rb5
-rw-r--r--lib/mastodon/version.rb4
-rw-r--r--spec/controllers/auth/sessions_controller_spec.rb2
-rw-r--r--spec/lib/activitypub/activity/create_spec.rb29
-rw-r--r--streaming/index.js99
205 files changed, 2020 insertions, 905 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 65f4e5df5..1b7f1db42 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -13,6 +13,9 @@ aliases:
           ALLOW_NOPAM: true
           CONTINUOUS_INTEGRATION: true
           DISABLE_SIMPLECOV: true
+          PAM_ENABLED: true	
+          PAM_DEFAULT_SERVICE: pam_test	
+          PAM_CONTROLLED_SERVICE: pam_test_controlled
     working_directory: ~/projects/mastodon/
 
   - &attach_workspace
diff --git a/.env.test b/.env.test
index 726351c5e..fa4e1d91f 100644
--- a/.env.test
+++ b/.env.test
@@ -3,7 +3,3 @@ NODE_ENV=test
 # Federation
 LOCAL_DOMAIN=cb6e6126.ngrok.io
 LOCAL_HTTPS=true
-# test pam authentication
-PAM_ENABLED=true
-PAM_DEFAULT_SERVICE=pam_test
-PAM_CONTROLLED_SERVICE=pam_test_controlled
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index 46602fd2c..3890729e2 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -1,11 +1,17 @@
 ---
 name: Feature Request
-about: Suggest an idea for this project
+about: I have a suggestion
 
 ---
 
-[Issue text goes here].
+<!-- Please use a concise and distinct title for the issue -->
 
-* * * *
+<!-- Consider: Could it be implemented as a 3rd party app using the REST API instead? -->
 
-- [ ] I searched or browsed the repo’s other issues to ensure this is not a duplicate.
+### Pitch
+
+<!-- Describe your idea for a feature. Make sure it has not already been suggested/implemented/turned down before -->
+
+### Motivation
+
+<!-- Why do you think this feature is needed? Who would benefit from it? -->
diff --git a/.github/ISSUE_TEMPLATE/support.md b/.github/ISSUE_TEMPLATE/support.md
new file mode 100644
index 000000000..7fbc86ff1
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/support.md
@@ -0,0 +1,10 @@
+---
+name: Support
+about: Ask for help with your deployment
+
+---
+
+We primarily use GitHub as a bug and feature tracker. For usage questions, troubleshooting of deployments and other individual technical assistance, please use one of the resources below:
+
+- https://discourse.joinmastodon.org
+- #mastodon on irc.freenode.net
diff --git a/.ruby-version b/.ruby-version
index 73462a5a1..aedc15bb0 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-2.5.1
+2.5.3
diff --git a/AUTHORS.md b/AUTHORS.md
index abcc24384..277683a00 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -5,44 +5,46 @@ and provided thanks to the work of the following contributors:
 * [ykzts](https://github.com/ykzts)
 * [akihikodaki](https://github.com/akihikodaki)
 * [mjankowski](https://github.com/mjankowski)
-* [unarist](https://github.com/unarist)
 * [ThibG](https://github.com/ThibG)
+* [unarist](https://github.com/unarist)
 * [m4sk1n](https://github.com/m4sk1n)
 * [yiskah](https://github.com/yiskah)
 * [nolanlawson](https://github.com/nolanlawson)
 * [sorin-davidoi](https://github.com/sorin-davidoi)
 * [abcang](https://github.com/abcang)
 * [lynlynlynx](https://github.com/lynlynlynx)
+* [dependabot[bot]](https://github.com/apps/dependabot)
 * [alpaca-tc](https://github.com/alpaca-tc)
 * [nclm](https://github.com/nclm)
 * [ineffyble](https://github.com/ineffyble)
 * [renatolond](https://github.com/renatolond)
 * [jeroenpraat](https://github.com/jeroenpraat)
+* [mayaeh](https://github.com/mayaeh)
 * [blackle](https://github.com/blackle)
 * [Quent-in](https://github.com/Quent-in)
 * [JantsoP](https://github.com/JantsoP)
 * [nullkal](https://github.com/nullkal)
 * [yookoala](https://github.com/yookoala)
-* [mayaeh](https://github.com/mayaeh)
 * [ysksn](https://github.com/ysksn)
 * [shuheiktgw](https://github.com/shuheiktgw)
 * [ashfurrow](https://github.com/ashfurrow)
+* [mabkenar](https://github.com/mabkenar)
 * [zunda](https://github.com/zunda)
-* [eramdam](https://github.com/eramdam)
 * [Kjwon15](https://github.com/Kjwon15)
+* [eramdam](https://github.com/eramdam)
 * [masarakki](https://github.com/masarakki)
 * [ticky](https://github.com/ticky)
+* [takayamaki](https://github.com/takayamaki)
 * [Quenty31](https://github.com/Quenty31)
 * [danhunsaker](https://github.com/danhunsaker)
 * [ThisIsMissEm](https://github.com/ThisIsMissEm)
 * [hcmiya](https://github.com/hcmiya)
 * [stephenburgess8](https://github.com/stephenburgess8)
 * [Wonderfall](https://github.com/Wonderfall)
-* [takayamaki](https://github.com/takayamaki)
 * [matteoaquila](https://github.com/matteoaquila)
 * [rkarabut](https://github.com/rkarabut)
-* [Artoria2e5](https://github.com/Artoria2e5)
 * [yukimochi](https://github.com/yukimochi)
+* [Artoria2e5](https://github.com/Artoria2e5)
 * [marrus-sh](https://github.com/marrus-sh)
 * [krainboltgreene](https://github.com/krainboltgreene)
 * [patf](https://github.com/patf)
@@ -56,7 +58,7 @@ and provided thanks to the work of the following contributors:
 * [MasterGroosha](https://github.com/MasterGroosha)
 * [JeanGauthier](https://github.com/JeanGauthier)
 * [kschaper](https://github.com/kschaper)
-* [mabkenar](https://github.com/mabkenar)
+* [MaciekBaron](https://github.com/MaciekBaron)
 * [MitarashiDango](mailto:mitarashidango@users.noreply.github.com)
 * [beatrix-bitrot](https://github.com/beatrix-bitrot)
 * [adbelle](https://github.com/adbelle)
@@ -64,9 +66,9 @@ and provided thanks to the work of the following contributors:
 * [MightyPork](https://github.com/MightyPork)
 * [yhirano55](https://github.com/yhirano55)
 * [camponez](https://github.com/camponez)
-* [MaciekBaron](https://github.com/MaciekBaron)
 * [SerCom-KC](https://github.com/SerCom-KC)
 * [aschmitz](https://github.com/aschmitz)
+* [devkral](https://github.com/devkral)
 * [fpiesche](https://github.com/fpiesche)
 * [gandaro](https://github.com/gandaro)
 * [johnsudaar](https://github.com/johnsudaar)
@@ -75,8 +77,6 @@ and provided thanks to the work of the following contributors:
 * [lindwurm](https://github.com/lindwurm)
 * [victorhck](mailto:victorhck@geeko.site)
 * [voidsatisfaction](https://github.com/voidsatisfaction)
-* [valentin2105](https://github.com/valentin2105)
-* [devkral](https://github.com/devkral)
 * [hikari-no-yume](https://github.com/hikari-no-yume)
 * [angristan](https://github.com/angristan)
 * [seefood](https://github.com/seefood)
@@ -93,6 +93,7 @@ and provided thanks to the work of the following contributors:
 * [tsuwatch](https://github.com/tsuwatch)
 * [victorhck](https://github.com/victorhck)
 * [puckipedia](https://github.com/puckipedia)
+* [fvh-P](https://github.com/fvh-P)
 * [contraexemplo](https://github.com/contraexemplo)
 * [hugogameiro](https://github.com/hugogameiro)
 * [kazu9su](https://github.com/kazu9su)
@@ -102,11 +103,11 @@ and provided thanks to the work of the following contributors:
 * [Neetshin](mailto:neetshin@neetsh.in)
 * [rainyday](https://github.com/rainyday)
 * [ProgVal](https://github.com/ProgVal)
+* [valentin2105](https://github.com/valentin2105)
 * [yuntan](https://github.com/yuntan)
 * [goofy-bz](mailto:goofy@babelzilla.org)
 * [kadiix](https://github.com/kadiix)
 * [kodacs](https://github.com/kodacs)
-* [fvh-P](https://github.com/fvh-P)
 * [rtucker](https://github.com/rtucker)
 * [KScl](https://github.com/KScl)
 * [sterdev](https://github.com/sterdev)
@@ -116,6 +117,7 @@ and provided thanks to the work of the following contributors:
 * [cpytel](https://github.com/cpytel)
 * [northerner](https://github.com/northerner)
 * [fhemberger](https://github.com/fhemberger)
+* [greysteil](https://github.com/greysteil)
 * [hnrysmth](https://github.com/hnrysmth)
 * [d6rkaiz](https://github.com/d6rkaiz)
 * [JMendyk](https://github.com/JMendyk)
@@ -125,12 +127,14 @@ and provided thanks to the work of the following contributors:
 * [reneklacan](https://github.com/reneklacan)
 * [ekiru](https://github.com/ekiru)
 * [tcitworld](https://github.com/tcitworld)
+* [ashleyhull-versent](https://github.com/ashleyhull-versent)
 * [geta6](https://github.com/geta6)
 * [happycoloredbanana](https://github.com/happycoloredbanana)
 * [leopku](https://github.com/leopku)
 * [SansPseudoFix](https://github.com/SansPseudoFix)
 * [tomfhowe](https://github.com/tomfhowe)
 * [noraworld](https://github.com/noraworld)
+* [theboss](https://github.com/theboss)
 * [178inaba](https://github.com/178inaba)
 * [alyssais](https://github.com/alyssais)
 * [kodnaplakal](https://github.com/kodnaplakal)
@@ -140,6 +144,7 @@ and provided thanks to the work of the following contributors:
 * [halkeye](https://github.com/halkeye)
 * [hinaloe](https://github.com/hinaloe)
 * [treby](https://github.com/treby)
+* [Reverite](https://github.com/Reverite)
 * [jpdevries](https://github.com/jpdevries)
 * [00x9d](https://github.com/00x9d)
 * [Kurtis Rainbolt-Greene](mailto:me@kurtisrainboltgreene.name)
@@ -147,15 +152,16 @@ and provided thanks to the work of the following contributors:
 * [nevillepark](https://github.com/nevillepark)
 * [ornithocoder](https://github.com/ornithocoder)
 * [pierreozoux](https://github.com/pierreozoux)
+* [qguv](https://github.com/qguv)
 * [Ram Lmn](mailto:ramlmn@users.noreply.github.com)
 * [harukasan](https://github.com/harukasan)
 * [stamak](https://github.com/stamak)
-* [theboss](https://github.com/theboss)
 * [Technowix](mailto:technowix@users.noreply.github.com)
 * [Eychics](https://github.com/Eychics)
 * [Thor Harald Johansen](mailto:thj@thj.no)
 * [0x70b1a5](https://github.com/0x70b1a5)
 * [gled-rs](https://github.com/gled-rs)
+* [Valentin_NC](mailto:valentin.ouvrard@nautile.sarl)
 * [R0ckweb](https://github.com/R0ckweb)
 * [caasi](https://github.com/caasi)
 * [esetomo](https://github.com/esetomo)
@@ -168,6 +174,7 @@ and provided thanks to the work of the following contributors:
 * [vahnj](https://github.com/vahnj)
 * [ikuradon](https://github.com/ikuradon)
 * [AndreLewin](https://github.com/AndreLewin)
+* [rinsuki](https://github.com/rinsuki)
 * [redtachyons](https://github.com/redtachyons)
 * [thurloat](https://github.com/thurloat)
 * [aaribaud](https://github.com/aaribaud)
@@ -188,14 +195,12 @@ and provided thanks to the work of the following contributors:
 * [Fjoerfoks](https://github.com/Fjoerfoks)
 * [fmauNeko](https://github.com/fmauNeko)
 * [gloaec](https://github.com/gloaec)
-* [greysteil](https://github.com/greysteil)
 * [unstabler](https://github.com/unstabler)
 * [potato4d](https://github.com/potato4d)
 * [h-izumi](https://github.com/h-izumi)
 * [ErikXXon](https://github.com/ErikXXon)
 * [ian-kelling](https://github.com/ian-kelling)
 * [immae](https://github.com/immae)
-* [Reverite](https://github.com/Reverite)
 * [foozmeat](https://github.com/foozmeat)
 * [jasonrhodes](https://github.com/jasonrhodes)
 * [Jason Snell](mailto:jason@newrelic.com)
@@ -232,6 +237,8 @@ and provided thanks to the work of the following contributors:
 * [zacanger](https://github.com/zacanger)
 * [amazedkoumei](https://github.com/amazedkoumei)
 * [anon5r](https://github.com/anon5r)
+* [aus-social](https://github.com/aus-social)
+* [imbsky](https://github.com/imbsky)
 * [bsky](mailto:me@imbsky.net)
 * [chr-1x](https://github.com/chr-1x)
 * [codl](https://github.com/codl)
@@ -249,12 +256,12 @@ and provided thanks to the work of the following contributors:
 * [oliverkeeble](https://github.com/oliverkeeble)
 * [pinfort](https://github.com/pinfort)
 * [rbaumert](https://github.com/rbaumert)
+* [rhoio](https://github.com/rhoio)
 * [trwnh](https://github.com/trwnh)
 * [usagi-f](https://github.com/usagi-f)
 * [vidarlee](https://github.com/vidarlee)
 * [vjackson725](https://github.com/vjackson725)
 * [wxcafe](https://github.com/wxcafe)
-* [rinsuki](https://github.com/rinsuki)
 * [新都心(Neet Shin)](mailto:nucx@dio-vox.com)
 * [cygnan](https://github.com/cygnan)
 * [Awea](https://github.com/Awea)
@@ -282,6 +289,7 @@ and provided thanks to the work of the following contributors:
 * [ameliavoncat](https://github.com/ameliavoncat)
 * [ilpianista](https://github.com/ilpianista)
 * [Andreas Drop](mailto:andy@remline.de)
+* [andi1984](https://github.com/andi1984)
 * [schas002](https://github.com/schas002)
 * [abackstrom](https://github.com/abackstrom)
 * [jumbosushi](https://github.com/jumbosushi)
@@ -303,8 +311,9 @@ and provided thanks to the work of the following contributors:
 * [chriswk](https://github.com/chriswk)
 * [csu](https://github.com/csu)
 * [kklleemm](https://github.com/kklleemm)
+* [colindean](https://github.com/colindean)
 * [dachinat](https://github.com/dachinat)
-* [monsterpit-daggertooth](https://github.com/monsterpit-daggertooth)
+* [multiple-creatures](https://github.com/multiple-creatures)
 * [watilde](https://github.com/watilde)
 * [daprice](https://github.com/daprice)
 * [dar5hak](https://github.com/dar5hak)
@@ -328,14 +337,17 @@ and provided thanks to the work of the following contributors:
 * [espenronnevik](https://github.com/espenronnevik)
 * [Finariel](https://github.com/Finariel)
 * [siuying](https://github.com/siuying)
+* [GenbuHase](https://github.com/GenbuHase)
 * [hattori6789](https://github.com/hattori6789)
 * [algernon](https://github.com/algernon)
 * [Fastbyte01](https://github.com/Fastbyte01)
+* [Gomasy](https://github.com/Gomasy)
 * [myfreeweb](https://github.com/myfreeweb)
 * [gfaivre](https://github.com/gfaivre)
 * [Fiaxhs](https://github.com/Fiaxhs)
 * [reedcourty](https://github.com/reedcourty)
 * [anneau](https://github.com/anneau)
+* [lanodan](https://github.com/lanodan)
 * [Harmon758](https://github.com/Harmon758)
 * [HellPie](https://github.com/HellPie)
 * [Habu-Kagumba](https://github.com/Habu-Kagumba)
@@ -360,6 +372,7 @@ and provided thanks to the work of the following contributors:
 * [jguerder](https://github.com/jguerder)
 * [Jehops](https://github.com/Jehops)
 * [joshuap](https://github.com/joshuap)
+* [YuleZ](https://github.com/YuleZ)
 * [Tiwy57](https://github.com/Tiwy57)
 * [xuv](https://github.com/xuv)
 * [Jnsll](https://github.com/Jnsll)
@@ -388,6 +401,7 @@ and provided thanks to the work of the following contributors:
 * [otsune](https://github.com/otsune)
 * [Mathias B](mailto:10813340+mathias-b@users.noreply.github.com)
 * [matt-auckland](https://github.com/matt-auckland)
+* [webroo](https://github.com/webroo)
 * [matthiasbeyer](https://github.com/matthiasbeyer)
 * [mattjmattj](https://github.com/mattjmattj)
 * [mtparet](https://github.com/mtparet)
@@ -400,6 +414,7 @@ and provided thanks to the work of the following contributors:
 * [mike-burns](https://github.com/mike-burns)
 * [verymilan](https://github.com/verymilan)
 * [milmazz](https://github.com/milmazz)
+* [premist](https://github.com/premist)
 * [Mnkai](https://github.com/Mnkai)
 * [mitchhentges](https://github.com/mitchhentges)
 * [moritzheiber](https://github.com/moritzheiber)
@@ -413,7 +428,7 @@ and provided thanks to the work of the following contributors:
 * [vonneudeck](https://github.com/vonneudeck)
 * [Ninetailed](https://github.com/Ninetailed)
 * [k24](https://github.com/k24)
-* [Noiob](mailto:noiob@users.noreply.github.com)
+* [noiob](https://github.com/noiob)
 * [kwaio](https://github.com/kwaio)
 * [norayr](https://github.com/norayr)
 * [joyeusenoelle](https://github.com/joyeusenoelle)
@@ -425,7 +440,6 @@ and provided thanks to the work of the following contributors:
 * [Pangoraw](https://github.com/Pangoraw)
 * [peterkeen](https://github.com/peterkeen)
 * [pgate](https://github.com/pgate)
-* [qguv](https://github.com/qguv)
 * [remram44](https://github.com/remram44)
 * [retokromer](https://github.com/retokromer)
 * [rfwatson](https://github.com/rfwatson)
@@ -436,6 +450,7 @@ and provided thanks to the work of the following contributors:
 * [staticsafe](https://github.com/staticsafe)
 * [snwh](https://github.com/snwh)
 * [sts10](https://github.com/sts10)
+* [sascha-sl](https://github.com/sascha-sl)
 * [skoji](https://github.com/skoji)
 * [ScienJus](https://github.com/ScienJus)
 * [larkinscott](https://github.com/larkinscott)
@@ -450,20 +465,20 @@ and provided thanks to the work of the following contributors:
 * [Sina Mashek](mailto:sina@mashek.xyz)
 * [sossii](https://github.com/sossii)
 * [SpankyWorks](https://github.com/SpankyWorks)
-* [StefOfficiel](https://github.com/StefOfficiel)
-* [svetlik](https://github.com/svetlik)
-* [dereckson](https://github.com/dereckson)
-* [phaedryx](https://github.com/phaedryx)
-* [takp](https://github.com/takp)
-* [tkusano](https://github.com/tkusano)
-* [TakesxiSximada](https://github.com/TakesxiSximada)
-* [TheInventrix](https://github.com/TheInventrix)
-* [shug0](https://github.com/shug0)
-* [Fortyseven](https://github.com/Fortyseven)
-* [tobypinder](https://github.com/tobypinder)
-* [tomosm](https://github.com/tomosm)
-* [TomoyaShibata](https://github.com/TomoyaShibata)
-* [treyssatvincent](https://github.com/treyssatvincent)
+* [StefOfficiel](mailto:pichard.stephane@free.fr)
+* [Svetlozar Todorov](mailto:svetlik@users.noreply.github.com)
+* [Sébastien Santoro](mailto:dereckson@espace-win.org)
+* [Tad Thorley](mailto:phaedryx@users.noreply.github.com)
+* [Takayoshi Nishida](mailto:takayoshi.nishida@gmail.com)
+* [Takayuki KUSANO](mailto:github@tkusano.jp)
+* [TakesxiSximada](mailto:takesxi.sximada@gmail.com)
+* [TheInventrix](mailto:theinventrix@users.noreply.github.com)
+* [Thomas Alberola](mailto:thomas@needacoffee.fr)
+* [Toby Deshane](mailto:fortyseven@users.noreply.github.com)
+* [Toby Pinder](mailto:gigitrix@gmail.com)
+* [Tomonori Murakami](mailto:crosslife777@gmail.com)
+* [TomoyaShibata](mailto:wind.of.hometown@gmail.com)
+* [Treyssat-Vincent Nino](mailto:treyssatvincent@users.noreply.github.com)
 * [Udo Kramer](mailto:optik@fluffel.io)
 * [Una](mailto:una@unascribed.com)
 * [Ushitora Anqou](mailto:ushitora_anqou@yahoo.co.jp)
@@ -489,6 +504,7 @@ and provided thanks to the work of the following contributors:
 * [benklop](mailto:benklop@gmail.com)
 * [bsky](mailto:git@imbsky.net)
 * [caesarologia](mailto:lopesgemelli.1@gmail.com)
+* [cbayerlein](mailto:c.bayerlein@gmail.com)
 * [chrolis](mailto:chrolis@users.noreply.github.com)
 * [cormo](mailto:cormorant2+github@gmail.com)
 * [d0p1](mailto:dopi-sama@hush.com)
@@ -500,19 +516,23 @@ and provided thanks to the work of the following contributors:
 * [hakoai](mailto:hk--76@qa2.so-net.ne.jp)
 * [haosbvnker](mailto:github@chaosbunker.com)
 * [isati](mailto:phil@juchnowi.cz)
+* [jacob](mailto:jacobherringtondeveloper@gmail.com)
 * [jenn kaplan](mailto:me@jkap.io)
 * [jirayudech](mailto:jirayudech@gmail.com)
+* [jooops](mailto:joops@autistici.org)
 * [jukper](mailto:jukkaperanto@gmail.com)
 * [jumoru](mailto:jumoru@mailbox.org)
 * [karlyeurl](mailto:karl.yeurl@gmail.com)
 * [kedama](mailto:32974885+kedamadq@users.noreply.github.com)
 * [kuro5hin](mailto:rusty@kuro5hin.org)
+* [luzpaz](mailto:luzpaz@users.noreply.github.com)
 * [maxypy](mailto:maxime@mpigou.fr)
 * [mhe](mailto:mail@marcus-herrmann.com)
 * [mimikun](mailto:dzdzble_effort_311@outlook.jp)
 * [mshrtkch](mailto:mshrtkch@users.noreply.github.com)
 * [muan](mailto:muan@github.com)
 * [neetshin](mailto:neetshin@neetsh.in)
+* [nightpool](mailto:nightpool@users.noreply.github.com)
 * [rch850](mailto:rich850@gmail.com)
 * [roikale](mailto:roikale@users.noreply.github.com)
 * [rysiekpl](mailto:rysiek@hackerspace.pl)
@@ -524,6 +544,7 @@ and provided thanks to the work of the following contributors:
 * [tackeyy](mailto:mailto.takita.yusuke@gmail.com)
 * [tateisu](mailto:tateisu@gmail.com)
 * [tmyt](mailto:shigure@refy.net)
+* [trevDev()](mailto:trev@trevdev.ca)
 * [utam0k](mailto:k0ma@utam0k.jp)
 * [vpzomtrrfrt](mailto:vpzomtrrfrt@gmail.com)
 * [walfie](mailto:walfington@gmail.com)
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 000000000..666ccd14b
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,107 @@
+Changelog
+=========
+
+All notable changes to this project will be documented in this file.
+
+## [Unreleased]
+### Added
+
+- Add link ownership verification (#8703)
+- Add conversations API (#8832)
+- Add limit for the number of people that can be followed from one account (#8807)
+- Add admin setting to customize mascot (#8766)
+- Add support for more granular ActivityPub audiences from other software, i.e. circles (#8950)
+- Add option to block all reports from a domain (#8830)
+- Add user preference to always expand toots marked with content warnings (#8762)
+- Add user preference to always hide all media (#8569)
+- Add `force_login` param to OAuth authorize page (#8655)
+- Add `tootctl accounts backup` (#8642, #8811)
+- Add `tootctl accounts create` (#8642, #8811)
+- Add `tootctl accounts cull` (#8642, #8811)
+- Add `tootctl accounts delete` (#8642, #8811)
+- Add `tootctl accounts modify` (#8642, #8811)
+- Add `tootctl accounts refresh` (#8642, #8811)
+- Add `tootctl feeds build` (#8642, #8811)
+- Add `tootctl feeds clear` (#8642, #8811)
+- Add `tootctl settings registrations open` (#8642, #8811)
+- Add `tootctl settings registrations close` (#8642, #8811)
+- Add `min_id` param to REST API to support backwards pagination (#8736)
+- Add a confirmation dialog when hitting reply and the compose box isn't empty (#8893)
+- Add PostgreSQL disk space growth tracking in PGHero (#8906)
+- Add button for disabling local account to report quick actions bar (#9024)
+- Add Czech language (#8594)
+- Add `Clear-Site-Data` header when logging out (#8627)
+- Add `same-site` (`lax`) attribute to cookies (#8626)
+- Add support for styled scrollbars in Firefox Nightly (#8653)
+- Add highlight to the active tab in web UI profiles (#8673)
+- Add auto-focus for comment textarea in report modal (#8689)
+- Add auto-focus for emoji picker's search field (#8688)
+- Add nginx and systemd templates to `dist/` directory (#8770)
+- Add support for `/.well-known/change-password` (#8828)
+- Add option to override FFMPEG binary path (#8855)
+- Add `dns-prefetch` tag when using different host for assets or uploads (#8942)
+- Add `description` meta tag (#8941)
+- Add `Content-Security-Policy` header (#8957)
+- Add cache for the instance info API (#8765)
+
+### Changed
+
+- Change forms design (#8703)
+- Change reports overview to group by target account (#8674)
+- Change web UI to show "read more" link on overly long in-stream statuses (#8205)
+- Change design of direct messages column (#8832, #9022)
+- Change home timelines to exclude DMs (#8940)
+- Change list timelines to exclude all replies (#8683)
+- Change admin accounts UI default sort to most recent (#8813)
+- Change documentation URL in the UI (#8898)
+- Change style of success and failure messages (#8973)
+- Change DM filtering to always allow DMs from staff (#8993)
+- Change recommended Ruby version to 2.5.3 (#9003)
+
+### Deprecated
+
+- `GET /api/v1/timelines/direct` → `GET /api/v1/conversations` (#8832)
+- `POST /api/v1/notifications/dismiss` → `POST /api/v1/notifications/:id/dismiss` (#8905)
+
+### Removed
+
+- Remove "on this device" label in column push settings (#8704)
+- Remove rake tasks in favour of tootctl commands (#8675)
+
+### Fixed
+
+- Fix remote statuses using instance's default locale if no language given (#8861)
+- Fix streaming API not exiting when port or socket is unavailable (#9023)
+- Fix network calls being performed in database transaction in ActivityPub handler (#8951)
+- Fix dropdown arrow position (#8637)
+- Fix first element of dropdowns being focused even if not using keyboard (#8679)
+- Fix tootctl requiring `bundle exec` invocation (#8619)
+- Fix public pages not using animation preference for avatars (#8614)
+- Fix OEmbed/OpenGraph cards not understanding relative URLs (#8669)
+- Fix some dark emojis not having a white outline (#8597)
+- Fix media description not being displayed in various media modals (#8678)
+- Fix generated URLs of desktop notifications missing base URL (#8758)
+- Fix RTL styles (#8764, #8767, #8823, #8897, #9005, #9007, #9018, #9021)
+- Fix crash in streaming API when tag param missing (#8955)
+- Fix hotkeys not working when no element is focused (#8998)
+- Fix some hotkeys not working on detailed status view (#9006)
+
+## [2.5.2] - 2018-10-12
+### Security
+
+- Fix XSS vulnerability (#8959)
+
+## [2.5.1] - 2018-10-07
+### Fixed
+
+- Fix database migrations for PostgreSQL below 9.5 (#8903)
+- Fix class autoloading issue in ActivityPub Create handler (#8820)
+- Fix cache statistics not being sent via statsd when statsd enabled (#8831)
+- Bump puma from 3.11.4 to 3.12.0 (#8883)
+
+### Security
+
+- Fix some local images not having their EXIF metadata stripped on upload (#8714)
+- Fix being able to enable a disabled relay via ActivityPub Accept handler (#8864)
+- Bump nokogiri from 1.8.4 to 1.8.5 (#8881)
+- Fix being able to report statuses not belonging to the reported account (#8916)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ddf303103..8044d04f7 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -32,60 +32,42 @@ You should also try to follow the guidelines set out in the original `CONTRIBUTI
 <blockquote>
 
 CONTRIBUTING
-============
+=======
+Contributing
 
-There are three ways in which you can contribute to this repository:
+Thank you for considering contributing to Mastodon 🐘 
 
-1. By improving the documentation
-2. By working on the back-end application
-3. By working on the front-end application
+You can contribute in the following ways:
 
-Choosing what to work on in a large open source project is not easy. The list of [GitHub issues](https://github.com/tootsuite/mastodon/issues) may provide some ideas, but not every feature request has been greenlit. Likewise, not every change or feature that resolves a personal itch will be merged into the main repository. Some communication ahead of time may be wise. If your addition creates a new feature or setting, or otherwise changes how things work in some substantial way, please remember to submit a correlating pull request to document your changes in the [documentation](http://github.com/tootsuite/documentation).
+- Finding and reporting bugs
+- Translating the Mastodon interface into various languages
+- Contributing code to Mastodon by fixing bugs or implementing features
+- Improving the documentation
 
-Below are the guidelines for working on pull requests:
+## Bug reports
 
-## General
+Bug reports and feature suggestions can be submitted to [GitHub Issues](https://github.com/tootsuite/mastodon/issues). Please make sure that you are not submitting duplicates, and that a similar report or request has not already been resolved or rejected in the past using the search function. Please also use descriptive, concise titles.
 
-- 2 spaces indentation
+## Translations
 
-## Documentation
-
-- No spelling mistakes
-- No orthographic mistakes
-- No Markdown syntax errors
-
-## Requirements
-
-- Ruby
-- Node.js
-- PostgreSQL
-- Redis
-- Nginx (optional)
-
-## Back-end application
+You can submit translations via [Weblate](https://weblate.joinmastodon.org/). They are periodically merged into the codebase.
 
-It is expected that you have a working development environment set up. The development environment includes [rubocop](https://github.com/bbatsov/rubocop), which checks your Ruby code for compliance with our style guide and best practices. Sublime Text, likely like other editors, has a [Rubocop plugin](https://github.com/pderichs/sublime_rubocop) that runs checks on files as you edit them. The codebase also has a test suite.
-
-* The codebase is not perfect, at the time of writing, but it is expected that you do not introduce new code style violations
-* The rspec test suite must pass
-* To the extent that it is possible, verify your changes. In the best case, by adding new tests to the test suite. At the very least, by running the server or console and checking it manually
-* If you are introducing new strings to the user interface, they must be using localization methods
+[![Mastodon translation statistics by language](https://weblate.joinmastodon.org/widgets/mastodon/-/multi-auto.svg)](https://weblate.joinmastodon.org/)
 
-If your code has syntax errors that won't let it run, it's a good sign that the pull request isn't ready for submission yet.
+## Pull requests
 
-## Front-end application
+Please use clean, concise titles for your pull requests. We use commit squashing, so the final commit in the master branch will carry the title of the pull request.
 
-It is expected that you have a working development environment set up (see back-end application section). This project includes an ESLint configuration file, with which you can lint your changes.
+The smaller the set of changes in the pull request is, the quicker it can be reviewed and merged. Splitting tasks into multiple smaller pull requests is often preferable.
 
-* Avoid grave ESLint violations
-* Verify that your changes work
-* If you are introducing new strings, they must be using localization methods
+**Pull requests that do not pass automated checks may not be reviewed**. In particular, you need to keep in mind:
 
-If the JavaScript or CSS assets won't compile due to a syntax error, it's a good sign that the pull request isn't ready for submission yet.
+- Unit and integration tests (rspec, jest)
+- Code style rules (rubocop, eslint)
+- Normalization of locale files (i18n-tasks)
 
-## Translate
+## Documentation
 
-You can contribute to translating Mastodon via Weblate at [weblate.joinmastodon.org](https://weblate.joinmastodon.org/).
-[![Mastodon translation statistics by language](https://weblate.joinmastodon.org/widgets/mastodon/-/multi-auto.svg)](https://weblate.joinmastodon.org/)
+The [Mastodon documentation](https://docs.joinmastodon.org) is a statically generated site. You can [submit merge requests to mastodon/docs](https://source.joinmastodon.org/mastodon/docs).
 
 </blockquote>
diff --git a/Dockerfile b/Dockerfile
index bdc10c4ab..3e54b6555 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
 FROM node:8.12.0-alpine as node
-FROM ruby:2.4.4-alpine3.7
+FROM ruby:2.4.5-alpine3.8
 
 LABEL maintainer="https://github.com/tootsuite/mastodon" \
       description="Your self-hosted, globally interconnected microblogging community"
diff --git a/Gemfile b/Gemfile
index b417a8d2e..ee9b746a6 100644
--- a/Gemfile
+++ b/Gemfile
@@ -16,8 +16,8 @@ gem 'pghero', '~> 2.2'
 gem 'dotenv-rails', '~> 2.5'
 
 gem 'aws-sdk-s3', '~> 1.21', require: false
-gem 'fog-core', '~> 2.1'
-gem 'fog-openstack', '~> 1.0', require: false
+gem 'fog-core', '<= 2.1.0'
+gem 'fog-openstack', '~> 0.3', require: false
 gem 'paperclip', '~> 6.0'
 gem 'paperclip-av-transcoder', '~> 0.6'
 gem 'streamio-ffmpeg', '~> 3.0'
@@ -64,7 +64,7 @@ gem 'oj', '~> 3.6'
 gem 'ostatus2', '~> 2.0'
 gem 'ox', '~> 2.10'
 gem 'posix-spawn', git: 'https://github.com/rtomayko/posix-spawn', ref: '58465d2e213991f8afb13b984854a49fcdcc980c'
-gem 'pundit', '~> 1.1'
+gem 'pundit', '~> 2.0'
 gem 'premailer-rails'
 gem 'rack-attack', '~> 5.4'
 gem 'rack-cors', '~> 1.0', require: 'rack/cors'
@@ -82,7 +82,7 @@ gem 'simple-navigation', '~> 4.0'
 gem 'simple_form', '~> 4.0'
 gem 'sprockets-rails', '~> 3.2', require: 'sprockets/railtie'
 gem 'stoplight', '~> 2.1.3'
-gem 'strong_migrations', '~> 0.2'
+gem 'strong_migrations', '~> 0.3'
 gem 'tty-command', '~> 0.8', require: false
 gem 'tty-prompt', '~> 0.17', require: false
 gem 'twitter-text', '~> 1.14'
@@ -115,7 +115,7 @@ group :test do
   gem 'rspec-sidekiq', '~> 3.0'
   gem 'simplecov', '~> 0.16', require: false
   gem 'webmock', '~> 3.4'
-  gem 'parallel_tests', '~> 2.23'
+  gem 'parallel_tests', '~> 2.24'
 end
 
 group :development do
diff --git a/Gemfile.lock b/Gemfile.lock
index 13c1127b0..283a6c25d 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -182,7 +182,7 @@ GEM
     docile (1.3.0)
     domain_name (0.5.20180417)
       unf (>= 0.0.5, < 1.0.0)
-    doorkeeper (5.0.0)
+    doorkeeper (5.0.1)
       railties (>= 4.2)
     dotenv (2.5.0)
     dotenv-rails (2.5.0)
@@ -211,7 +211,7 @@ GEM
     fast_blank (1.0.0)
     fastimage (2.1.4)
     ffi (1.9.25)
-    fog-core (2.1.2)
+    fog-core (2.1.0)
       builder
       excon (~> 0.58)
       formatador (~> 0.2)
@@ -219,8 +219,8 @@ GEM
     fog-json (1.2.0)
       fog-core
       multi_json (~> 1.10)
-    fog-openstack (1.0.3)
-      fog-core (~> 2.1)
+    fog-openstack (0.3.7)
+      fog-core (>= 1.45, <= 2.1.0)
       fog-json (>= 1.0)
       ipaddress (>= 0.8)
     formatador (0.2.5)
@@ -271,7 +271,7 @@ GEM
     httplog (1.1.1)
       rack (>= 1.0)
       rainbow (>= 2.0.0)
-    i18n (1.1.0)
+    i18n (1.1.1)
       concurrent-ruby (~> 1.0)
     i18n-tasks (0.9.25)
       activesupport (>= 4.0.2)
@@ -360,7 +360,7 @@ GEM
       concurrent-ruby (~> 1.0.0)
       sidekiq (>= 3.5.0)
       statsd-ruby (~> 1.2.0)
-    oj (3.6.11)
+    oj (3.6.12)
     omniauth (1.8.1)
       hashie (>= 3.4.6, < 3.6.0)
       rack (>= 1.6.2, < 3)
@@ -387,7 +387,7 @@ GEM
       av (~> 0.9.0)
       paperclip (>= 2.5.2)
     parallel (1.12.1)
-    parallel_tests (2.23.0)
+    parallel_tests (2.24.0)
       parallel
     parser (2.5.1.2)
       ast (~> 2.4.0)
@@ -417,7 +417,7 @@ GEM
       pry (>= 0.10.4)
     public_suffix (3.0.3)
     puma (3.12.0)
-    pundit (1.1.0)
+    pundit (2.0.0)
       activesupport (>= 3.0.0)
     raabro (1.1.6)
     rack (2.0.5)
@@ -587,7 +587,7 @@ GEM
     stoplight (2.1.3)
     streamio-ffmpeg (3.0.2)
       multi_json (~> 1.8)
-    strong_migrations (0.2.3)
+    strong_migrations (0.3.1)
       activerecord (>= 3.2.0)
     temple (0.8.0)
     terminal-table (1.8.0)
@@ -618,7 +618,7 @@ GEM
       unf (~> 0.1.0)
     tzinfo (1.2.5)
       thread_safe (~> 0.1)
-    tzinfo-data (1.2018.5)
+    tzinfo-data (1.2018.6)
       tzinfo (>= 1.0.0)
     unf (0.1.4)
       unf_ext
@@ -680,8 +680,8 @@ DEPENDENCIES
   faker (~> 1.9)
   fast_blank (~> 1.0)
   fastimage
-  fog-core (~> 2.1)
-  fog-openstack (~> 1.0)
+  fog-core (<= 2.1.0)
+  fog-openstack (~> 0.3)
   fuubar (~> 2.3)
   goldfinger (~> 2.1)
   hamlit-rails (~> 0.2)
@@ -717,7 +717,7 @@ DEPENDENCIES
   ox (~> 2.10)
   paperclip (~> 6.0)
   paperclip-av-transcoder (~> 0.6)
-  parallel_tests (~> 2.23)
+  parallel_tests (~> 2.24)
   pg (~> 1.1)
   pghero (~> 2.2)
   pkg-config (~> 1.3)
@@ -727,7 +727,7 @@ DEPENDENCIES
   pry-byebug (~> 3.6)
   pry-rails (~> 0.3)
   puma (~> 3.12)
-  pundit (~> 1.1)
+  pundit (~> 2.0)
   rack-attack (~> 5.4)
   rack-cors (~> 1.0)
   rails (~> 5.2.1)
@@ -755,7 +755,7 @@ DEPENDENCIES
   stackprof
   stoplight (~> 2.1.3)
   streamio-ffmpeg (~> 3.0)
-  strong_migrations (~> 0.2)
+  strong_migrations (~> 0.3)
   thor (~> 0.20)
   tty-command (~> 0.8)
   tty-prompt (~> 0.17)
@@ -766,7 +766,7 @@ DEPENDENCIES
   webpush
 
 RUBY VERSION
-   ruby 2.5.0p0
+   ruby 2.5.3p105
 
 BUNDLED WITH
-   1.16.5
+   1.16.6
diff --git a/app/controllers/admin/domain_blocks_controller.rb b/app/controllers/admin/domain_blocks_controller.rb
index 64de2cbf0..90c70275a 100644
--- a/app/controllers/admin/domain_blocks_controller.rb
+++ b/app/controllers/admin/domain_blocks_controller.rb
@@ -46,7 +46,7 @@ module Admin
     end
 
     def resource_params
-      params.require(:domain_block).permit(:domain, :severity, :reject_media, :retroactive)
+      params.require(:domain_block).permit(:domain, :severity, :reject_media, :reject_reports, :retroactive)
     end
 
     def retroactive_unblock?
diff --git a/app/controllers/admin/reports_controller.rb b/app/controllers/admin/reports_controller.rb
index 5d7f43e00..e97ddb9b6 100644
--- a/app/controllers/admin/reports_controller.rb
+++ b/app/controllers/admin/reports_controller.rb
@@ -44,6 +44,14 @@ module Admin
       when 'resolve'
         @report.resolve!(current_account)
         log_action :resolve, @report
+      when 'disable'
+        @report.resolve!(current_account)
+        @report.target_account.user.disable!
+
+        log_action :resolve, @report
+        log_action :disable, @report.target_account.user
+
+        resolve_all_target_account_reports
       when 'silence'
         @report.resolve!(current_account)
         @report.target_account.update!(silenced: true)
@@ -55,6 +63,7 @@ module Admin
       else
         raise ActiveRecord::RecordNotFound
       end
+
       @report.reload
     end
 
diff --git a/app/controllers/api/v1/conversations_controller.rb b/app/controllers/api/v1/conversations_controller.rb
index 736cb21ca..b19f27ebf 100644
--- a/app/controllers/api/v1/conversations_controller.rb
+++ b/app/controllers/api/v1/conversations_controller.rb
@@ -3,9 +3,11 @@
 class Api::V1::ConversationsController < Api::BaseController
   LIMIT = 20
 
-  before_action -> { doorkeeper_authorize! :read, :'read:statuses' }
+  before_action -> { doorkeeper_authorize! :read, :'read:statuses' }, only: :index
+  before_action -> { doorkeeper_authorize! :write, :'write:conversations' }, except: :index
   before_action :require_user!
-  after_action :insert_pagination_headers
+  before_action :set_conversation, except: :index
+  after_action :insert_pagination_headers, only: :index
 
   respond_to :json
 
@@ -14,8 +16,22 @@ class Api::V1::ConversationsController < Api::BaseController
     render json: @conversations, each_serializer: REST::ConversationSerializer
   end
 
+  def read
+    @conversation.update!(unread: false)
+    render json: @conversation, serializer: REST::ConversationSerializer
+  end
+
+  def destroy
+    @conversation.destroy!
+    render_empty
+  end
+
   private
 
+  def set_conversation
+    @conversation = AccountConversation.where(account: current_account).find(params[:id])
+  end
+
   def paginated_conversations
     AccountConversation.where(account: current_account)
                        .paginate_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
diff --git a/app/controllers/api/v1/reports_controller.rb b/app/controllers/api/v1/reports_controller.rb
index 726817927..e182a9c6c 100644
--- a/app/controllers/api/v1/reports_controller.rb
+++ b/app/controllers/api/v1/reports_controller.rb
@@ -1,7 +1,6 @@
 # frozen_string_literal: true
 
 class Api::V1::ReportsController < Api::BaseController
-  before_action -> { doorkeeper_authorize! :read, :'read:reports' }, except: [:create]
   before_action -> { doorkeeper_authorize! :write, :'write:reports' }, only: [:create]
   before_action :require_user!
 
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index e9b48fa98..5e7fdffb0 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -84,7 +84,7 @@ module ApplicationHelper
   end
 
   def cdn_host
-    ENV['CDN_HOST'].presence
+    Rails.configuration.action_controller.asset_host
   end
 
   def cdn_host?
@@ -92,10 +92,10 @@ module ApplicationHelper
   end
 
   def storage_host
-    ENV['S3_ALIAS_HOST'].presence || ENV['S3_CLOUDFRONT_HOST'].presence
+    "https://#{ENV['S3_ALIAS_HOST'].presence || ENV['S3_CLOUDFRONT_HOST']}"
   end
 
   def storage_host?
-    storage_host.present?
+    ENV['S3_ALIAS_HOST'].present? || ENV['S3_CLOUDFRONT_HOST'].present?
   end
 end
diff --git a/app/javascript/core/admin.js b/app/javascript/core/admin.js
index 0c26dc18d..3f6f187bc 100644
--- a/app/javascript/core/admin.js
+++ b/app/javascript/core/admin.js
@@ -2,18 +2,6 @@
 
 import { delegate } from 'rails-ujs';
 
-function handleDeleteStatus(event) {
-  const [data] = event.detail;
-  const element = document.querySelector(`[data-id="${data.id}"]`);
-  if (element) {
-    element.parentNode.removeChild(element);
-  }
-}
-
-[].forEach.call(document.querySelectorAll('.trash-button'), (content) => {
-  content.addEventListener('ajax:success', handleDeleteStatus);
-});
-
 const batchCheckboxClassName = '.batch-checkbox input[type="checkbox"]';
 
 delegate(document, '#batch_checkbox_all', 'change', ({ target }) => {
@@ -24,6 +12,7 @@ delegate(document, '#batch_checkbox_all', 'change', ({ target }) => {
 
 delegate(document, batchCheckboxClassName, 'change', () => {
   const checkAllElement = document.querySelector('#batch_checkbox_all');
+
   if (checkAllElement) {
     checkAllElement.checked = [].every.call(document.querySelectorAll(batchCheckboxClassName), (content) => content.checked);
     checkAllElement.indeterminate = !checkAllElement.checked && [].some.call(document.querySelectorAll(batchCheckboxClassName), (content) => content.checked);
@@ -43,8 +32,14 @@ delegate(document, '.media-spoiler-hide-button', 'click', () => {
 });
 
 delegate(document, '#domain_block_severity', 'change', ({ target }) => {
-  const rejectMediaDiv = document.querySelector('.input.with_label.domain_block_reject_media');
+  const rejectMediaDiv   = document.querySelector('.input.with_label.domain_block_reject_media');
+  const rejectReportsDiv = document.querySelector('.input.with_label.domain_block_reject_reports');
+
   if (rejectMediaDiv) {
     rejectMediaDiv.style.display = (target.value === 'suspend') ? 'none' : 'block';
   }
+
+  if (rejectReportsDiv) {
+    rejectReportsDiv.style.display = (target.value === 'suspend') ? 'none' : 'block';
+  }
 });
diff --git a/app/javascript/flavours/glitch/components/display_name.js b/app/javascript/flavours/glitch/components/display_name.js
index 4c65aaefa..d6ac4907d 100644
--- a/app/javascript/flavours/glitch/components/display_name.js
+++ b/app/javascript/flavours/glitch/components/display_name.js
@@ -15,7 +15,7 @@ export default function DisplayName ({
   //  The result.
   return account ? (
     <span className={computedClass}>
-      <strong className='display-name__html' dangerouslySetInnerHTML={{ __html: account.get('display_name_html') }} />
+      <bdi><strong className='display-name__html' dangerouslySetInnerHTML={{ __html: account.get('display_name_html') }} /></bdi>
       {inline ? ' ' : null}
       <span className='display-name__account'>@{account.get('acct')}</span>
     </span>
diff --git a/app/javascript/flavours/glitch/features/account_timeline/components/moved_note.js b/app/javascript/flavours/glitch/features/account_timeline/components/moved_note.js
index 1c0e081cc..280389bba 100644
--- a/app/javascript/flavours/glitch/features/account_timeline/components/moved_note.js
+++ b/app/javascript/flavours/glitch/features/account_timeline/components/moved_note.js
@@ -34,7 +34,7 @@ export default class MovedNote extends ImmutablePureComponent {
       <div className='account__moved-note'>
         <div className='account__moved-note__message'>
           <div className='account__moved-note__icon-wrapper'><i className='fa fa-fw fa-suitcase account__moved-note__icon' /></div>
-          <FormattedMessage id='account.moved_to' defaultMessage='{name} has moved to:' values={{ name: <strong dangerouslySetInnerHTML={displayNameHtml} /> }} />
+          <FormattedMessage id='account.moved_to' defaultMessage='{name} has moved to:' values={{ name: <bdi><strong dangerouslySetInnerHTML={displayNameHtml} /></bdi> }} />
         </div>
 
         <a href={to.get('url')} onClick={this.handleAccountClick} className='detailed-status__display-name'>
diff --git a/app/javascript/flavours/glitch/features/composer/options/dropdown/index.js b/app/javascript/flavours/glitch/features/composer/options/dropdown/index.js
index 8cfbac1bb..7817cc964 100644
--- a/app/javascript/flavours/glitch/features/composer/options/dropdown/index.js
+++ b/app/javascript/flavours/glitch/features/composer/options/dropdown/index.js
@@ -131,7 +131,7 @@ export default class ComposerOptionsDropdown extends React.PureComponent {
     this.state = {
       needsModalUpdate: false,
       open: false,
-      placement: null,
+      placement: 'bottom',
     };
   }
 
diff --git a/app/javascript/flavours/glitch/features/notifications/components/follow.js b/app/javascript/flavours/glitch/features/notifications/components/follow.js
index 54506f67c..ea81d9ab4 100644
--- a/app/javascript/flavours/glitch/features/notifications/components/follow.js
+++ b/app/javascript/flavours/glitch/features/notifications/components/follow.js
@@ -63,13 +63,13 @@ export default class NotificationFollow extends ImmutablePureComponent {
     //  Links to the display name.
     const displayName = account.get('display_name_html') || account.get('username');
     const link = (
-      <Permalink
+      <bdi><Permalink
         className='notification__display-name'
         href={account.get('url')}
         title={account.get('acct')}
         to={`/accounts/${account.get('id')}`}
         dangerouslySetInnerHTML={{ __html: displayName }}
-      />
+      /></bdi>
     );
 
     //  Renders.
diff --git a/app/javascript/flavours/glitch/styles/forms.scss b/app/javascript/flavours/glitch/styles/forms.scss
index be2bf7cea..8c4c934ea 100644
--- a/app/javascript/flavours/glitch/styles/forms.scss
+++ b/app/javascript/flavours/glitch/styles/forms.scss
@@ -427,7 +427,7 @@ code {
 
     &__append {
       position: absolute;
-      right: 1px;
+      right: 3px;
       top: 1px;
       padding: 10px;
       padding-bottom: 9px;
@@ -460,9 +460,20 @@ code {
   border-radius: 4px;
   padding: 15px 10px;
   margin-bottom: 30px;
-  box-shadow: 0 0 5px rgba($base-shadow-color, 0.2);
   text-align: center;
 
+  &.notice {
+    border: 1px solid rgba($valid-value-color, 0.5);
+    background: rgba($valid-value-color, 0.25);
+    color: $valid-value-color;
+  }
+
+  &.alert {
+    border: 1px solid rgba($error-value-color, 0.5);
+    background: rgba($error-value-color, 0.25);
+    color: $error-value-color;
+  }
+
   p {
     margin-bottom: 15px;
   }
@@ -551,12 +562,12 @@ code {
 .oauth-prompt,
 .follow-prompt {
   margin-bottom: 30px;
-  text-align: center;
   color: $darker-text-color;
 
   h2 {
     font-size: 16px;
     margin-bottom: 30px;
+    text-align: center;
   }
 
   strong {
diff --git a/app/javascript/flavours/glitch/styles/rtl.scss b/app/javascript/flavours/glitch/styles/rtl.scss
index 70aaa5bb1..3c775618e 100644
--- a/app/javascript/flavours/glitch/styles/rtl.scss
+++ b/app/javascript/flavours/glitch/styles/rtl.scss
@@ -73,7 +73,7 @@ body.rtl {
     float: left;
   }
 
-  .setting-toggle {
+  .setting-toggle__label {
     margin-left: 0;
     margin-right: 8px;
   }
@@ -200,6 +200,10 @@ body.rtl {
     right: -2.14285714em;
   }
 
+  .admin-wrapper {
+    direction: rtl;
+  }
+
   .admin-wrapper .sidebar ul a i.fa,
   a.table-action-link i.fa {
     margin-right: 0;
@@ -218,22 +222,47 @@ body.rtl {
     right: 0;
   }
 
+  .simple_form .input.radio_buttons .radio {
+    left: auto;
+    right: 0;
+  }
+
+  .simple_form .input.radio_buttons .radio > label {
+    padding-right: 28px;
+    padding-left: 0;
+  }
+
   .simple_form .input-with-append .input input {
     padding-left: 142px;
     padding-right: 0;
   }
 
-  .simple_form .input-with-append .append {
+  .simple_form .input.boolean label.checkbox {
+    left: auto;
+    right: 0;
+  }
+
+  .simple_form .input.boolean .label_input,
+  .simple_form .input.boolean .hint {
+    padding-left: 0;
+    padding-right: 28px;
+  }
+
+  .simple_form .label_input__append {
     right: auto;
-    left: 0;
+    left: 3px;
 
     &::after {
       right: auto;
       left: 0;
-      background-image: linear-gradient(to left, rgba($ui-base-color, 0), $ui-base-color);
+      background-image: linear-gradient(to left, rgba(darken($ui-base-color, 10%), 0), darken($ui-base-color, 10%));
     }
   }
 
+  .simple_form select {
+    background: darken($ui-base-color, 10%) url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14.933 18.467' height='19.698' width='15.929'><path d='M3.467 14.967l-3.393-3.5H14.86l-3.392 3.5c-1.866 1.925-3.666 3.5-4 3.5-.335 0-2.135-1.575-4-3.5zm.266-11.234L7.467 0 11.2 3.733l3.733 3.734H0l3.733-3.734z' fill='#{hex-color(lighten($ui-base-color, 12%))}'/></svg>") no-repeat left 8px center / auto 16px;
+  }
+
   .table th,
   .table td {
     text-align: right;
@@ -249,6 +278,10 @@ body.rtl {
     left: auto;
   }
 
+  .landing-page__call-to-action .row__information-board {
+    direction: rtl;
+  }
+
   .landing-page .header .hero .floats .float-1 {
     left: -120px;
     right: auto;
@@ -312,4 +345,22 @@ body.rtl {
       margin-right: 20px;
     }
   }
+
+  .landing-page__information {
+    .account__display-name {
+      margin-right: 0;
+      margin-left: 5px;
+    }
+
+    .account__avatar-wrapper {
+      margin-left: 12px;
+      margin-right: 0;
+    }
+  }
+
+  .card__bar .display-name {
+    margin-left: 0;
+    margin-right: 15px;
+    text-align: right;
+  }
 }
diff --git a/app/javascript/flavours/glitch/styles/stream_entries.scss b/app/javascript/flavours/glitch/styles/stream_entries.scss
index c458fcb79..80e2d0ca0 100644
--- a/app/javascript/flavours/glitch/styles/stream_entries.scss
+++ b/app/javascript/flavours/glitch/styles/stream_entries.scss
@@ -3,7 +3,6 @@
   border-radius: 4px;
   overflow: hidden;
   margin-bottom: 10px;
-  text-align: left;
 
   @media screen and (max-width: $no-gap-breakpoint) {
     margin-bottom: 0;
diff --git a/app/javascript/mastodon/actions/compose.js b/app/javascript/mastodon/actions/compose.js
index 6d975cd1e..fac8d32a1 100644
--- a/app/javascript/mastodon/actions/compose.js
+++ b/app/javascript/mastodon/actions/compose.js
@@ -56,7 +56,7 @@ export function changeCompose(text) {
   };
 };
 
-export function replyCompose(status, router) {
+export function replyCompose(status, routerHistory) {
   return (dispatch, getState) => {
     dispatch({
       type: COMPOSE_REPLY,
@@ -64,7 +64,7 @@ export function replyCompose(status, router) {
     });
 
     if (!getState().getIn(['compose', 'mounted'])) {
-      router.push('/statuses/new');
+      routerHistory.push('/statuses/new');
     }
   };
 };
@@ -81,7 +81,7 @@ export function resetCompose() {
   };
 };
 
-export function mentionCompose(account, router) {
+export function mentionCompose(account, routerHistory) {
   return (dispatch, getState) => {
     dispatch({
       type: COMPOSE_MENTION,
@@ -89,12 +89,12 @@ export function mentionCompose(account, router) {
     });
 
     if (!getState().getIn(['compose', 'mounted'])) {
-      router.push('/statuses/new');
+      routerHistory.push('/statuses/new');
     }
   };
 };
 
-export function directCompose(account, router) {
+export function directCompose(account, routerHistory) {
   return (dispatch, getState) => {
     dispatch({
       type: COMPOSE_DIRECT,
@@ -102,12 +102,12 @@ export function directCompose(account, router) {
     });
 
     if (!getState().getIn(['compose', 'mounted'])) {
-      router.push('/statuses/new');
+      routerHistory.push('/statuses/new');
     }
   };
 };
 
-export function submitCompose() {
+export function submitCompose(routerHistory) {
   return function (dispatch, getState) {
     const status = getState().getIn(['compose', 'text'], '');
     const media  = getState().getIn(['compose', 'media_attachments']);
@@ -133,21 +133,24 @@ export function submitCompose() {
       dispatch(insertIntoTagHistory(response.data.tags, status));
       dispatch(submitComposeSuccess({ ...response.data }));
 
-      // To make the app more responsive, immediately get the status into the columns
+      // To make the app more responsive, immediately push the status
+      // into the columns
 
-      const insertIfOnline = (timelineId) => {
+      const insertIfOnline = timelineId => {
         if (getState().getIn(['timelines', timelineId, 'items', 0]) !== null) {
           dispatch(updateTimeline(timelineId, { ...response.data }));
         }
       };
 
-      insertIfOnline('home');
+      if (response.data.visibility === 'direct' && getState().getIn(['conversations', 'mounted']) <= 0) {
+        routerHistory.push('/timelines/direct');
+      } else if (response.data.visibility !== 'direct') {
+        insertIfOnline('home');
+      }
 
       if (response.data.in_reply_to_id === null && response.data.visibility === 'public') {
         insertIfOnline('community');
         insertIfOnline('public');
-      } else if (response.data.visibility === 'direct') {
-        insertIfOnline('direct');
       }
     }).catch(function (error) {
       dispatch(submitComposeFail(error));
diff --git a/app/javascript/mastodon/actions/conversations.js b/app/javascript/mastodon/actions/conversations.js
index 3840d23ca..aefd2fef7 100644
--- a/app/javascript/mastodon/actions/conversations.js
+++ b/app/javascript/mastodon/actions/conversations.js
@@ -5,11 +5,33 @@ import {
   importFetchedStatus,
 } from './importer';
 
+export const CONVERSATIONS_MOUNT   = 'CONVERSATIONS_MOUNT';
+export const CONVERSATIONS_UNMOUNT = 'CONVERSATIONS_UNMOUNT';
+
 export const CONVERSATIONS_FETCH_REQUEST = 'CONVERSATIONS_FETCH_REQUEST';
 export const CONVERSATIONS_FETCH_SUCCESS = 'CONVERSATIONS_FETCH_SUCCESS';
 export const CONVERSATIONS_FETCH_FAIL    = 'CONVERSATIONS_FETCH_FAIL';
 export const CONVERSATIONS_UPDATE        = 'CONVERSATIONS_UPDATE';
 
+export const CONVERSATIONS_READ = 'CONVERSATIONS_READ';
+
+export const mountConversations = () => ({
+  type: CONVERSATIONS_MOUNT,
+});
+
+export const unmountConversations = () => ({
+  type: CONVERSATIONS_UNMOUNT,
+});
+
+export const markConversationRead = conversationId => (dispatch, getState) => {
+  dispatch({
+    type: CONVERSATIONS_READ,
+    id: conversationId,
+  });
+
+  api(getState).post(`/api/v1/conversations/${conversationId}/read`);
+};
+
 export const expandConversations = ({ maxId } = {}) => (dispatch, getState) => {
   dispatch(expandConversationsRequest());
 
diff --git a/app/javascript/mastodon/actions/suggestions.js b/app/javascript/mastodon/actions/suggestions.js
new file mode 100644
index 000000000..b15bd916b
--- /dev/null
+++ b/app/javascript/mastodon/actions/suggestions.js
@@ -0,0 +1,52 @@
+import api from '../api';
+import { importFetchedAccounts } from './importer';
+
+export const SUGGESTIONS_FETCH_REQUEST = 'SUGGESTIONS_FETCH_REQUEST';
+export const SUGGESTIONS_FETCH_SUCCESS = 'SUGGESTIONS_FETCH_SUCCESS';
+export const SUGGESTIONS_FETCH_FAIL    = 'SUGGESTIONS_FETCH_FAIL';
+
+export const SUGGESTIONS_DISMISS = 'SUGGESTIONS_DISMISS';
+
+export function fetchSuggestions() {
+  return (dispatch, getState) => {
+    dispatch(fetchSuggestionsRequest());
+
+    api(getState).get('/api/v1/suggestions').then(response => {
+      dispatch(importFetchedAccounts(response.data));
+      dispatch(fetchSuggestionsSuccess(response.data));
+    }).catch(error => dispatch(fetchSuggestionsFail(error)));
+  };
+};
+
+export function fetchSuggestionsRequest() {
+  return {
+    type: SUGGESTIONS_FETCH_REQUEST,
+    skipLoading: true,
+  };
+};
+
+export function fetchSuggestionsSuccess(accounts) {
+  return {
+    type: SUGGESTIONS_FETCH_SUCCESS,
+    accounts,
+    skipLoading: true,
+  };
+};
+
+export function fetchSuggestionsFail(error) {
+  return {
+    type: SUGGESTIONS_FETCH_FAIL,
+    error,
+    skipLoading: true,
+    skipAlert: true,
+  };
+};
+
+export const dismissSuggestion = accountId => (dispatch, getState) => {
+  dispatch({
+    type: SUGGESTIONS_DISMISS,
+    id: accountId,
+  });
+
+  api(getState).delete(`/api/v1/suggestions/${accountId}`);
+};
diff --git a/app/javascript/mastodon/components/account.js b/app/javascript/mastodon/components/account.js
index c021e3267..2bcea8b67 100644
--- a/app/javascript/mastodon/components/account.js
+++ b/app/javascript/mastodon/components/account.js
@@ -30,6 +30,9 @@ class Account extends ImmutablePureComponent {
     onMuteNotifications: PropTypes.func.isRequired,
     intl: PropTypes.object.isRequired,
     hidden: PropTypes.bool,
+    actionIcon: PropTypes.string,
+    actionTitle: PropTypes.string,
+    onActionClick: PropTypes.func,
   };
 
   handleFollow = () => {
@@ -52,8 +55,12 @@ class Account extends ImmutablePureComponent {
     this.props.onMuteNotifications(this.props.account, false);
   }
 
+  handleAction = () => {
+    this.props.onActionClick(this.props.account);
+  }
+
   render () {
-    const { account, intl, hidden } = this.props;
+    const { account, intl, hidden, onActionClick, actionIcon, actionTitle } = this.props;
 
     if (!account) {
       return <div />;
@@ -70,7 +77,9 @@ class Account extends ImmutablePureComponent {
 
     let buttons;
 
-    if (account.get('id') !== me && account.get('relationship', null) !== null) {
+    if (onActionClick && actionIcon) {
+      buttons = <IconButton icon={actionIcon} title={actionTitle} onClick={this.handleAction} />;
+    } else if (account.get('id') !== me && account.get('relationship', null) !== null) {
       const following = account.getIn(['relationship', 'following']);
       const requested = account.getIn(['relationship', 'requested']);
       const blocking  = account.getIn(['relationship', 'blocking']);
diff --git a/app/javascript/mastodon/components/avatar_composite.js b/app/javascript/mastodon/components/avatar_composite.js
new file mode 100644
index 000000000..4a9a73c51
--- /dev/null
+++ b/app/javascript/mastodon/components/avatar_composite.js
@@ -0,0 +1,96 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import ImmutablePropTypes from 'react-immutable-proptypes';
+import { autoPlayGif } from '../initial_state';
+
+export default class AvatarComposite extends React.PureComponent {
+
+  static propTypes = {
+    accounts: ImmutablePropTypes.list.isRequired,
+    animate: PropTypes.bool,
+    size: PropTypes.number.isRequired,
+  };
+
+  static defaultProps = {
+    animate: autoPlayGif,
+  };
+
+  renderItem (account, size, index) {
+    const { animate } = this.props;
+
+    let width  = 50;
+    let height = 100;
+    let top    = 'auto';
+    let left   = 'auto';
+    let bottom = 'auto';
+    let right  = 'auto';
+
+    if (size === 1) {
+      width = 100;
+    }
+
+    if (size === 4 || (size === 3 && index > 0)) {
+      height = 50;
+    }
+
+    if (size === 2) {
+      if (index === 0) {
+        right = '2px';
+      } else {
+        left = '2px';
+      }
+    } else if (size === 3) {
+      if (index === 0) {
+        right = '2px';
+      } else if (index > 0) {
+        left = '2px';
+      }
+
+      if (index === 1) {
+        bottom = '2px';
+      } else if (index > 1) {
+        top = '2px';
+      }
+    } else if (size === 4) {
+      if (index === 0 || index === 2) {
+        right = '2px';
+      }
+
+      if (index === 1 || index === 3) {
+        left = '2px';
+      }
+
+      if (index < 2) {
+        bottom = '2px';
+      } else {
+        top = '2px';
+      }
+    }
+
+    const style = {
+      left: left,
+      top: top,
+      right: right,
+      bottom: bottom,
+      width: `${width}%`,
+      height: `${height}%`,
+      backgroundSize: 'cover',
+      backgroundImage: `url(${account.get(animate ? 'avatar' : 'avatar_static')})`,
+    };
+
+    return (
+      <div key={account.get('id')} style={style} />
+    );
+  }
+
+  render() {
+    const { accounts, size } = this.props;
+
+    return (
+      <div className='account__avatar-composite' style={{ width: `${size}px`, height: `${size}px` }}>
+        {accounts.take(4).map((account, i) => this.renderItem(account, accounts.size, i))}
+      </div>
+    );
+  }
+
+}
diff --git a/app/javascript/mastodon/components/display_name.js b/app/javascript/mastodon/components/display_name.js
index c3a9ab921..c2c40cb3f 100644
--- a/app/javascript/mastodon/components/display_name.js
+++ b/app/javascript/mastodon/components/display_name.js
@@ -1,25 +1,28 @@
 import React from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
-import PropTypes from 'prop-types';
 
 export default class DisplayName extends React.PureComponent {
 
   static propTypes = {
     account: ImmutablePropTypes.map.isRequired,
-    withAcct: PropTypes.bool,
-  };
-
-  static defaultProps = {
-    withAcct: true,
+    others: ImmutablePropTypes.list,
   };
 
   render () {
-    const { account, withAcct } = this.props;
+    const { account, others } = this.props;
     const displayNameHtml = { __html: account.get('display_name_html') };
 
+    let suffix;
+
+    if (others && others.size > 1) {
+      suffix = `+${others.size}`;
+    } else {
+      suffix = <span className='display-name__account'>@{account.get('acct')}</span>;
+    }
+
     return (
       <span className='display-name'>
-        <bdi><strong className='display-name__html' dangerouslySetInnerHTML={displayNameHtml} /></bdi> {withAcct && <span className='display-name__account'>@{account.get('acct')}</span>}
+        <bdi><strong className='display-name__html' dangerouslySetInnerHTML={displayNameHtml} /></bdi> {suffix}
       </span>
     );
   }
diff --git a/app/javascript/mastodon/components/status.js b/app/javascript/mastodon/components/status.js
index 90c689a75..0b23e51f8 100644
--- a/app/javascript/mastodon/components/status.js
+++ b/app/javascript/mastodon/components/status.js
@@ -3,6 +3,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import Avatar from './avatar';
 import AvatarOverlay from './avatar_overlay';
+import AvatarComposite from './avatar_composite';
 import RelativeTimestamp from './relative_timestamp';
 import DisplayName from './display_name';
 import StatusContent from './status_content';
@@ -45,6 +46,8 @@ class Status extends ImmutablePureComponent {
   static propTypes = {
     status: ImmutablePropTypes.map,
     account: ImmutablePropTypes.map,
+    otherAccounts: ImmutablePropTypes.list,
+    onClick: PropTypes.func,
     onReply: PropTypes.func,
     onFavourite: PropTypes.func,
     onReblog: PropTypes.func,
@@ -60,6 +63,7 @@ class Status extends ImmutablePureComponent {
     onToggleHidden: PropTypes.func,
     muted: PropTypes.bool,
     hidden: PropTypes.bool,
+    unread: PropTypes.bool,
     onMoveUp: PropTypes.func,
     onMoveDown: PropTypes.func,
   };
@@ -74,6 +78,11 @@ class Status extends ImmutablePureComponent {
   ]
 
   handleClick = () => {
+    if (this.props.onClick) {
+      this.props.onClick();
+      return;
+    }
+
     if (!this.context.router) {
       return;
     }
@@ -158,7 +167,7 @@ class Status extends ImmutablePureComponent {
     let media = null;
     let statusAvatar, prepend, rebloggedByText;
 
-    const { intl, hidden, featured } = this.props;
+    const { intl, hidden, featured, otherAccounts, unread } = this.props;
 
     let { status, account, ...other } = this.props;
 
@@ -249,9 +258,11 @@ class Status extends ImmutablePureComponent {
       }
     }
 
-    if (account === undefined || account === null) {
+    if (otherAccounts) {
+      statusAvatar = <AvatarComposite accounts={otherAccounts} size={48} />;
+    } else if (account === undefined || account === null) {
       statusAvatar = <Avatar account={status.get('account')} size={48} />;
-    }else{
+    } else {
       statusAvatar = <AvatarOverlay account={status.get('account')} friend={account} />;
     }
 
@@ -269,10 +280,10 @@ class Status extends ImmutablePureComponent {
 
     return (
       <HotKeys handlers={handlers}>
-        <div className={classNames('status__wrapper', `status__wrapper-${status.get('visibility')}`, { 'status__wrapper-reply': !!status.get('in_reply_to_id'), focusable: !this.props.muted })} tabIndex={this.props.muted ? null : 0} data-featured={featured ? 'true' : null} aria-label={textForScreenReader(intl, status, rebloggedByText, !status.get('hidden'))}>
+        <div className={classNames('status__wrapper', `status__wrapper-${status.get('visibility')}`, { 'status__wrapper-reply': !!status.get('in_reply_to_id'), read: unread === false, focusable: !this.props.muted })} tabIndex={this.props.muted ? null : 0} data-featured={featured ? 'true' : null} aria-label={textForScreenReader(intl, status, rebloggedByText, !status.get('hidden'))}>
           {prepend}
 
-          <div className={classNames('status', `status-${status.get('visibility')}`, { 'status-reply': !!status.get('in_reply_to_id'), muted: this.props.muted })} data-id={status.get('id')}>
+          <div className={classNames('status', `status-${status.get('visibility')}`, { 'status-reply': !!status.get('in_reply_to_id'), muted: this.props.muted, read: unread === false })} data-id={status.get('id')}>
             <div className='status__info'>
               <a href={status.get('url')} className='status__relative-time' target='_blank' rel='noopener'><RelativeTimestamp timestamp={status.get('created_at')} /></a>
 
@@ -281,7 +292,7 @@ class Status extends ImmutablePureComponent {
                   {statusAvatar}
                 </div>
 
-                <DisplayName account={status.get('account')} />
+                <DisplayName account={status.get('account')} others={otherAccounts} />
               </a>
             </div>
 
diff --git a/app/javascript/mastodon/features/compose/components/compose_form.js b/app/javascript/mastodon/features/compose/components/compose_form.js
index eec93fc28..1b1a4f8d4 100644
--- a/app/javascript/mastodon/features/compose/components/compose_form.js
+++ b/app/javascript/mastodon/features/compose/components/compose_form.js
@@ -31,6 +31,10 @@ const messages = defineMessages({
 export default @injectIntl
 class ComposeForm extends ImmutablePureComponent {
 
+  static contextTypes = {
+    router: PropTypes.object,
+  };
+
   static propTypes = {
     intl: PropTypes.object.isRequired,
     text: PropTypes.string.isRequired,
@@ -85,7 +89,7 @@ class ComposeForm extends ImmutablePureComponent {
       return;
     }
 
-    this.props.onSubmit();
+    this.props.onSubmit(this.context.router.history);
   }
 
   onSuggestionsClearRequested = () => {
diff --git a/app/javascript/mastodon/features/compose/components/privacy_dropdown.js b/app/javascript/mastodon/features/compose/components/privacy_dropdown.js
index 7b5482f05..5698765d9 100644
--- a/app/javascript/mastodon/features/compose/components/privacy_dropdown.js
+++ b/app/javascript/mastodon/features/compose/components/privacy_dropdown.js
@@ -164,7 +164,7 @@ class PrivacyDropdown extends React.PureComponent {
 
   state = {
     open: false,
-    placement: null,
+    placement: 'bottom',
   };
 
   handleToggle = ({ target }) => {
diff --git a/app/javascript/mastodon/features/compose/components/search_results.js b/app/javascript/mastodon/features/compose/components/search_results.js
index c351b84bb..f0ddf6d71 100644
--- a/app/javascript/mastodon/features/compose/components/search_results.js
+++ b/app/javascript/mastodon/features/compose/components/search_results.js
@@ -1,19 +1,56 @@
 import React from 'react';
+import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
-import { FormattedMessage } from 'react-intl';
+import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
 import AccountContainer from '../../../containers/account_container';
 import StatusContainer from '../../../containers/status_container';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import Hashtag from '../../../components/hashtag';
 
-export default class SearchResults extends ImmutablePureComponent {
+const messages = defineMessages({
+  dismissSuggestion: { id: 'suggestions.dismiss', defaultMessage: 'Dismiss suggestion' },
+});
+
+export default @injectIntl
+class SearchResults extends ImmutablePureComponent {
 
   static propTypes = {
     results: ImmutablePropTypes.map.isRequired,
+    suggestions: ImmutablePropTypes.list.isRequired,
+    fetchSuggestions: PropTypes.func.isRequired,
+    dismissSuggestion: PropTypes.func.isRequired,
+    intl: PropTypes.object.isRequired,
   };
 
+  componentDidMount () {
+    this.props.fetchSuggestions();
+  }
+
   render () {
-    const { results } = this.props;
+    const { intl, results, suggestions, dismissSuggestion } = this.props;
+
+    if (results.isEmpty() && !suggestions.isEmpty()) {
+      return (
+        <div className='search-results'>
+          <div className='trends'>
+            <div className='trends__header'>
+              <i className='fa fa-user-plus fa-fw' />
+              <FormattedMessage id='suggestions.header' defaultMessage='You might be interested in…' />
+            </div>
+
+            {suggestions && suggestions.map(accountId => (
+              <AccountContainer
+                key={accountId}
+                id={accountId}
+                actionIcon='times'
+                actionTitle={intl.formatMessage(messages.dismissSuggestion)}
+                onActionClick={dismissSuggestion}
+              />
+            ))}
+          </div>
+        </div>
+      );
+    }
 
     let accounts, statuses, hashtags;
     let count = 0;
diff --git a/app/javascript/mastodon/features/compose/components/upload.js b/app/javascript/mastodon/features/compose/components/upload.js
index e377da90c..66c93452c 100644
--- a/app/javascript/mastodon/features/compose/components/upload.js
+++ b/app/javascript/mastodon/features/compose/components/upload.js
@@ -14,6 +14,10 @@ const messages = defineMessages({
 export default @injectIntl
 class Upload extends ImmutablePureComponent {
 
+  static contextTypes = {
+    router: PropTypes.object,
+  };
+
   static propTypes = {
     media: ImmutablePropTypes.map.isRequired,
     intl: PropTypes.object.isRequired,
@@ -37,7 +41,7 @@ class Upload extends ImmutablePureComponent {
 
   handleSubmit = () => {
     this.handleInputBlur();
-    this.props.onSubmit();
+    this.props.onSubmit(this.context.router.history);
   }
 
   handleUndoClick = () => {
diff --git a/app/javascript/mastodon/features/compose/containers/compose_form_container.js b/app/javascript/mastodon/features/compose/containers/compose_form_container.js
index 3822dd711..5d7fb8852 100644
--- a/app/javascript/mastodon/features/compose/containers/compose_form_container.js
+++ b/app/javascript/mastodon/features/compose/containers/compose_form_container.js
@@ -33,8 +33,8 @@ const mapDispatchToProps = (dispatch) => ({
     dispatch(changeCompose(text));
   },
 
-  onSubmit () {
-    dispatch(submitCompose());
+  onSubmit (router) {
+    dispatch(submitCompose(router));
   },
 
   onClearSuggestions () {
diff --git a/app/javascript/mastodon/features/compose/containers/search_results_container.js b/app/javascript/mastodon/features/compose/containers/search_results_container.js
index 16d95d417..f9637861a 100644
--- a/app/javascript/mastodon/features/compose/containers/search_results_container.js
+++ b/app/javascript/mastodon/features/compose/containers/search_results_container.js
@@ -1,8 +1,15 @@
 import { connect } from 'react-redux';
 import SearchResults from '../components/search_results';
+import { fetchSuggestions, dismissSuggestion } from '../../../actions/suggestions';
 
 const mapStateToProps = state => ({
   results: state.getIn(['search', 'results']),
+  suggestions: state.getIn(['suggestions', 'items']),
 });
 
-export default connect(mapStateToProps)(SearchResults);
+const mapDispatchToProps = dispatch => ({
+  fetchSuggestions: () => dispatch(fetchSuggestions()),
+  dismissSuggestion: account => dispatch(dismissSuggestion(account.get('id'))),
+});
+
+export default connect(mapStateToProps, mapDispatchToProps)(SearchResults);
diff --git a/app/javascript/mastodon/features/compose/containers/upload_container.js b/app/javascript/mastodon/features/compose/containers/upload_container.js
index 9f3aab4bc..b6d81f03a 100644
--- a/app/javascript/mastodon/features/compose/containers/upload_container.js
+++ b/app/javascript/mastodon/features/compose/containers/upload_container.js
@@ -22,8 +22,8 @@ const mapDispatchToProps = dispatch => ({
     dispatch(openModal('FOCAL_POINT', { id }));
   },
 
-  onSubmit () {
-    dispatch(submitCompose());
+  onSubmit (router) {
+    dispatch(submitCompose(router));
   },
 
 });
diff --git a/app/javascript/mastodon/features/compose/index.js b/app/javascript/mastodon/features/compose/index.js
index cf1714b71..d76cd76e6 100644
--- a/app/javascript/mastodon/features/compose/index.js
+++ b/app/javascript/mastodon/features/compose/index.js
@@ -13,6 +13,7 @@ import spring from 'react-motion/lib/spring';
 import SearchResultsContainer from './containers/search_results_container';
 import { changeComposing } from '../../actions/compose';
 import elephantUIPlane from '../../../images/elephant_ui_plane.svg';
+import { mascot } from '../../initial_state';
 
 const messages = defineMessages({
   start: { id: 'getting_started.heading', defaultMessage: 'Getting started' },
@@ -107,7 +108,7 @@ class Compose extends React.PureComponent {
             <ComposeFormContainer />
             {multiColumn && (
               <div className='drawer__inner__mastodon'>
-                <img alt='' draggable='false' src={elephantUIPlane} />
+                <img alt='' draggable='false' src={mascot || elephantUIPlane} />
               </div>
             )}
           </div>}
diff --git a/app/javascript/mastodon/features/direct_timeline/components/conversation.js b/app/javascript/mastodon/features/direct_timeline/components/conversation.js
index f9a8d4f72..7277b7f0f 100644
--- a/app/javascript/mastodon/features/direct_timeline/components/conversation.js
+++ b/app/javascript/mastodon/features/direct_timeline/components/conversation.js
@@ -2,12 +2,7 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import ImmutablePureComponent from 'react-immutable-pure-component';
-import StatusContent from '../../../components/status_content';
-import RelativeTimestamp from '../../../components/relative_timestamp';
-import DisplayName from '../../../components/display_name';
-import Avatar from '../../../components/avatar';
-import AttachmentList from '../../../components/attachment_list';
-import { HotKeys } from 'react-hotkeys';
+import StatusContainer from '../../../containers/status_container';
 
 export default class Conversation extends ImmutablePureComponent {
 
@@ -18,9 +13,11 @@ export default class Conversation extends ImmutablePureComponent {
   static propTypes = {
     conversationId: PropTypes.string.isRequired,
     accounts: ImmutablePropTypes.list.isRequired,
-    lastStatus: ImmutablePropTypes.map.isRequired,
+    lastStatusId: PropTypes.string,
+    unread:PropTypes.bool.isRequired,
     onMoveUp: PropTypes.func,
     onMoveDown: PropTypes.func,
+    markRead: PropTypes.func.isRequired,
   };
 
   handleClick = () => {
@@ -28,8 +25,13 @@ export default class Conversation extends ImmutablePureComponent {
       return;
     }
 
-    const { lastStatus } = this.props;
-    this.context.router.history.push(`/statuses/${lastStatus.get('id')}`);
+    const { lastStatusId, unread, markRead } = this.props;
+
+    if (unread) {
+      markRead();
+    }
+
+    this.context.router.history.push(`/statuses/${lastStatusId}`);
   }
 
   handleHotkeyMoveUp = () => {
@@ -41,44 +43,20 @@ export default class Conversation extends ImmutablePureComponent {
   }
 
   render () {
-    const { accounts, lastStatus, lastAccount } = this.props;
+    const { accounts, lastStatusId, unread } = this.props;
 
-    if (lastStatus === null) {
+    if (lastStatusId === null) {
       return null;
     }
 
-    const handlers = {
-      moveDown: this.handleHotkeyMoveDown,
-      moveUp: this.handleHotkeyMoveUp,
-      open: this.handleClick,
-    };
-
-    let media;
-
-    if (lastStatus.get('media_attachments').size > 0) {
-      media = <AttachmentList compact media={lastStatus.get('media_attachments')} />;
-    }
-
     return (
-      <HotKeys handlers={handlers}>
-        <div className='conversation focusable' tabIndex='0' onClick={this.handleClick} role='button'>
-          <div className='conversation__header'>
-            <div className='conversation__avatars'>
-              <div>{accounts.map(account => <Avatar key={account.get('id')} size={36} account={account} />)}</div>
-            </div>
-
-            <div className='conversation__time'>
-              <RelativeTimestamp timestamp={lastStatus.get('created_at')} />
-              <br />
-              <DisplayName account={lastAccount} withAcct={false} />
-            </div>
-          </div>
-
-          <StatusContent status={lastStatus} onClick={this.handleClick} />
-
-          {media}
-        </div>
-      </HotKeys>
+      <StatusContainer
+        id={lastStatusId}
+        unread={unread}
+        otherAccounts={accounts}
+        onMoveUp={this.handleHotkeyMoveUp}
+        onMoveDown={this.handleHotkeyMoveDown}
+      />
     );
   }
 
diff --git a/app/javascript/mastodon/features/direct_timeline/containers/conversation_container.js b/app/javascript/mastodon/features/direct_timeline/containers/conversation_container.js
index 4166ee2ac..bd6f6bfb0 100644
--- a/app/javascript/mastodon/features/direct_timeline/containers/conversation_container.js
+++ b/app/javascript/mastodon/features/direct_timeline/containers/conversation_container.js
@@ -1,15 +1,19 @@
 import { connect } from 'react-redux';
 import Conversation from '../components/conversation';
+import { markConversationRead } from '../../../actions/conversations';
 
 const mapStateToProps = (state, { conversationId }) => {
   const conversation = state.getIn(['conversations', 'items']).find(x => x.get('id') === conversationId);
-  const lastStatus   = state.getIn(['statuses', conversation.get('last_status')], null);
 
   return {
     accounts: conversation.get('accounts').map(accountId => state.getIn(['accounts', accountId], null)),
-    lastStatus,
-    lastAccount: lastStatus === null ? null : state.getIn(['accounts', lastStatus.get('account')], null),
+    unread: conversation.get('unread'),
+    lastStatusId: conversation.get('last_status', null),
   };
 };
 
-export default connect(mapStateToProps)(Conversation);
+const mapDispatchToProps = (dispatch, { conversationId }) => ({
+  markRead: () => dispatch(markConversationRead(conversationId)),
+});
+
+export default connect(mapStateToProps, mapDispatchToProps)(Conversation);
diff --git a/app/javascript/mastodon/features/direct_timeline/index.js b/app/javascript/mastodon/features/direct_timeline/index.js
index 41ec73d98..d202f3bfd 100644
--- a/app/javascript/mastodon/features/direct_timeline/index.js
+++ b/app/javascript/mastodon/features/direct_timeline/index.js
@@ -3,7 +3,7 @@ import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import Column from '../../components/column';
 import ColumnHeader from '../../components/column_header';
-import { expandConversations } from '../../actions/conversations';
+import { mountConversations, unmountConversations, expandConversations } from '../../actions/conversations';
 import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 import { connectDirectStream } from '../../actions/streaming';
@@ -48,11 +48,14 @@ class DirectTimeline extends React.PureComponent {
   componentDidMount () {
     const { dispatch } = this.props;
 
+    dispatch(mountConversations());
     dispatch(expandConversations());
     this.disconnect = dispatch(connectDirectStream());
   }
 
   componentWillUnmount () {
+    this.props.dispatch(unmountConversations());
+
     if (this.disconnect) {
       this.disconnect();
       this.disconnect = null;
diff --git a/app/javascript/mastodon/features/status/index.js b/app/javascript/mastodon/features/status/index.js
index 2cd17b805..b36d82865 100644
--- a/app/javascript/mastodon/features/status/index.js
+++ b/app/javascript/mastodon/features/status/index.js
@@ -181,7 +181,7 @@ class Status extends ImmutablePureComponent {
     if (status.get('reblogged')) {
       this.props.dispatch(unreblog(status));
     } else {
-      if (e.shiftKey || !boostModal) {
+      if ((e && e.shiftKey) || !boostModal) {
         this.handleModalReblog(status);
       } else {
         this.props.dispatch(openModal('BOOST', { status, onReblog: this.handleModalReblog }));
diff --git a/app/javascript/mastodon/features/ui/index.js b/app/javascript/mastodon/features/ui/index.js
index fb6f675f4..662375a76 100644
--- a/app/javascript/mastodon/features/ui/index.js
+++ b/app/javascript/mastodon/features/ui/index.js
@@ -460,7 +460,7 @@ class UI extends React.PureComponent {
     };
 
     return (
-      <HotKeys keyMap={keyMap} handlers={handlers} ref={this.setHotkeysRef}>
+      <HotKeys keyMap={keyMap} handlers={handlers} ref={this.setHotkeysRef} attach={window} focused>
         <div className={classNames('ui', { 'is-composing': isComposing })} ref={this.setRef} style={{ pointerEvents: dropdownMenuIsOpen ? 'none' : null }}>
           <TabsBar />
 
diff --git a/app/javascript/mastodon/initial_state.js b/app/javascript/mastodon/initial_state.js
index 1d3d84f9d..05c209d8f 100644
--- a/app/javascript/mastodon/initial_state.js
+++ b/app/javascript/mastodon/initial_state.js
@@ -15,5 +15,6 @@ export const searchEnabled = getMeta('search_enabled');
 export const maxChars = (initialState && initialState.max_toot_chars) || 500;
 export const invitesEnabled = getMeta('invites_enabled');
 export const version = getMeta('version');
+export const mascot = getMeta('mascot');
 
 export default initialState;
diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json
index a74207db6..da79b62d2 100644
--- a/app/javascript/mastodon/locales/ar.json
+++ b/app/javascript/mastodon/locales/ar.json
@@ -15,7 +15,7 @@
   "account.follows.empty": "هذا المستخدِم لا يتبع أحدًا بعد.",
   "account.follows_you": "يتابعك",
   "account.hide_reblogs": "إخفاء ترقيات @{name}",
-  "account.link_verified_on": "Ownership of this link was checked on {date}",
+  "account.link_verified_on": "تم التحقق مِن مالك هذا الرابط بتاريخ {date}",
   "account.media": "وسائط",
   "account.mention": "أُذكُر @{name}",
   "account.moved_to": "{name} إنتقل إلى :",
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "هل أنت متأكد أنك تريد كتم {name} ؟",
   "confirmations.redraft.confirm": "إزالة و إعادة الصياغة",
   "confirmations.redraft.message": "هل أنت متأكد من أنك تريد حذف هذا المنشور و إعادة صياغته ؟ سوف تفقد جميع الإعجابات و الترقيات أما الردود المتصلة به فستُصبِح يتيمة.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "إلغاء المتابعة",
   "confirmations.unfollow.message": "متأكد من أنك تريد إلغاء متابعة {name} ؟",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "يمكنكم إدماج هذا المنشور على موقعكم الإلكتروني عن طريق نسخ الشفرة أدناه.",
   "embed.preview": "هكذا ما سوف يبدو عليه :",
   "emoji_button.activity": "الأنشطة",
@@ -113,9 +116,9 @@
   "empty_column.community": "الخط الزمني المحلي فارغ. أكتب شيئا ما للعامة كبداية !",
   "empty_column.direct": "لم تتلق أية رسالة خاصة مباشِرة بعد. سوف يتم عرض الرسائل المباشرة هنا إن قمت بإرسال واحدة أو تلقيت البعض منها.",
   "empty_column.domain_blocks": "ليس هناك نطاقات مخفية بعد.",
-  "empty_column.favourited_statuses": "You don't have any favourite toots yet. When you favourite one, it will show up here.",
-  "empty_column.favourites": "No one has favourited this toot yet. When someone does, they will show up here.",
-  "empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.",
+  "empty_column.favourited_statuses": "ليس لديك أية تبويقات مفضلة بعد. عندما ستقوم بالإعجاب بواحد، سيظهر هنا.",
+  "empty_column.favourites": "لم يقم أي أحد بالإعجاب بهذا التبويق بعد. عندما يقوم أحدهم بذلك سوف يظهر هنا.",
+  "empty_column.follow_requests": "ليس عندك أي طلب للمتابعة بعد. سوف تظهر طلباتك هنا إن قمت بتلقي البعض منها.",
   "empty_column.hashtag": "ليس هناك بعدُ أي محتوى ذو علاقة بهذا الوسم.",
   "empty_column.home": "إنّ الخيط الزمني لصفحتك الرئيسية فارغ. قم بزيارة {public} أو استخدم حقل البحث لكي تكتشف مستخدمين آخرين.",
   "empty_column.home.public_timeline": "الخيط العام",
@@ -163,7 +166,7 @@
   "keyboard_shortcuts.reply": "للردّ",
   "keyboard_shortcuts.requests": "لفتح قائمة طلبات المتابعة",
   "keyboard_shortcuts.search": "للتركيز على البحث",
-  "keyboard_shortcuts.start": "to open \"get started\" column",
+  "keyboard_shortcuts.start": "لفتح عمود \"هيا نبدأ\"",
   "keyboard_shortcuts.toggle_hidden": "لعرض أو إخفاء النص مِن وراء التحذير",
   "keyboard_shortcuts.toot": "لتحرير تبويق جديد",
   "keyboard_shortcuts.unfocus": "لإلغاء التركيز على حقل النص أو نافذة البحث",
@@ -280,7 +283,7 @@
   "status.cancel_reblog_private": "إلغاء الترقية",
   "status.cannot_reblog": "تعذرت ترقية هذا المنشور",
   "status.delete": "إحذف",
-  "status.detailed_status": "Detailed conversation view",
+  "status.detailed_status": "تفاصيل المحادثة",
   "status.direct": "رسالة خاصة إلى @{name}",
   "status.embed": "إدماج",
   "status.favourite": "أضف إلى المفضلة",
@@ -294,6 +297,7 @@
   "status.open": "وسع هذه المشاركة",
   "status.pin": "تدبيس على الملف الشخصي",
   "status.pinned": "تبويق مثبَّت",
+  "status.read_more": "Read more",
   "status.reblog": "رَقِّي",
   "status.reblog_private": "القيام بالترقية إلى الجمهور الأصلي",
   "status.reblogged_by": "رقّاه {name}",
diff --git a/app/javascript/mastodon/locales/ast.json b/app/javascript/mastodon/locales/ast.json
index 147c5ad2a..5e258c58c 100644
--- a/app/javascript/mastodon/locales/ast.json
+++ b/app/javascript/mastodon/locales/ast.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "¿De xuru que quies silenciar a {name}?",
   "confirmations.redraft.confirm": "Delete & redraft",
   "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Unfollow",
   "confirmations.unfollow.message": "Are you sure you want to unfollow {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Embed this status on your website by copying the code below.",
   "embed.preview": "Here is what it will look like:",
   "emoji_button.activity": "Actividá",
@@ -294,6 +297,7 @@
   "status.open": "Espander esti estáu",
   "status.pin": "Pin on profile",
   "status.pinned": "Pinned toot",
+  "status.read_more": "Read more",
   "status.reblog": "Boost",
   "status.reblog_private": "Boost to original audience",
   "status.reblogged_by": "{name} boosted",
diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json
index 756c33393..5daf5d639 100644
--- a/app/javascript/mastodon/locales/bg.json
+++ b/app/javascript/mastodon/locales/bg.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Are you sure you want to mute {name}?",
   "confirmations.redraft.confirm": "Delete & redraft",
   "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Unfollow",
   "confirmations.unfollow.message": "Are you sure you want to unfollow {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Embed this status on your website by copying the code below.",
   "embed.preview": "Here is what it will look like:",
   "emoji_button.activity": "Activity",
@@ -294,6 +297,7 @@
   "status.open": "Expand this status",
   "status.pin": "Pin on profile",
   "status.pinned": "Pinned toot",
+  "status.read_more": "Read more",
   "status.reblog": "Споделяне",
   "status.reblog_private": "Boost to original audience",
   "status.reblogged_by": "{name} сподели",
diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json
index 4701c9316..f2235b190 100644
--- a/app/javascript/mastodon/locales/ca.json
+++ b/app/javascript/mastodon/locales/ca.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Estàs segur que vols silenciar {name}?",
   "confirmations.redraft.confirm": "Esborrar i refer",
   "confirmations.redraft.message": "Estàs segur que vols esborrar aquesta publicació i tornar a redactar-la? Perderàs totes els impulsos i favorits, i les respostes a la publicació original es quedaran orfes.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Deixa de seguir",
   "confirmations.unfollow.message": "Estàs segur que vols deixar de seguir {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Incrusta aquest estat al lloc web copiant el codi a continuació.",
   "embed.preview": "Aquí tenim quin aspecte tindrá:",
   "emoji_button.activity": "Activitat",
@@ -294,6 +297,7 @@
   "status.open": "Ampliar aquest estat",
   "status.pin": "Fixat en el perfil",
   "status.pinned": "Toot fixat",
+  "status.read_more": "Read more",
   "status.reblog": "Impuls",
   "status.reblog_private": "Impulsar a l'audiència original",
   "status.reblogged_by": "{name} ha retootejat",
diff --git a/app/javascript/mastodon/locales/co.json b/app/javascript/mastodon/locales/co.json
index 62976c98e..4507deddb 100644
--- a/app/javascript/mastodon/locales/co.json
+++ b/app/javascript/mastodon/locales/co.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Site sicuru·a che vulete piattà @{name}?",
   "confirmations.redraft.confirm": "Sguassà è riscrive",
   "confirmations.redraft.message": "Site sicuru·a chè vulete sguassà stu statutu è riscrivelu? I favuriti è spartere saranu persi, è e risposte diventeranu orfane.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Disabbunassi",
   "confirmations.unfollow.message": "Site sicuru·a ch'ùn vulete più siguità @{name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Integrà stu statutu à u vostru situ cù u codice quì sottu.",
   "embed.preview": "Assumiglierà à qualcosa cusì:",
   "emoji_button.activity": "Attività",
@@ -294,6 +297,7 @@
   "status.open": "Apre stu statutu",
   "status.pin": "Puntarulà à u prufile",
   "status.pinned": "Statutu puntarulatu",
+  "status.read_more": "Read more",
   "status.reblog": "Sparte",
   "status.reblog_private": "Sparte à l'audienza uriginale",
   "status.reblogged_by": "{name} hà spartutu",
diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json
index 2c34fd34c..116a65468 100644
--- a/app/javascript/mastodon/locales/cs.json
+++ b/app/javascript/mastodon/locales/cs.json
@@ -8,14 +8,14 @@
   "account.domain_blocked": "Doména skryta",
   "account.edit_profile": "Upravit profil",
   "account.endorse": "Představit na profilu",
-  "account.follow": "Sleduj",
+  "account.follow": "Sledovat",
   "account.followers": "Sledovatelé",
   "account.followers.empty": "Tohoto uživatele ještě nikdo nesleduje.",
   "account.follows": "Sleduje",
   "account.follows.empty": "Tento uživatel ještě nikoho nesleduje.",
   "account.follows_you": "Sleduje vás",
   "account.hide_reblogs": "Skrýt boosty od uživatele @{name}",
-  "account.link_verified_on": "Ownership of this link was checked on {date}",
+  "account.link_verified_on": "Vlastnictví tohoto odkazu bylo zkontrolováno {date}",
   "account.media": "Média",
   "account.mention": "Zmínit uživatele @{name}",
   "account.moved_to": "{name} se přesunul/a na:",
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Jste si jistý/á, že chcete ignorovat uživatele {name}?",
   "confirmations.redraft.confirm": "Vymazat a přepsat",
   "confirmations.redraft.message": "Jste si jistý/á, že chcete vymazat a přepsat tento příspěvek? Oblíbení a boosty budou ztraceny a odpovědi na původní příspěvek budou opuštěny.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Přestat sledovat",
   "confirmations.unfollow.message": "jste si jistý/á, že chcete přestat sledovat uživatele {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Pro přidání příspěvku na vaši webovou stránku zkopírujte níže uvedený kód.",
   "embed.preview": "Takhle to bude vypadat:",
   "emoji_button.activity": "Aktivita",
@@ -294,6 +297,7 @@
   "status.open": "Rozbalit tento příspěvek",
   "status.pin": "Připnout na profil",
   "status.pinned": "Připnutý toot",
+  "status.read_more": "Read more",
   "status.reblog": "Boostnout",
   "status.reblog_private": "Boostnout původnímu publiku",
   "status.reblogged_by": "{name} boostnul/a",
diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json
index 90f3f8e30..4816a0e35 100644
--- a/app/javascript/mastodon/locales/cy.json
+++ b/app/javascript/mastodon/locales/cy.json
@@ -1,335 +1,340 @@
 {
-    "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"
+  "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.link_verified_on": "Gwiriwyd perchnogaeth y ddolen yma ar {date}",
+  "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": "Ffrwd y ffederasiwn",
+  "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": "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": "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": "Cuddio parth cyfan",
+  "confirmations.domain_block.message": "A ydych yn hollol, hollol sicr eich bod am flocio y {domain} cyfan? Yn y nifer helaeth o achosion mae blocio neu tawelu ambell gyfrif yn ddigonol ac yn well. Ni fyddwch yn gweld cynnwyr o'r parth hwnnw mewn unrhyw ffrydiau cyhoeddus na chwaith eich hysbysiadau. Bydd hyn yn cael gwared o'ch dilynwyr o'r parth hwnnw.",
+  "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.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
+  "confirmations.unfollow.confirm": "Dad-ddilynwch",
+  "confirmations.unfollow.message": "Ydych chi'n sicr eich bod am ddad-ddilyn {name}?",
+  "conversation.last_message": "Last message:",
+  "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": "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": "Mae'r ffrwd lleol yn wag. Ysgrifenwch rhywbeth yn gyhoeddus i gael dechrau arni!",
+  "empty_column.direct": "Nid oes gennych unrhyw negeseuon preifat eto. Pan y byddwch yn anfon neu derbyn un, mi fydd yn ymddangos yma.",
+  "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": "Mae eich ffrwd gartref yn wag! Ymwelwch a {public} neu defnyddiwch y chwilotwr i ddechrau arni ac i gwrdd a defnyddwyr eraill.",
+  "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": "Show boosts",
+  "home.column_settings.show_replies": "Dangoswch ymatebion",
+  "keyboard_shortcuts.back": "i lywio nôl",
+  "keyboard_shortcuts.blocked": "i agor rhestr defnyddwyr a flociwyd",
+  "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": "i agor ffrwd y ffederasiwn",
+  "keyboard_shortcuts.heading": "Llwybrau byr allweddell",
+  "keyboard_shortcuts.home": "i agor ffrwd cartref",
+  "keyboard_shortcuts.hotkey": "Hotkey",
+  "keyboard_shortcuts.legend": "i ddangos yr arwr yma",
+  "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": "i agor rhestr tŵtiau wedi'i pinio",
+  "keyboard_shortcuts.profile": "i agor proffil yr awdur",
+  "keyboard_shortcuts.reply": "i ateb",
+  "keyboard_shortcuts.requests": "i agor rhestr ceisiadau dilyn",
+  "keyboard_shortcuts.search": "i ffocysu chwilio",
+  "keyboard_shortcuts.start": "i agor colofn \"dechrau arni\"",
+  "keyboard_shortcuts.toggle_hidden": "i ddangos/cuddio testun tu ôl i CW",
+  "keyboard_shortcuts.toot": "i ddechrau tŵt newydd sbon",
+  "keyboard_shortcuts.unfocus": "i ddad-ffocysu ardal cyfansoddi testun/chwilio",
+  "keyboard_shortcuts.up": "i symud yn uwch yn y rhestr",
+  "lightbox.close": "Cau",
+  "lightbox.next": "Nesaf",
+  "lightbox.previous": "Blaenorol",
+  "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": "Teitl rhestr newydd",
+  "lists.search": "Chwiliwch ymysg pobl yr ydych yn ei ddilyn",
+  "lists.subheading": "Eich rhestrau",
+  "loading_indicator.label": "Llwytho...",
+  "media_gallery.toggle_visible": "Toglo gwelededd",
+  "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": "Ffrwd leol",
+  "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": "Ynghylch yr achos hwn",
+  "navigation_bar.keyboard_shortcuts": "Bysellau brys",
+  "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": "Ffrwd y fferasiwn",
+  "navigation_bar.security": "Diogelwch",
+  "notification.favourite": "hoffodd {name} eich statws",
+  "notification.follow": "dilynodd {name} chi",
+  "notification.mention": "Soniodd {name} amdanoch chi",
+  "notification.reblog": "{name} boosted your status",
+  "notifications.clear": "Clirio hysbysiadau",
+  "notifications.clear_confirmation": "Ydych chi'n sicr eich bod am glirio'ch holl hysbysiadau am byth?",
+  "notifications.column_settings.alert": "Hysbysiadau bwrdd gwaith",
+  "notifications.column_settings.favourite": "Ffefrynnau:",
+  "notifications.column_settings.follow": "Dilynwyr newydd:",
+  "notifications.column_settings.mention": "Crybwylliadau:",
+  "notifications.column_settings.push": "Hysbysiadau push",
+  "notifications.column_settings.reblog": "Boosts:",
+  "notifications.column_settings.show": "Dangos yn y golofn",
+  "notifications.column_settings.sound": "Chwarae sain",
+  "notifications.group": "{count} o hysbysiadau",
+  "onboarding.done": "Wedi'i wneud",
+  "onboarding.next": "Nesaf",
+  "onboarding.page_five.public_timelines": "Mae'r ffrwd lleol yn dangos tŵtiau cyhoeddus o bawb ar y {domain}. Mae ffrwd y ffederasiwn yn dangos tŵtiau cyhoeddus o bawb y mae pobl ar y {domain} yn dilyn. Mae rhain yn Ffrydiau Cyhoeddus, ffordd wych o ddarganfod pobl newydd.",
+  "onboarding.page_four.home": "Mae'r ffrwd gartref yn dangos twtiau o bobl yr ydych yn dilyn.",
+  "onboarding.page_four.notifications": "Mae'r golofn hysbysiadau yn dangos pan mae rhywun yn ymwneud a chi.",
+  "onboarding.page_one.federation": "Mae mastodon yn rwydwaith o weinyddwyr anibynnol sy'n uno i greu un rhwydwaith gymdeithasol mwy. Yr ydym yn galw'r gweinyddwyr yma yn achosion.",
+  "onboarding.page_one.full_handle": "Your full handle",
+  "onboarding.page_one.handle_hint": "Dyma beth y bysech chi'n dweud wrth eich ffrindiau i chwilota amdano.",
+  "onboarding.page_one.welcome": "Croeso i Mastodon!",
+  "onboarding.page_six.admin": "Your instance's admin is {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": "Golygwch eich proffil i newid eich afatar, bywgraffiad, ac enw arddangos. Yno fe fyddwch hefyd yn canfod gosodiadau eraill.",
+  "onboarding.page_three.search": "Defnyddiwch y bar chwilio i ganfod pobl ac i edrych ar eu hashnodau, megis {illustration} ac {introductions}. I chwilio am rhywun nad ydynt ar yr achos hwn, defnyddiwch eu HANDLE llawn.",
+  "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": "Sgipiwch",
+  "privacy.change": "Addasu preifatrwdd y statws",
+  "privacy.direct.long": "Cyhoeddi i'r defnyddwyr sy'n cael eu crybwyll yn unig",
+  "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": "Forward to {target}",
+  "report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?",
+  "report.hint": "Bydd yr adroddiad yn cael ei anfon i arolygydd eich achos. Mae modd darparu esboniad o pam yr ydych yn cwyno am y cyfrif hwn isod:",
+  "report.placeholder": "Sylwadau ychwanegol",
+  "report.submit": "Cyflwyno",
+  "report.target": "Cwyno am {target}",
+  "search.placeholder": "Chwilio",
+  "search_popout.search_format": "Fformat chwilio uwch",
+  "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": "Mae testun syml yn dychwelyd enwau arddangos, enwau defnyddwyr a hashnodau sy'n cyfateb",
+  "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": "Golwg tu fewn...",
+  "status.block": "Blociwch @{name}",
+  "status.cancel_reblog_private": "Unboost",
+  "status.cannot_reblog": "Ni ellir sbarduno'r tŵt hwn",
+  "status.delete": "Dileu",
+  "status.detailed_status": "Golwg manwl o'r sgwrs",
+  "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": "Tawelu @{name}",
+  "status.mute_conversation": "Mute conversation",
+  "status.open": "Expand this status",
+  "status.pin": "Pin on profile",
+  "status.pinned": "Pinned toot",
+  "status.read_more": "Read more",
+  "status.reblog": "Boost",
+  "status.reblog_private": "Boost to original audience",
+  "status.reblogged_by": "{name} boosted",
+  "status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.",
+  "status.redraft": "Dilëwh & ailddrafftio",
+  "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": "Dad-dawelu sgwrs",
+  "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}} 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": "Describe for the visually impaired",
+  "upload_form.focus": "Crop",
+  "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 e3d040ea8..2848c187f 100644
--- a/app/javascript/mastodon/locales/da.json
+++ b/app/javascript/mastodon/locales/da.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Er du sikker på, du vil dæmpe {name}?",
   "confirmations.redraft.confirm": "Slet & omskriv",
   "confirmations.redraft.message": "Er du sikker på, du vil slette denne status og omskrive den? Favoritter og fremhævelser vil gå tabt og svar til det oprindelige opslag vil blive forældreløse.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Følg ikke længere",
   "confirmations.unfollow.message": "Er du sikker på, du ikke længere vil følge {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Indlejre denne status på din side ved at kopiere nedenstående kode.",
   "embed.preview": "Det kommer til at se således ud:",
   "emoji_button.activity": "Aktivitet",
@@ -294,6 +297,7 @@
   "status.open": "Udvid denne status",
   "status.pin": "Fastgør til profil",
   "status.pinned": "Fastgjort trut",
+  "status.read_more": "Read more",
   "status.reblog": "Fremhæv",
   "status.reblog_private": "Fremhæv til oprindeligt publikum",
   "status.reblogged_by": "{name} fremhævede",
diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json
index d798878fb..a263e2309 100644
--- a/app/javascript/mastodon/locales/de.json
+++ b/app/javascript/mastodon/locales/de.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Bist du dir sicher, dass du {name} stummschalten möchtest?",
   "confirmations.redraft.confirm": "Löschen und neu erstellen",
   "confirmations.redraft.message": "Bist du dir sicher, dass du diesen Status löschen und neu machen möchtest? Favoriten und Boosts werden verloren gehen und Antworten zu diesem Post werden verwaist sein.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Entfolgen",
   "confirmations.unfollow.message": "Bist du dir sicher, dass du {name} entfolgen möchtest?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Du kannst diesen Beitrag auf deiner Webseite einbetten, indem du den folgenden Code einfügst.",
   "embed.preview": "So wird es aussehen:",
   "emoji_button.activity": "Aktivitäten",
@@ -294,6 +297,7 @@
   "status.open": "Diesen Beitrag öffnen",
   "status.pin": "Im Profil anheften",
   "status.pinned": "Angehefteter Beitrag",
+  "status.read_more": "Read more",
   "status.reblog": "Teilen",
   "status.reblog_private": "An das eigentliche Publikum teilen",
   "status.reblogged_by": "{name} teilte",
diff --git a/app/javascript/mastodon/locales/defaultMessages.json b/app/javascript/mastodon/locales/defaultMessages.json
index b2ed49309..f613b6cb8 100644
--- a/app/javascript/mastodon/locales/defaultMessages.json
+++ b/app/javascript/mastodon/locales/defaultMessages.json
@@ -1050,6 +1050,15 @@
   {
     "descriptors": [
       {
+        "defaultMessage": "Last message:",
+        "id": "conversation.last_message"
+      }
+    ],
+    "path": "app/javascript/mastodon/features/direct_timeline/components/conversation.json"
+  },
+  {
+    "descriptors": [
+      {
         "defaultMessage": "Direct messages",
         "id": "column.direct"
       },
diff --git a/app/javascript/mastodon/locales/el.json b/app/javascript/mastodon/locales/el.json
index 4e4b733ec..5ef160955 100644
--- a/app/javascript/mastodon/locales/el.json
+++ b/app/javascript/mastodon/locales/el.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Σίγουρα θες να αποσιωπήσεις τον/την {name};",
   "confirmations.redraft.confirm": "Διαγραφή & ξαναγράψιμο",
   "confirmations.redraft.message": "Σίγουρα θέλεις να σβήσεις αυτή την κατάσταση και να την ξαναγράψεις; Οι αναφορές και τα αγαπημένα της θα χαθούν ενώ οι απαντήσεις προς αυτή θα μείνουν ορφανές.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Διακοπή παρακολούθησης",
   "confirmations.unfollow.message": "Σίγουρα θες να πάψεις να ακολουθείς τον/την {name};",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Ενσωματώστε αυτή την κατάσταση στην ιστοσελίδα σας αντιγράφοντας τον παρακάτω κώδικα.",
   "embed.preview": "Ορίστε πως θα φαίνεται:",
   "emoji_button.activity": "Δραστηριότητα",
@@ -274,7 +277,7 @@
   "search_results.accounts": "Άνθρωποι",
   "search_results.hashtags": "Ταμπέλες",
   "search_results.statuses": "Τουτ",
-  "search_results.total": "{count, number} {count, plural, one {result} other {results}}",
+  "search_results.total": "{count, number} {count, plural, ένα {result} υπόλοιπα {results}}",
   "standalone.public_title": "Μια πρώτη γεύση...",
   "status.block": "Block @{name}",
   "status.cancel_reblog_private": "Ακύρωσε την προώθηση",
@@ -294,6 +297,7 @@
   "status.open": "Διεύρυνε αυτή την κατάσταση",
   "status.pin": "Καρφίτσωσε στο προφίλ",
   "status.pinned": "Καρφιτσωμένο τουτ",
+  "status.read_more": "Read more",
   "status.reblog": "Προώθησε",
   "status.reblog_private": "Προώθησε στους αρχικούς παραλήπτες",
   "status.reblogged_by": "{name} προώθησε",
diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json
index 0d85ec744..b616d6c83 100644
--- a/app/javascript/mastodon/locales/en.json
+++ b/app/javascript/mastodon/locales/en.json
@@ -99,6 +99,7 @@
   "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Unfollow",
   "confirmations.unfollow.message": "Are you sure you want to unfollow {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Embed this status on your website by copying the code below.",
   "embed.preview": "Here is what it will look like:",
   "emoji_button.activity": "Activity",
diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json
index 86bee46b1..19e7a21e5 100644
--- a/app/javascript/mastodon/locales/eo.json
+++ b/app/javascript/mastodon/locales/eo.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Ĉu vi certas, ke vi volas silentigi {name}?",
   "confirmations.redraft.confirm": "Forigi kaj reskribi",
   "confirmations.redraft.message": "Ĉu vi certas, ke vi volas forigi tiun mesaĝon kaj reskribi ĝin? Vi perdos ĉiujn respondojn, diskonigojn kaj stelumojn ligitajn al ĝi.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Ne plu sekvi",
   "confirmations.unfollow.message": "Ĉu vi certas, ke vi volas ĉesi sekvi {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Enkorpigu ĉi tiun mesaĝon en vian retejon per kopio de la suba kodo.",
   "embed.preview": "Ĝi aperos tiel:",
   "emoji_button.activity": "Agadoj",
@@ -294,6 +297,7 @@
   "status.open": "Grandigi",
   "status.pin": "Alpingli profile",
   "status.pinned": "Alpinglita mesaĝo",
+  "status.read_more": "Read more",
   "status.reblog": "Diskonigi",
   "status.reblog_private": "Diskonigi al la originala atentaro",
   "status.reblogged_by": "{name} diskonigis",
diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json
index 63f197c28..1a71a1023 100644
--- a/app/javascript/mastodon/locales/es.json
+++ b/app/javascript/mastodon/locales/es.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "¿Estás seguro de que quieres silenciar a {name}?",
   "confirmations.redraft.confirm": "Borrar y volver a borrador",
   "confirmations.redraft.message": "Estás seguro de que quieres borrar este estado y volverlo a borrador? Perderás todas las respuestas, impulsos y favoritos asociados a él, y las respuestas a la publicación original quedarán huérfanos.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Dejar de seguir",
   "confirmations.unfollow.message": "¿Estás seguro de que quieres dejar de seguir a {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Añade este toot a tu sitio web con el siguiente código.",
   "embed.preview": "Así es como se verá:",
   "emoji_button.activity": "Actividad",
@@ -294,6 +297,7 @@
   "status.open": "Expandir estado",
   "status.pin": "Fijar",
   "status.pinned": "Toot fijado",
+  "status.read_more": "Read more",
   "status.reblog": "Retootear",
   "status.reblog_private": "Implusar a la audiencia original",
   "status.reblogged_by": "Retooteado por {name}",
diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json
index e4b1154b7..f088c07a8 100644
--- a/app/javascript/mastodon/locales/eu.json
+++ b/app/javascript/mastodon/locales/eu.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Ziur {name} mututu nahi duzula?",
   "confirmations.redraft.confirm": "Ezabatu eta berridatzi",
   "confirmations.redraft.message": "Ziur mezu hau ezabatu eta berridatzi nahi duzula? Gogokoak eta bultzadak galduko dira eta jaso dituen erantzunak umezurtz geratuko dira.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Utzi jarraitzeari",
   "confirmations.unfollow.message": "Ziur {name} jarraitzeari utzi nahi diozula?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Txertatu mezu hau zure webgunean beheko kodea kopatuz.",
   "embed.preview": "Hau da izango duen itxura:",
   "emoji_button.activity": "Jarduera",
@@ -294,6 +297,7 @@
   "status.open": "Hedatu mezu hau",
   "status.pin": "Finkatu profilean",
   "status.pinned": "Finkatutako toot-a",
+  "status.read_more": "Read more",
   "status.reblog": "Bultzada",
   "status.reblog_private": "Bultzada jatorrizko hartzaileei",
   "status.reblogged_by": "{name}(r)en bultzada",
diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json
index fb4ded11c..6a7964606 100644
--- a/app/javascript/mastodon/locales/fa.json
+++ b/app/javascript/mastodon/locales/fa.json
@@ -15,7 +15,7 @@
   "account.follows.empty": "این کاربر هنوز هیچ کسی را پی نمی‌گیرد.",
   "account.follows_you": "پیگیر شماست",
   "account.hide_reblogs": "پنهان کردن بازبوق‌های @{name}",
-  "account.link_verified_on": "Ownership of this link was checked on {date}",
+  "account.link_verified_on": "مالکیت این نشانی در تایخ {date} بررسی شد",
   "account.media": "عکس و ویدیو",
   "account.mention": "نام‌بردن از @{name}",
   "account.moved_to": "{name} منتقل شده است به:",
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "آیا واقعاً می‌خواهید {name} را بی‌صدا کنید؟",
   "confirmations.redraft.confirm": "پاک‌کردن و بازنویسی",
   "confirmations.redraft.message": "آیا واقعاً می‌خواهید این نوشته را پاک کنید و آن را از نو بنویسید؟ با این کار بازبوق‌ها و پسندیده‌شدن‌های آن از دست می‌رود و پاسخ‌ها به آن بی‌مرجع می‌شود.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "لغو پیگیری",
   "confirmations.unfollow.message": "آیا واقعاً می‌خواهید به پیگیری از {name} پایان دهید؟",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "برای جاگذاری این نوشته در سایت خودتان، کد زیر را کپی کنید.",
   "embed.preview": "نوشتهٔ جاگذاری‌شده این گونه به نظر خواهد رسید:",
   "emoji_button.activity": "فعالیت",
@@ -294,6 +297,7 @@
   "status.open": "این نوشته را باز کن",
   "status.pin": "نوشتهٔ ثابت نمایه",
   "status.pinned": "بوق ثابت",
+  "status.read_more": "Read more",
   "status.reblog": "بازبوقیدن",
   "status.reblog_private": "بازبوق به مخاطبان اولیه",
   "status.reblogged_by": "‫{name}‬ بازبوقید",
diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json
index caf949e8c..5a6752ce1 100644
--- a/app/javascript/mastodon/locales/fi.json
+++ b/app/javascript/mastodon/locales/fi.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Haluatko varmasti mykistää käyttäjän {name}?",
   "confirmations.redraft.confirm": "Delete & redraft",
   "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Lakkaa seuraamasta",
   "confirmations.unfollow.message": "Haluatko varmasti lakata seuraamasta käyttäjää {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Upota statuspäivitys sivullesi kopioimalla alla oleva koodi.",
   "embed.preview": "Se tulee näyttämään tältä:",
   "emoji_button.activity": "Aktiviteetit",
@@ -294,6 +297,7 @@
   "status.open": "Laajenna tilapäivitys",
   "status.pin": "Kiinnitä profiiliin",
   "status.pinned": "Kiinnitetty tuuttaus",
+  "status.read_more": "Read more",
   "status.reblog": "Buustaa",
   "status.reblog_private": "Buustaa alkuperäiselle yleisölle",
   "status.reblogged_by": "{name} buustasi",
diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json
index ff09a1402..4371e166c 100644
--- a/app/javascript/mastodon/locales/fr.json
+++ b/app/javascript/mastodon/locales/fr.json
@@ -15,7 +15,7 @@
   "account.follows.empty": "Cet utilisateur ne suit personne pour l'instant.",
   "account.follows_you": "Vous suit",
   "account.hide_reblogs": "Masquer les partages de @{name}",
-  "account.link_verified_on": "Ownership of this link was checked on {date}",
+  "account.link_verified_on": "La propriété de ce lien a été vérifiée le {date}",
   "account.media": "Média",
   "account.mention": "Mentionner",
   "account.moved_to": "{name} a déménagé vers :",
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Confirmez-vous le masquage de {name} ?",
   "confirmations.redraft.confirm": "Effacer et ré-écrire",
   "confirmations.redraft.message": "Êtes-vous sûr·e de vouloir effacer ce statut pour le ré-écrire ? Ses partages ainsi que ses mises en favori seront perdu·e·s et ses réponses seront orphelines.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Ne plus suivre",
   "confirmations.unfollow.message": "Voulez-vous arrêter de suivre {name} ?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Intégrez ce statut à votre site en copiant le code ci-dessous.",
   "embed.preview": "Il apparaîtra comme cela :",
   "emoji_button.activity": "Activités",
@@ -294,6 +297,7 @@
   "status.open": "Déplier ce statut",
   "status.pin": "Épingler sur le profil",
   "status.pinned": "Pouet épinglé",
+  "status.read_more": "Read more",
   "status.reblog": "Partager",
   "status.reblog_private": "Booster vers l’audience originale",
   "status.reblogged_by": "{name} a partagé :",
diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json
index 6afa21c9f..f3b1a533b 100644
--- a/app/javascript/mastodon/locales/gl.json
+++ b/app/javascript/mastodon/locales/gl.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Está segura de que quere acalar a {name}?",
   "confirmations.redraft.confirm": "Eliminar e reescribir",
   "confirmations.redraft.message": "Está segura de querer eliminar este estado e voltalo a escribir? Perderá réplicas e favoritas, e as respostas ao orixinal quedarán orfas.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Deixar de seguir",
   "confirmations.unfollow.message": "Quere deixar de seguir a {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Copie o código inferior para incrustar no seu sitio web este estado.",
   "embed.preview": "Así será mostrado:",
   "emoji_button.activity": "Actividade",
@@ -294,6 +297,7 @@
   "status.open": "Expandir este estado",
   "status.pin": "Fixar no perfil",
   "status.pinned": "Toot fixado",
+  "status.read_more": "Read more",
   "status.reblog": "Promover",
   "status.reblog_private": "Promover a audiencia orixinal",
   "status.reblogged_by": "{name} promoveu",
diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json
index d670d8a55..e20d4cd9a 100644
--- a/app/javascript/mastodon/locales/he.json
+++ b/app/javascript/mastodon/locales/he.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "להשתיק את {name}?",
   "confirmations.redraft.confirm": "Delete & redraft",
   "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "להפסיק מעקב",
   "confirmations.unfollow.message": "להפסיק מעקב אחרי {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "ניתן להטמיע את ההודעה באתרך ע\"י העתקת הקוד שלהלן.",
   "embed.preview": "דוגמא כיצד זה יראה:",
   "emoji_button.activity": "פעילות",
@@ -294,6 +297,7 @@
   "status.open": "הרחבת הודעה",
   "status.pin": "לקבע באודות",
   "status.pinned": "Pinned toot",
+  "status.read_more": "Read more",
   "status.reblog": "הדהוד",
   "status.reblog_private": "Boost to original audience",
   "status.reblogged_by": "הודהד על ידי {name}",
diff --git a/app/javascript/mastodon/locales/hr.json b/app/javascript/mastodon/locales/hr.json
index b76b82e1b..f3808d061 100644
--- a/app/javascript/mastodon/locales/hr.json
+++ b/app/javascript/mastodon/locales/hr.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Jesi li siguran da želiš utišati {name}?",
   "confirmations.redraft.confirm": "Delete & redraft",
   "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Unfollow",
   "confirmations.unfollow.message": "Are you sure you want to unfollow {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Embed this status on your website by copying the code below.",
   "embed.preview": "Here is what it will look like:",
   "emoji_button.activity": "Aktivnost",
@@ -294,6 +297,7 @@
   "status.open": "Proširi ovaj status",
   "status.pin": "Pin on profile",
   "status.pinned": "Pinned toot",
+  "status.read_more": "Read more",
   "status.reblog": "Podigni",
   "status.reblog_private": "Boost to original audience",
   "status.reblogged_by": "{name} je podigao",
diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json
index 57a8b7cfa..0ffb07173 100644
--- a/app/javascript/mastodon/locales/hu.json
+++ b/app/javascript/mastodon/locales/hu.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Biztos benne, hogy némítani szeretné {name}?",
   "confirmations.redraft.confirm": "Delete & redraft",
   "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Követés visszavonása",
   "confirmations.unfollow.message": "Biztos benne, hogy vissza szeretné vonni {name} követését?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Ágyazza be ezen státuszt weboldalába az alábbi kód másolásával.",
   "embed.preview": "Így fog kinézni:",
   "emoji_button.activity": "Aktivitás",
@@ -294,6 +297,7 @@
   "status.open": "Státusz kinagyítása",
   "status.pin": "Kitűzés a profilra",
   "status.pinned": "Pinned toot",
+  "status.read_more": "Read more",
   "status.reblog": "Reblog",
   "status.reblog_private": "Boost to original audience",
   "status.reblogged_by": "{name} reblogolta",
diff --git a/app/javascript/mastodon/locales/hy.json b/app/javascript/mastodon/locales/hy.json
index 077748a0a..b4f19c697 100644
--- a/app/javascript/mastodon/locales/hy.json
+++ b/app/javascript/mastodon/locales/hy.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Վստա՞հ ես, որ ուզում ես {name}֊ին լռեցնել։",
   "confirmations.redraft.confirm": "Delete & redraft",
   "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Ապահետեւել",
   "confirmations.unfollow.message": "Վստա՞հ ես, որ ուզում ես այլեւս չհետեւել {name}֊ին։",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Այս թութը քո կայքում ներդնելու համար կարող ես պատճենել ներքոհիշյալ կոդը։",
   "embed.preview": "Ահա, թե ինչ տեսք կունենա այն՝",
   "emoji_button.activity": "Զբաղմունքներ",
@@ -294,6 +297,7 @@
   "status.open": "Ընդարձակել այս թութը",
   "status.pin": "Ամրացնել անձնական էջում",
   "status.pinned": "Pinned toot",
+  "status.read_more": "Read more",
   "status.reblog": "Տարածել",
   "status.reblog_private": "Boost to original audience",
   "status.reblogged_by": "{name} տարածել է",
diff --git a/app/javascript/mastodon/locales/id.json b/app/javascript/mastodon/locales/id.json
index 3d80c0949..6d82269f4 100644
--- a/app/javascript/mastodon/locales/id.json
+++ b/app/javascript/mastodon/locales/id.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Apa anda yakin ingin membisukan {name}?",
   "confirmations.redraft.confirm": "Delete & redraft",
   "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Berhenti mengikuti",
   "confirmations.unfollow.message": "Apakah anda ingin berhenti mengikuti {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Sematkan status ini di website anda dengan menyalin kode di bawah ini.",
   "embed.preview": "Seperti ini nantinya:",
   "emoji_button.activity": "Aktivitas",
@@ -294,6 +297,7 @@
   "status.open": "Tampilkan status ini",
   "status.pin": "Pin on profile",
   "status.pinned": "Pinned toot",
+  "status.read_more": "Read more",
   "status.reblog": "Boost",
   "status.reblog_private": "Boost to original audience",
   "status.reblogged_by": "di-boost {name}",
diff --git a/app/javascript/mastodon/locales/io.json b/app/javascript/mastodon/locales/io.json
index 9059b3a2b..3df7e05ad 100644
--- a/app/javascript/mastodon/locales/io.json
+++ b/app/javascript/mastodon/locales/io.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Are you sure you want to mute {name}?",
   "confirmations.redraft.confirm": "Delete & redraft",
   "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Unfollow",
   "confirmations.unfollow.message": "Are you sure you want to unfollow {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Embed this status on your website by copying the code below.",
   "embed.preview": "Here is what it will look like:",
   "emoji_button.activity": "Activity",
@@ -294,6 +297,7 @@
   "status.open": "Detaligar ca mesajo",
   "status.pin": "Pin on profile",
   "status.pinned": "Pinned toot",
+  "status.read_more": "Read more",
   "status.reblog": "Repetar",
   "status.reblog_private": "Boost to original audience",
   "status.reblogged_by": "{name} repetita",
diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json
index 5d8e3fe4a..10d71c173 100644
--- a/app/javascript/mastodon/locales/it.json
+++ b/app/javascript/mastodon/locales/it.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Sei sicuro di voler silenziare {name}?",
   "confirmations.redraft.confirm": "Cancella e riscrivi",
   "confirmations.redraft.message": "Sei sicuro di voler cancellare questo stato e riscriverlo? Perderai tutte le risposte, condivisioni e preferiti.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Smetti di seguire",
   "confirmations.unfollow.message": "Sei sicuro che non vuoi più seguire {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Inserisci questo status nel tuo sito copiando il codice qui sotto.",
   "embed.preview": "Ecco come apparirà:",
   "emoji_button.activity": "Attività",
@@ -294,6 +297,7 @@
   "status.open": "Espandi questo post",
   "status.pin": "Fissa in cima sul profilo",
   "status.pinned": "Toot fissato in cima",
+  "status.read_more": "Read more",
   "status.reblog": "Condividi",
   "status.reblog_private": "Condividi con i destinatari iniziali",
   "status.reblogged_by": "{name} ha condiviso",
diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json
index ae2c7e3c4..a940d6ce1 100644
--- a/app/javascript/mastodon/locales/ja.json
+++ b/app/javascript/mastodon/locales/ja.json
@@ -15,7 +15,7 @@
   "account.follows.empty": "まだ誰もフォローしていません。",
   "account.follows_you": "フォローされています",
   "account.hide_reblogs": "@{name}さんからのブーストを非表示",
-  "account.link_verified_on": "Ownership of this link was checked on {date}",
+  "account.link_verified_on": "このリンクの所有権は{date}に確認されました",
   "account.media": "メディア",
   "account.mention": "@{name}さんにトゥート",
   "account.moved_to": "{name}さんは引っ越しました:",
@@ -95,10 +95,11 @@
   "confirmations.mute.message": "本当に{name}さんをミュートしますか?",
   "confirmations.redraft.confirm": "削除して下書きに戻す",
   "confirmations.redraft.message": "本当にこのトゥートを削除して下書きに戻しますか? このトゥートへのお気に入り登録やブーストは失われ、返信は孤立することになります。",
-  "confirmations.reply.confirm": "返信",
-  "confirmations.reply.message": "今返信すると現在作成中のメッセージが上書きされます。本当に実行しますか?",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "フォロー解除",
   "confirmations.unfollow.message": "本当に{name}さんのフォローを解除しますか?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "下記のコードをコピーしてウェブサイトに埋め込みます。",
   "embed.preview": "表示例:",
   "emoji_button.activity": "活動",
@@ -301,7 +302,7 @@
   "status.open": "詳細を表示",
   "status.pin": "プロフィールに固定表示",
   "status.pinned": "固定されたトゥート",
-  "status.read_more": "もっと見る",
+  "status.read_more": "Read more",
   "status.reblog": "ブースト",
   "status.reblog_private": "ブースト",
   "status.reblogged_by": "{name}さんがブースト",
diff --git a/app/javascript/mastodon/locales/ka.json b/app/javascript/mastodon/locales/ka.json
index 21cd7d644..d09371705 100644
--- a/app/javascript/mastodon/locales/ka.json
+++ b/app/javascript/mastodon/locales/ka.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "დარწმუნებული ხართ, გსურთ გააჩუმოთ {name}?",
   "confirmations.redraft.confirm": "გაუქმება და გადანაწილება",
   "confirmations.redraft.message": "დარწმუნებული ხართ, გსურთ გააუქმოთ ეს სტატუსი და გადაანაწილოთ? დაკარგავთ ყველა პასუხს, ბუსტს და მასზედ არსებულ ფავორიტს.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "ნუღარ მიჰყვები",
   "confirmations.unfollow.message": "დარწმუნებული ხართ, აღარ გსურთ მიჰყვებოდეთ {name}-ს?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "ეს სტატუსი ჩასვით თქვენს ვებ-საიტზე შემდეგი კოდის კოპირებით.",
   "embed.preview": "ესაა თუ როგორც გამოჩნდება:",
   "emoji_button.activity": "აქტივობა",
@@ -294,6 +297,7 @@
   "status.open": "ამ სტატუსის გაფართოება",
   "status.pin": "აპინე პროფილზე",
   "status.pinned": "აპინული ტუტი",
+  "status.read_more": "Read more",
   "status.reblog": "ბუსტი",
   "status.reblog_private": "დაიბუსტოს საწყის აუდიტორიაზე",
   "status.reblogged_by": "{name} დაიბუსტა",
diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json
index 8e0f9f59f..678433ff6 100644
--- a/app/javascript/mastodon/locales/ko.json
+++ b/app/javascript/mastodon/locales/ko.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "정말로 {name}를 뮤트하시겠습니까?",
   "confirmations.redraft.confirm": "삭제하고 다시 쓰기",
   "confirmations.redraft.message": "정말로 이 포스트를 삭제하고 다시 쓰시겠습니까? 해당 포스트에 대한 부스트와 즐겨찾기를 잃게 되고 원본에 대한 답장은 연결 되지 않습니다.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "언팔로우",
   "confirmations.unfollow.message": "정말로 {name}를 언팔로우하시겠습니까?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "아래의 코드를 복사하여 대화를 원하는 곳으로 공유하세요.",
   "embed.preview": "다음과 같이 표시됩니다:",
   "emoji_button.activity": "활동",
@@ -294,6 +297,7 @@
   "status.open": "상세 정보 표시",
   "status.pin": "고정",
   "status.pinned": "고정 된 툿",
+  "status.read_more": "Read more",
   "status.reblog": "부스트",
   "status.reblog_private": "원래의 수신자들에게 부스트",
   "status.reblogged_by": "{name}님이 부스트 했습니다",
diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json
index e6b85692c..6433f6211 100644
--- a/app/javascript/mastodon/locales/nl.json
+++ b/app/javascript/mastodon/locales/nl.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Weet je het zeker dat je {name} wilt negeren?",
   "confirmations.redraft.confirm": "Verwijderen en herschrijven",
   "confirmations.redraft.message": "Weet je zeker dat je deze toot wilt verwijderen en herschrijven? Je verliest wel de boosts en favorieten, en reacties op de originele toot zitten niet meer aan de nieuwe toot vast.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Ontvolgen",
   "confirmations.unfollow.message": "Weet je het zeker dat je {name} wilt ontvolgen?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Embed deze toot op jouw website, door de onderstaande code te kopiëren.",
   "embed.preview": "Zo komt het eruit te zien:",
   "emoji_button.activity": "Activiteiten",
@@ -294,6 +297,7 @@
   "status.open": "Toot volledig tonen",
   "status.pin": "Aan profielpagina vastmaken",
   "status.pinned": "Vastgemaakte toot",
+  "status.read_more": "Read more",
   "status.reblog": "Boost",
   "status.reblog_private": "Boost naar oorspronkelijke ontvangers",
   "status.reblogged_by": "{name} boostte",
diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json
index 4a8176e82..1105f2351 100644
--- a/app/javascript/mastodon/locales/no.json
+++ b/app/javascript/mastodon/locales/no.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Er du sikker på at du vil dempe {name}?",
   "confirmations.redraft.confirm": "Delete & redraft",
   "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Slutt å følge",
   "confirmations.unfollow.message": "Er du sikker på at du vil slutte å følge {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Kopier koden under for å bygge inn denne statusen på hjemmesiden din.",
   "embed.preview": "Slik kommer det til å se ut:",
   "emoji_button.activity": "Aktivitet",
@@ -294,6 +297,7 @@
   "status.open": "Utvid denne statusen",
   "status.pin": "Fest på profilen",
   "status.pinned": "Pinned toot",
+  "status.read_more": "Read more",
   "status.reblog": "Fremhev",
   "status.reblog_private": "Boost to original audience",
   "status.reblogged_by": "Fremhevd av {name}",
diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json
index 64cbaef55..d95beb2b5 100644
--- a/app/javascript/mastodon/locales/oc.json
+++ b/app/javascript/mastodon/locales/oc.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Volètz vertadièrament rescondre {name} ?",
   "confirmations.redraft.confirm": "Escafar & tornar formular",
   "confirmations.redraft.message": "Volètz vertadièrament escafar aqueste estatut e lo reformular ? Tote sos partiments e favorits seràn perduts, e sas responsas seràn orfanèlas.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Quitar de sègre",
   "confirmations.unfollow.message": "Volètz vertadièrament quitar de sègre {name} ?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Embarcar aqueste estatut per lo far veire sus un site Internet en copiar lo còdi çai-jos.",
   "embed.preview": "Semblarà aquò :",
   "emoji_button.activity": "Activitats",
@@ -294,6 +297,7 @@
   "status.open": "Desplegar aqueste estatut",
   "status.pin": "Penjar al perfil",
   "status.pinned": "Tut penjat",
+  "status.read_more": "Read more",
   "status.reblog": "Partejar",
   "status.reblog_private": "Partejar a l’audiéncia d’origina",
   "status.reblogged_by": "{name} a partejat",
diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json
index 76b340af3..8031f759d 100644
--- a/app/javascript/mastodon/locales/pl.json
+++ b/app/javascript/mastodon/locales/pl.json
@@ -99,6 +99,7 @@
   "confirmations.reply.message": "W ten sposób utracisz wpis który obecnie tworzysz. Czy na pewno chcesz to zrobić?",
   "confirmations.unfollow.confirm": "Przestań śledzić",
   "confirmations.unfollow.message": "Czy na pewno zamierzasz przestać śledzić {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Osadź ten wpis na swojej stronie wklejając poniższy kod.",
   "embed.preview": "Tak będzie to wyglądać:",
   "emoji_button.activity": "Aktywność",
diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json
index 3e5b5da8e..ac67a770f 100644
--- a/app/javascript/mastodon/locales/pt-BR.json
+++ b/app/javascript/mastodon/locales/pt-BR.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Você tem certeza de que quer silenciar {name}?",
   "confirmations.redraft.confirm": "Apagar & usar como rascunho",
   "confirmations.redraft.message": "Você tem certeza que deseja apagar esse status e usá-lo como rascunho? Você vai perder todas as respostas, compartilhamentos e favoritos relacionados a ele.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Deixar de seguir",
   "confirmations.unfollow.message": "Você tem certeza de que quer deixar de seguir {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Incorpore esta postagem em seu site copiando o código abaixo.",
   "embed.preview": "Aqui está uma previsão de como ficará:",
   "emoji_button.activity": "Atividades",
@@ -294,6 +297,7 @@
   "status.open": "Expandir",
   "status.pin": "Fixar no perfil",
   "status.pinned": "Toot fixado",
+  "status.read_more": "Read more",
   "status.reblog": "Compartilhar",
   "status.reblog_private": "Compartilhar com a audiência original",
   "status.reblogged_by": "{name} compartilhou",
diff --git a/app/javascript/mastodon/locales/pt.json b/app/javascript/mastodon/locales/pt.json
index e9d91f631..b2bf0f01d 100644
--- a/app/javascript/mastodon/locales/pt.json
+++ b/app/javascript/mastodon/locales/pt.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "De certeza que queres silenciar {name}?",
   "confirmations.redraft.confirm": "Delete & redraft",
   "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Deixar de seguir",
   "confirmations.unfollow.message": "De certeza que queres deixar de seguir {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Publicar este post num outro site copiando o código abaixo.",
   "embed.preview": "Podes ver aqui como irá ficar:",
   "emoji_button.activity": "Actividade",
@@ -294,6 +297,7 @@
   "status.open": "Expandir",
   "status.pin": "Fixar no perfil",
   "status.pinned": "Pinned toot",
+  "status.read_more": "Read more",
   "status.reblog": "Partilhar",
   "status.reblog_private": "Boost to original audience",
   "status.reblogged_by": "{name} partilhou",
diff --git a/app/javascript/mastodon/locales/ro.json b/app/javascript/mastodon/locales/ro.json
index 1d6e73bfd..c5f2c7607 100644
--- a/app/javascript/mastodon/locales/ro.json
+++ b/app/javascript/mastodon/locales/ro.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Ești sigur că vrei să oprești {name}?",
   "confirmations.redraft.confirm": "Șterge și salvează ca ciornă",
   "confirmations.redraft.message": "Ești sigur că vrei să faci asta? Tot ce ține de această postare, inclusiv răspunsurile vor fi deconectate.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Nu mai urmări",
   "confirmations.unfollow.message": "Ești sigur că nu mai vrei să îl urmărești pe {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Inserează această postare pe site-ul tău adăugând codul de mai jos.",
   "embed.preview": "Cam așa va arăta:",
   "emoji_button.activity": "Activitate",
@@ -294,6 +297,7 @@
   "status.open": "Extinde acest status",
   "status.pin": "Fixează pe profil",
   "status.pinned": "Postare fixată",
+  "status.read_more": "Read more",
   "status.reblog": "Redistribuie",
   "status.reblog_private": "Redistribuie către audiența originală",
   "status.reblogged_by": "{name} redistribuit",
diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json
index 15fbfac3f..b283b0976 100644
--- a/app/javascript/mastodon/locales/ru.json
+++ b/app/javascript/mastodon/locales/ru.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Вы уверены, что хотите заглушить {name}?",
   "confirmations.redraft.confirm": "Удалить и исправить",
   "confirmations.redraft.message": "Вы уверены, что хотите удалить этот статус и превратить в черновик? Вы потеряете все ответы, продвижения и отметки 'нравится' к нему.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Отписаться",
   "confirmations.unfollow.message": "Вы уверены, что хотите отписаться от {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Встройте этот статус на Вашем сайте, скопировав код внизу.",
   "embed.preview": "Так это будет выглядеть:",
   "emoji_button.activity": "Занятия",
@@ -294,6 +297,7 @@
   "status.open": "Развернуть статус",
   "status.pin": "Закрепить в профиле",
   "status.pinned": "Закреплённый статус",
+  "status.read_more": "Read more",
   "status.reblog": "Продвинуть",
   "status.reblog_private": "Продвинуть для своей аудитории",
   "status.reblogged_by": "{name} продвинул(а)",
diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json
index 11a6b76c1..c89922de8 100644
--- a/app/javascript/mastodon/locales/sk.json
+++ b/app/javascript/mastodon/locales/sk.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Naozaj chcete ignorovať {name}?",
   "confirmations.redraft.confirm": "Vyčistiť a prepísať",
   "confirmations.redraft.message": "Si si istý/á, že chceš premazať a prepísať tento príspevok? Jeho nadobudnuté odpovede, povýšenia a obľúbenia, ale i odpovede na pôvodný príspevok budú odlúčené.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Nesledovať",
   "confirmations.unfollow.message": "Naozaj chcete prestať sledovať {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Umiestni kód uvedený nižšie pre pridanie tohto statusu na tvoju web stránku.",
   "embed.preview": "Tu je ako to bude vyzerať:",
   "emoji_button.activity": "Aktivita",
@@ -294,6 +297,7 @@
   "status.open": "Otvoriť tento status",
   "status.pin": "Pripni na profil",
   "status.pinned": "Pripnutý príspevok",
+  "status.read_more": "Read more",
   "status.reblog": "Povýšiť",
   "status.reblog_private": "Povýš k pôvodnému publiku",
   "status.reblogged_by": "{name} povýšil/a",
diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json
index f715abe85..cb03849c2 100644
--- a/app/javascript/mastodon/locales/sl.json
+++ b/app/javascript/mastodon/locales/sl.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Ali ste prepričani, da želite utišati {name}?",
   "confirmations.redraft.confirm": "Delete & redraft",
   "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Prenehaj slediti",
   "confirmations.unfollow.message": "Ali ste prepričani, da ne želite več slediti {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Vstavi ta status na svojo spletno stran tako, da kopirate spodnjo kodo.",
   "embed.preview": "Tukaj je, kako bo izgledalo:",
   "emoji_button.activity": "Dejavnost",
@@ -294,6 +297,7 @@
   "status.open": "Expand this status",
   "status.pin": "Pin on profile",
   "status.pinned": "Pripeti tut",
+  "status.read_more": "Read more",
   "status.reblog": "Suni",
   "status.reblog_private": "Suni v prvotno občinstvo",
   "status.reblogged_by": "{name} sunjen",
diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json
index 7131d3044..4eab0a4ab 100644
--- a/app/javascript/mastodon/locales/sr-Latn.json
+++ b/app/javascript/mastodon/locales/sr-Latn.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Da li stvarno želite da ućutkate korisnika {name}?",
   "confirmations.redraft.confirm": "Delete & redraft",
   "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Otprati",
   "confirmations.unfollow.message": "Da li ste sigurni da želite da otpratite korisnika {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Ugradi ovaj status na Vaš veb sajt kopiranjem koda ispod.",
   "embed.preview": "Ovako će da izgleda:",
   "emoji_button.activity": "Aktivnost",
@@ -294,6 +297,7 @@
   "status.open": "Proširi ovaj status",
   "status.pin": "Prikači na profil",
   "status.pinned": "Pinned toot",
+  "status.read_more": "Read more",
   "status.reblog": "Podrži",
   "status.reblog_private": "Boost to original audience",
   "status.reblogged_by": "{name} podržao(la)",
diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json
index 806c0acb3..c5c33fb0c 100644
--- a/app/javascript/mastodon/locales/sr.json
+++ b/app/javascript/mastodon/locales/sr.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Да ли стварно желите да ућуткате корисника {name}?",
   "confirmations.redraft.confirm": "Избриши и преправи",
   "confirmations.redraft.message": "Да ли сте сигурни да желите да избришете овај статус и да га преправите? Сва стављања у омиљене трубе, као и подршке ће бити изгубљене, а одговори на оригинални пост ће бити поништени.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Отпрати",
   "confirmations.unfollow.message": "Да ли сте сигурни да желите да отпратите корисника {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Угради овај статус на Ваш веб сајт копирањем кода испод.",
   "embed.preview": "Овако ће да изгледа:",
   "emoji_button.activity": "Активност",
@@ -294,6 +297,7 @@
   "status.open": "Прошири овај статус",
   "status.pin": "Закачи на профил",
   "status.pinned": "Закачена труба",
+  "status.read_more": "Read more",
   "status.reblog": "Подржи",
   "status.reblog_private": "Подржи да види првобитна публика",
   "status.reblogged_by": "{name} подржао/ла",
diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json
index f9129d368..68fdf8d4e 100644
--- a/app/javascript/mastodon/locales/sv.json
+++ b/app/javascript/mastodon/locales/sv.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Är du säker du vill tysta ner {name}?",
   "confirmations.redraft.confirm": "Radera och gör om",
   "confirmations.redraft.message": "Är du säker på att du vill radera meddelandet och göra om det? Du kommer förlora alla svar, knuffar och favoriter som hänvisar till meddelandet.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Sluta följa",
   "confirmations.unfollow.message": "Är du säker på att du vill sluta följa {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Bädda in den här statusen på din webbplats genom att kopiera koden nedan.",
   "embed.preview": "Här ser du hur det kommer att se ut:",
   "emoji_button.activity": "Aktivitet",
@@ -294,6 +297,7 @@
   "status.open": "Utvidga denna status",
   "status.pin": "Fäst i profil",
   "status.pinned": "Fäst toot",
+  "status.read_more": "Read more",
   "status.reblog": "Knuff",
   "status.reblog_private": "Knuffa till de ursprungliga åhörarna",
   "status.reblogged_by": "{name} knuffade",
diff --git a/app/javascript/mastodon/locales/ta.json b/app/javascript/mastodon/locales/ta.json
index 427e9a3dc..38cf67e18 100644
--- a/app/javascript/mastodon/locales/ta.json
+++ b/app/javascript/mastodon/locales/ta.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Are you sure you want to mute {name}?",
   "confirmations.redraft.confirm": "Delete & redraft",
   "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Unfollow",
   "confirmations.unfollow.message": "Are you sure you want to unfollow {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Embed this status on your website by copying the code below.",
   "embed.preview": "Here is what it will look like:",
   "emoji_button.activity": "Activity",
@@ -294,6 +297,7 @@
   "status.open": "Expand this status",
   "status.pin": "Pin on profile",
   "status.pinned": "Pinned toot",
+  "status.read_more": "Read more",
   "status.reblog": "Boost",
   "status.reblog_private": "Boost to original audience",
   "status.reblogged_by": "{name} boosted",
diff --git a/app/javascript/mastodon/locales/te.json b/app/javascript/mastodon/locales/te.json
index bc13b02f1..eead75ff5 100644
--- a/app/javascript/mastodon/locales/te.json
+++ b/app/javascript/mastodon/locales/te.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "{name}ను మీరు ఖచ్చితంగా మ్యూట్ చేయాలనుకుంటున్నారా?",
   "confirmations.redraft.confirm": "తొలగించు & తిరగరాయు",
   "confirmations.redraft.message": "మీరు ఖచ్చితంగా ఈ స్టేటస్ ని తొలగించి తిరగరాయాలనుకుంటున్నారా? ఈ స్టేటస్ యొక్క బూస్ట్ లు మరియు ఇష్టాలు పోతాయి,మరియు ప్రత్యుత్తరాలు అనాధలు అయిపోతాయి.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "అనుసరించవద్దు",
   "confirmations.unfollow.message": "{name}ను మీరు ఖచ్చితంగా అనుసరించవద్దనుకుంటున్నారా?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "దిగువ కోడ్ను కాపీ చేయడం ద్వారా మీ వెబ్సైట్లో ఈ స్టేటస్ ని పొందుపరచండి.",
   "embed.preview": "అది ఈ క్రింది విధంగా కనిపిస్తుంది:",
   "emoji_button.activity": "కార్యకలాపాలు",
@@ -294,6 +297,7 @@
   "status.open": "ఈ స్టేటస్ ను విస్తరించు",
   "status.pin": "ప్రొఫైల్లో అతికించు",
   "status.pinned": "అతికించిన టూట్",
+  "status.read_more": "Read more",
   "status.reblog": "బూస్ట్",
   "status.reblog_private": "అసలు ప్రేక్షకులకు బూస్ట్ చేయి",
   "status.reblogged_by": "{name} బూస్ట్ చేసారు",
diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json
index 3114bca60..052f6b16a 100644
--- a/app/javascript/mastodon/locales/th.json
+++ b/app/javascript/mastodon/locales/th.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Are you sure you want to mute {name}?",
   "confirmations.redraft.confirm": "Delete & redraft",
   "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Unfollow",
   "confirmations.unfollow.message": "Are you sure you want to unfollow {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Embed this status on your website by copying the code below.",
   "embed.preview": "Here is what it will look like:",
   "emoji_button.activity": "Activity",
@@ -294,6 +297,7 @@
   "status.open": "Expand this status",
   "status.pin": "Pin on profile",
   "status.pinned": "Pinned toot",
+  "status.read_more": "Read more",
   "status.reblog": "Boost",
   "status.reblog_private": "Boost to original audience",
   "status.reblogged_by": "{name} boosted",
diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json
index a661b022b..fccbc55ec 100644
--- a/app/javascript/mastodon/locales/tr.json
+++ b/app/javascript/mastodon/locales/tr.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "{name} kullanıcısını sessize almak istiyor musunuz?",
   "confirmations.redraft.confirm": "Delete & redraft",
   "confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Unfollow",
   "confirmations.unfollow.message": "Are you sure you want to unfollow {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Embed this status on your website by copying the code below.",
   "embed.preview": "Here is what it will look like:",
   "emoji_button.activity": "Aktivite",
@@ -294,6 +297,7 @@
   "status.open": "Bu gönderiyi genişlet",
   "status.pin": "Pin on profile",
   "status.pinned": "Pinned toot",
+  "status.read_more": "Read more",
   "status.reblog": "Boost'la",
   "status.reblog_private": "Boost to original audience",
   "status.reblogged_by": "{name} boost etti",
diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json
index 116dfc489..6c2e8380b 100644
--- a/app/javascript/mastodon/locales/uk.json
+++ b/app/javascript/mastodon/locales/uk.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "Ви впевнені, що хочете заглушити {name}?",
   "confirmations.redraft.confirm": "Видалити і перестворити",
   "confirmations.redraft.message": "Ви впевнені, що хочете видалити допис і перестворити його? Ви втратите всі відповіді, передмухи та вподобайки допису.",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "Відписатися",
   "confirmations.unfollow.message": "Ви впевнені, що хочете відписатися від {name}?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "Інтегруйте цей статус на вашому вебсайті, скопіювавши код нижче.",
   "embed.preview": "Ось як він виглядатиме:",
   "emoji_button.activity": "Заняття",
@@ -294,6 +297,7 @@
   "status.open": "Розгорнути допис",
   "status.pin": "Pin on profile",
   "status.pinned": "Pinned toot",
+  "status.read_more": "Read more",
   "status.reblog": "Передмухнути",
   "status.reblog_private": "Boost to original audience",
   "status.reblogged_by": "{name} передмухнув(-ла)",
diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json
index 69ecd9431..b7937fc00 100644
--- a/app/javascript/mastodon/locales/zh-CN.json
+++ b/app/javascript/mastodon/locales/zh-CN.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "你确定要隐藏 {name} 吗?",
   "confirmations.redraft.confirm": "删除并重新编辑",
   "confirmations.redraft.message": "你确定要删除这条嘟文并重新编辑它吗?所有相关的回复、转嘟和收藏都会被清除。",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "取消关注",
   "confirmations.unfollow.message": "你确定要取消关注 {name} 吗?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "要在你的网站上嵌入这条嘟文,请复制以下代码。",
   "embed.preview": "它会像这样显示出来:",
   "emoji_button.activity": "活动",
@@ -294,6 +297,7 @@
   "status.open": "展开嘟文",
   "status.pin": "在个人资料页面置顶",
   "status.pinned": "置顶嘟文",
+  "status.read_more": "Read more",
   "status.reblog": "转嘟",
   "status.reblog_private": "转嘟给原有关注者",
   "status.reblogged_by": "{name} 转嘟了",
diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json
index fc5376699..af106312f 100644
--- a/app/javascript/mastodon/locales/zh-HK.json
+++ b/app/javascript/mastodon/locales/zh-HK.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "你確定要將{name}靜音嗎?",
   "confirmations.redraft.confirm": "刪除並編輯",
   "confirmations.redraft.message": "你確定要刪除並重新編輯嗎?所有相關的回覆、轉推與最愛都會被刪除。",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "取消關注",
   "confirmations.unfollow.message": "真的不要繼續關注 {name} 了嗎?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "要內嵌此文章,請將以下代碼貼進你的網站。",
   "embed.preview": "看上去會是這樣:",
   "emoji_button.activity": "活動",
@@ -294,6 +297,7 @@
   "status.open": "展開文章",
   "status.pin": "置頂到資料頁",
   "status.pinned": "置頂文章",
+  "status.read_more": "Read more",
   "status.reblog": "轉推",
   "status.reblog_private": "轉推到原讀者",
   "status.reblogged_by": "{name} 轉推",
diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json
index 458af6b95..454fd80db 100644
--- a/app/javascript/mastodon/locales/zh-TW.json
+++ b/app/javascript/mastodon/locales/zh-TW.json
@@ -91,8 +91,11 @@
   "confirmations.mute.message": "你確定要消音 {name} ?",
   "confirmations.redraft.confirm": "刪除 & 編輯",
   "confirmations.redraft.message": "你確定要刪除這條嘟文並重新編輯它嗎?所有相關的轉嘟與最愛都會被刪除,而對原始嘟文的回覆將會變成孤兒。",
+  "confirmations.reply.confirm": "Reply",
+  "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
   "confirmations.unfollow.confirm": "取消關注",
   "confirmations.unfollow.message": "真的不要繼續關注 {name} 了嗎?",
+  "conversation.last_message": "Last message:",
   "embed.instructions": "要內嵌此嘟文,請將以下代碼貼進你的網站。",
   "embed.preview": "看上去會變成這樣:",
   "emoji_button.activity": "活動",
@@ -294,6 +297,7 @@
   "status.open": "展開嘟文",
   "status.pin": "置頂到個人資訊頁",
   "status.pinned": "置頂嘟文",
+  "status.read_more": "Read more",
   "status.reblog": "轉嘟",
   "status.reblog_private": "轉嘟給原有關注者",
   "status.reblogged_by": "{name} 轉嘟了",
diff --git a/app/javascript/mastodon/reducers/conversations.js b/app/javascript/mastodon/reducers/conversations.js
index f339abf56..ea39fccee 100644
--- a/app/javascript/mastodon/reducers/conversations.js
+++ b/app/javascript/mastodon/reducers/conversations.js
@@ -1,9 +1,12 @@
 import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
 import {
+  CONVERSATIONS_MOUNT,
+  CONVERSATIONS_UNMOUNT,
   CONVERSATIONS_FETCH_REQUEST,
   CONVERSATIONS_FETCH_SUCCESS,
   CONVERSATIONS_FETCH_FAIL,
   CONVERSATIONS_UPDATE,
+  CONVERSATIONS_READ,
 } from '../actions/conversations';
 import compareId from '../compare_id';
 
@@ -11,10 +14,12 @@ const initialState = ImmutableMap({
   items: ImmutableList(),
   isLoading: false,
   hasMore: true,
+  mounted: false,
 });
 
 const conversationToMap = item => ImmutableMap({
   id: item.id,
+  unread: item.unread,
   accounts: ImmutableList(item.accounts.map(a => a.id)),
   last_status: item.last_status.id,
 });
@@ -73,6 +78,18 @@ export default function conversations(state = initialState, action) {
     return expandNormalizedConversations(state, action.conversations, action.next);
   case CONVERSATIONS_UPDATE:
     return updateConversation(state, action.conversation);
+  case CONVERSATIONS_MOUNT:
+    return state.update('mounted', count => count + 1);
+  case CONVERSATIONS_UNMOUNT:
+    return state.update('mounted', count => count - 1);
+  case CONVERSATIONS_READ:
+    return state.update('items', list => list.map(item => {
+      if (item.get('id') === action.id) {
+        return item.set('unread', false);
+      }
+
+      return item;
+    }));
   default:
     return state;
   }
diff --git a/app/javascript/mastodon/reducers/index.js b/app/javascript/mastodon/reducers/index.js
index d3b98d4f6..e98566e26 100644
--- a/app/javascript/mastodon/reducers/index.js
+++ b/app/javascript/mastodon/reducers/index.js
@@ -28,6 +28,7 @@ import lists from './lists';
 import listEditor from './list_editor';
 import filters from './filters';
 import conversations from './conversations';
+import suggestions from './suggestions';
 
 const reducers = {
   dropdown_menu,
@@ -59,6 +60,7 @@ const reducers = {
   listEditor,
   filters,
   conversations,
+  suggestions,
 };
 
 export default combineReducers(reducers);
diff --git a/app/javascript/mastodon/reducers/suggestions.js b/app/javascript/mastodon/reducers/suggestions.js
new file mode 100644
index 000000000..9f4b89d58
--- /dev/null
+++ b/app/javascript/mastodon/reducers/suggestions.js
@@ -0,0 +1,30 @@
+import {
+  SUGGESTIONS_FETCH_REQUEST,
+  SUGGESTIONS_FETCH_SUCCESS,
+  SUGGESTIONS_FETCH_FAIL,
+  SUGGESTIONS_DISMISS,
+} from '../actions/suggestions';
+import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable';
+
+const initialState = ImmutableMap({
+  items: ImmutableList(),
+  isLoading: false,
+});
+
+export default function suggestionsReducer(state = initialState, action) {
+  switch(action.type) {
+  case SUGGESTIONS_FETCH_REQUEST:
+    return state.set('isLoading', true);
+  case SUGGESTIONS_FETCH_SUCCESS:
+    return state.withMutations(map => {
+      map.set('items', fromJS(action.accounts.map(x => x.id)));
+      map.set('isLoading', false);
+    });
+  case SUGGESTIONS_FETCH_FAIL:
+    return state.set('isLoading', false);
+  case SUGGESTIONS_DISMISS:
+    return state.update('items', list => list.filterNot(id => id === action.id));
+  default:
+    return state;
+  }
+};
diff --git a/app/javascript/styles/mastodon-light/diff.scss b/app/javascript/styles/mastodon-light/diff.scss
index ac161a004..78bc2dbb6 100644
--- a/app/javascript/styles/mastodon-light/diff.scss
+++ b/app/javascript/styles/mastodon-light/diff.scss
@@ -286,20 +286,6 @@
   }
 }
 
-.flash-message {
-  box-shadow: none;
-
-  &.notice {
-    background: rgba($success-green, 0.5);
-    color: lighten($success-green, 12%);
-  }
-
-  &.alert {
-    background: rgba($error-red, 0.5);
-    color: lighten($error-red, 12%);
-  }
-}
-
 .simple_form,
 .table-form {
   .warning {
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index 6aabf5777..f8eb37c58 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -801,7 +801,7 @@
   padding: 8px 10px;
   padding-left: 68px;
   position: relative;
-  min-height: 48px;
+  min-height: 54px;
   border-bottom: 1px solid lighten($ui-base-color, 8%);
   cursor: default;
 
@@ -823,7 +823,7 @@
     margin-top: 8px;
   }
 
-  &.status-direct {
+  &.status-direct:not(.read) {
     background: lighten($ui-base-color, 8%);
     border-bottom-color: lighten($ui-base-color, 12%);
   }
@@ -1133,6 +1133,18 @@
     vertical-align: middle;
     margin-right: 5px;
   }
+
+  &-composite {
+    @include avatar-radius();
+    overflow: hidden;
+
+    & > div {
+      @include avatar-radius();
+      float: left;
+      position: relative;
+      box-sizing: border-box;
+    }
+  }
 }
 
 a .account__avatar {
@@ -5497,44 +5509,3 @@ noscript {
     }
   }
 }
-
-.conversation {
-  padding: 14px 10px;
-  border-bottom: 1px solid lighten($ui-base-color, 8%);
-  cursor: pointer;
-
-  &__header {
-    display: flex;
-    margin-bottom: 15px;
-  }
-
-  &__avatars {
-    overflow: hidden;
-    flex: 1 1 auto;
-
-    & > div {
-      display: flex;
-      flex-wrap: none;
-      width: 900px;
-    }
-
-    .account__avatar {
-      margin-right: 10px;
-    }
-  }
-
-  &__time {
-    flex: 0 0 auto;
-    font-size: 14px;
-    color: $darker-text-color;
-    text-align: right;
-
-    .display-name {
-      color: $secondary-text-color;
-    }
-  }
-
-  .attachment-list.compact {
-    margin-top: 15px;
-  }
-}
diff --git a/app/javascript/styles/mastodon/forms.scss b/app/javascript/styles/mastodon/forms.scss
index be2bf7cea..8c4c934ea 100644
--- a/app/javascript/styles/mastodon/forms.scss
+++ b/app/javascript/styles/mastodon/forms.scss
@@ -427,7 +427,7 @@ code {
 
     &__append {
       position: absolute;
-      right: 1px;
+      right: 3px;
       top: 1px;
       padding: 10px;
       padding-bottom: 9px;
@@ -460,9 +460,20 @@ code {
   border-radius: 4px;
   padding: 15px 10px;
   margin-bottom: 30px;
-  box-shadow: 0 0 5px rgba($base-shadow-color, 0.2);
   text-align: center;
 
+  &.notice {
+    border: 1px solid rgba($valid-value-color, 0.5);
+    background: rgba($valid-value-color, 0.25);
+    color: $valid-value-color;
+  }
+
+  &.alert {
+    border: 1px solid rgba($error-value-color, 0.5);
+    background: rgba($error-value-color, 0.25);
+    color: $error-value-color;
+  }
+
   p {
     margin-bottom: 15px;
   }
@@ -551,12 +562,12 @@ code {
 .oauth-prompt,
 .follow-prompt {
   margin-bottom: 30px;
-  text-align: center;
   color: $darker-text-color;
 
   h2 {
     font-size: 16px;
     margin-bottom: 30px;
+    text-align: center;
   }
 
   strong {
diff --git a/app/javascript/styles/mastodon/rtl.scss b/app/javascript/styles/mastodon/rtl.scss
index 9644f8e02..a86e3e632 100644
--- a/app/javascript/styles/mastodon/rtl.scss
+++ b/app/javascript/styles/mastodon/rtl.scss
@@ -73,7 +73,7 @@ body.rtl {
     float: left;
   }
 
-  .setting-toggle {
+  .setting-toggle__label {
     margin-left: 0;
     margin-right: 8px;
   }
@@ -196,6 +196,10 @@ body.rtl {
     right: -2.14285714em;
   }
 
+  .admin-wrapper {
+    direction: rtl;
+  }
+
   .admin-wrapper .sidebar ul a i.fa,
   a.table-action-link i.fa {
     margin-right: 0;
@@ -214,22 +218,47 @@ body.rtl {
     right: 0;
   }
 
+  .simple_form .input.radio_buttons .radio {
+    left: auto;
+    right: 0;
+  }
+
+  .simple_form .input.radio_buttons .radio > label {
+    padding-right: 28px;
+    padding-left: 0;
+  }
+
   .simple_form .input-with-append .input input {
     padding-left: 142px;
     padding-right: 0;
   }
 
-  .simple_form .input-with-append .append {
+  .simple_form .input.boolean label.checkbox {
+    left: auto;
+    right: 0;
+  }
+
+  .simple_form .input.boolean .label_input,
+  .simple_form .input.boolean .hint {
+    padding-left: 0;
+    padding-right: 28px;
+  }
+
+  .simple_form .label_input__append {
     right: auto;
-    left: 0;
+    left: 3px;
 
     &::after {
       right: auto;
       left: 0;
-      background-image: linear-gradient(to left, rgba($ui-base-color, 0), $ui-base-color);
+      background-image: linear-gradient(to left, rgba(darken($ui-base-color, 10%), 0), darken($ui-base-color, 10%));
     }
   }
 
+  .simple_form select {
+    background: darken($ui-base-color, 10%) url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14.933 18.467' height='19.698' width='15.929'><path d='M3.467 14.967l-3.393-3.5H14.86l-3.392 3.5c-1.866 1.925-3.666 3.5-4 3.5-.335 0-2.135-1.575-4-3.5zm.266-11.234L7.467 0 11.2 3.733l3.733 3.734H0l3.733-3.734z' fill='#{hex-color(lighten($ui-base-color, 12%))}'/></svg>") no-repeat left 8px center / auto 16px;
+  }
+
   .table th,
   .table td {
     text-align: right;
@@ -245,6 +274,10 @@ body.rtl {
     left: auto;
   }
 
+  .landing-page__call-to-action .row__information-board {
+    direction: rtl;
+  }
+
   .landing-page .header .hero .floats .float-1 {
     left: -120px;
     right: auto;
@@ -308,4 +341,22 @@ body.rtl {
       margin-right: 20px;
     }
   }
+
+  .landing-page__information {
+    .account__display-name {
+      margin-right: 0;
+      margin-left: 5px;
+    }
+
+    .account__avatar-wrapper {
+      margin-left: 12px;
+      margin-right: 0;
+    }
+  }
+
+  .card__bar .display-name {
+    margin-left: 0;
+    margin-right: 15px;
+    text-align: right;
+  }
 }
diff --git a/app/javascript/styles/mastodon/stream_entries.scss b/app/javascript/styles/mastodon/stream_entries.scss
index 14306c8bd..d8bd30377 100644
--- a/app/javascript/styles/mastodon/stream_entries.scss
+++ b/app/javascript/styles/mastodon/stream_entries.scss
@@ -3,7 +3,6 @@
   border-radius: 4px;
   overflow: hidden;
   margin-bottom: 10px;
-  text-align: left;
 
   @media screen and (max-width: $no-gap-breakpoint) {
     margin-bottom: 0;
diff --git a/app/lib/activitypub/activity.rb b/app/lib/activitypub/activity.rb
index 3a39b723e..999954cb5 100644
--- a/app/lib/activitypub/activity.rb
+++ b/app/lib/activitypub/activity.rb
@@ -96,7 +96,7 @@ class ActivityPub::Activity
   end
 
   def notify_about_mentions(status)
-    status.mentions.includes(:account).each do |mention|
+    status.active_mentions.includes(:account).each do |mention|
       next unless mention.account.local? && audience_includes?(mention.account)
       NotifyService.new.call(mention.account, mention)
     end
diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb
index 978289788..7e6702a63 100644
--- a/app/lib/activitypub/activity/create.rb
+++ b/app/lib/activitypub/activity/create.rb
@@ -22,12 +22,17 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
   private
 
   def process_status
-    status_params = process_status_params
+    @tags     = []
+    @mentions = []
+    @params   = {}
 
-    ApplicationRecord.transaction do
-      @status = Status.create!(status_params)
+    process_status_params
+    process_tags
+    process_audience
 
-      process_tags(@status)
+    ApplicationRecord.transaction do
+      @status = Status.create!(@params)
+      attach_tags(@status)
     end
 
     resolve_thread(@status)
@@ -42,62 +47,98 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
   end
 
   def process_status_params
-    {
-      uri: @object['id'],
-      url: object_url || @object['id'],
-      account: @account,
-      text: text_from_content || '',
-      language: detected_language,
-      spoiler_text: text_from_summary || '',
-      created_at: @object['published'],
-      override_timestamps: @options[:override_timestamps],
-      reply: @object['inReplyTo'].present?,
-      sensitive: @object['sensitive'] || false,
-      visibility: visibility_from_audience,
-      thread: replied_to_status,
-      conversation: conversation_from_uri(@object['conversation']),
-      media_attachment_ids: process_attachments.take(4).map(&:id),
-    }
-  end
-
-  def process_tags(status)
+    @params = begin
+      {
+        uri: @object['id'],
+        url: object_url || @object['id'],
+        account: @account,
+        text: text_from_content || '',
+        language: detected_language,
+        spoiler_text: text_from_summary || '',
+        created_at: @object['published'],
+        override_timestamps: @options[:override_timestamps],
+        reply: @object['inReplyTo'].present?,
+        sensitive: @object['sensitive'] || false,
+        visibility: visibility_from_audience,
+        thread: replied_to_status,
+        conversation: conversation_from_uri(@object['conversation']),
+        media_attachment_ids: process_attachments.take(4).map(&:id),
+      }
+    end
+  end
+
+  def process_audience
+    (as_array(@object['to']) + as_array(@object['cc'])).uniq.each do |audience|
+      next if audience == ActivityPub::TagManager::COLLECTIONS[:public]
+
+      # Unlike with tags, there is no point in resolving accounts we don't already
+      # know here, because silent mentions would only be used for local access
+      # control anyway
+      account = account_from_uri(audience)
+
+      next if account.nil? || @mentions.any? { |mention| mention.account_id == account.id }
+
+      @mentions << Mention.new(account: account, silent: true)
+
+      # If there is at least one silent mention, then the status can be considered
+      # as a limited-audience status, and not strictly a direct message
+      next unless @params[:visibility] == :direct
+
+      @params[:visibility] = :limited
+    end
+  end
+
+  def attach_tags(status)
+    @tags.each do |tag|
+      status.tags << tag
+      TrendingTags.record_use!(tag, status.account, status.created_at) if status.public_visibility?
+    end
+
+    @mentions.each do |mention|
+      mention.status = status
+      mention.save
+    end
+  end
+
+  def process_tags
     return if @object['tag'].nil?
 
     as_array(@object['tag']).each do |tag|
       if equals_or_includes?(tag['type'], 'Hashtag')
-        process_hashtag tag, status
+        process_hashtag tag
       elsif equals_or_includes?(tag['type'], 'Mention')
-        process_mention tag, status
+        process_mention tag
       elsif equals_or_includes?(tag['type'], 'Emoji')
-        process_emoji tag, status
+        process_emoji tag
       end
     end
   end
 
-  def process_hashtag(tag, status)
+  def process_hashtag(tag)
     return if tag['name'].blank?
 
     hashtag = tag['name'].gsub(/\A#/, '').mb_chars.downcase
     hashtag = Tag.where(name: hashtag).first_or_create(name: hashtag)
 
-    return if status.tags.include?(hashtag)
+    return if @tags.include?(hashtag)
 
-    status.tags << hashtag
-    TrendingTags.record_use!(hashtag, status.account, status.created_at) if status.public_visibility?
+    @tags << hashtag
   rescue ActiveRecord::RecordInvalid
     nil
   end
 
-  def process_mention(tag, status)
+  def process_mention(tag)
     return if tag['href'].blank?
 
     account = account_from_uri(tag['href'])
     account = ::FetchRemoteAccountService.new.call(tag['href'], id: false) if account.nil?
+
     return if account.nil?
-    account.mentions.create(status: status)
+
+    @mentions << Mention.new(account: account, silent: false)
   end
 
-  def process_emoji(tag, _status)
+  def process_emoji(tag)
     return if skip_download?
     return if tag['name'].blank? || tag['icon'].blank? || tag['icon']['url'].blank?
 
diff --git a/app/lib/activitypub/activity/flag.rb b/app/lib/activitypub/activity/flag.rb
index 36d3c5730..92e59bb81 100644
--- a/app/lib/activitypub/activity/flag.rb
+++ b/app/lib/activitypub/activity/flag.rb
@@ -2,6 +2,8 @@
 
 class ActivityPub::Activity::Flag < ActivityPub::Activity
   def perform
+    return if skip_reports?
+
     target_accounts            = object_uris.map { |uri| account_from_uri(uri) }.compact.select(&:local?)
     target_statuses_by_account = object_uris.map { |uri| status_from_uri(uri) }.compact.select(&:local?).group_by(&:account_id)
 
@@ -19,6 +21,12 @@ class ActivityPub::Activity::Flag < ActivityPub::Activity
     end
   end
 
+  private
+
+  def skip_reports?
+    DomainBlock.find_by(domain: @account.domain)&.reject_reports?
+  end
+
   def object_uris
     @object_uris ||= Array(@object.is_a?(Array) ? @object.map { |item| value_or_id(item) } : value_or_id(@object))
   end
diff --git a/app/lib/activitypub/tag_manager.rb b/app/lib/activitypub/tag_manager.rb
index 95d1cf9f3..be3a562d0 100644
--- a/app/lib/activitypub/tag_manager.rb
+++ b/app/lib/activitypub/tag_manager.rb
@@ -58,8 +58,8 @@ class ActivityPub::TagManager
       [COLLECTIONS[:public]]
     when 'unlisted', 'private'
       [account_followers_url(status.account)]
-    when 'direct'
-      status.mentions.map { |mention| uri_for(mention.account) }
+    when 'direct', 'limited'
+      status.active_mentions.map { |mention| uri_for(mention.account) }
     end
   end
 
@@ -80,7 +80,7 @@ class ActivityPub::TagManager
       cc << COLLECTIONS[:public]
     end
 
-    cc.concat(status.mentions.map { |mention| uri_for(mention.account) }) unless status.direct_visibility?
+    cc.concat(status.active_mentions.map { |mention| uri_for(mention.account) }) unless status.direct_visibility? || status.limited_visibility?
 
     cc
   end
diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb
index b10e5dd24..3d7db2721 100644
--- a/app/lib/feed_manager.rb
+++ b/app/lib/feed_manager.rb
@@ -88,7 +88,7 @@ class FeedManager
     end
 
     query.each do |status|
-      next if status.direct_visibility? || filter?(:home, status, into_account)
+      next if status.direct_visibility? || status.limited_visibility? || filter?(:home, status, into_account)
       add_to_feed(:home, into_account.id, status)
     end
 
@@ -156,12 +156,12 @@ class FeedManager
     return true  if status.reply? && (status.in_reply_to_id.nil? || status.in_reply_to_account_id.nil?)
     return true  if phrase_filtered?(status, receiver_id, :home)
 
-    check_for_blocks = status.mentions.pluck(:account_id)
+    check_for_blocks = status.active_mentions.pluck(:account_id)
     check_for_blocks.concat([status.account_id])
 
     if status.reblog?
       check_for_blocks.concat([status.reblog.account_id])
-      check_for_blocks.concat(status.reblog.mentions.pluck(:account_id))
+      check_for_blocks.concat(status.reblog.active_mentions.pluck(:account_id))
     end
 
     return true if blocks_or_mutes?(receiver_id, check_for_blocks, :home)
@@ -188,7 +188,7 @@ class FeedManager
     # This filter is called from NotifyService, but already after the sender of
     # the notification has been checked for mute/block. Therefore, it's not
     # necessary to check the author of the toot for mute/block again
-    check_for_blocks = status.mentions.pluck(:account_id)
+    check_for_blocks = status.active_mentions.pluck(:account_id)
     check_for_blocks.concat([status.in_reply_to_account]) if status.reply? && !status.in_reply_to_account_id.nil?
 
     should_filter   = blocks_or_mutes?(receiver_id, check_for_blocks, :mentions)                                                         # Filter if it's from someone I blocked, in reply to someone I blocked, or mentioning someone I blocked (or muted)
diff --git a/app/lib/formatter.rb b/app/lib/formatter.rb
index 35d5a09b7..d13884ec8 100644
--- a/app/lib/formatter.rb
+++ b/app/lib/formatter.rb
@@ -27,7 +27,7 @@ class Formatter
       return html.html_safe # rubocop:disable Rails/OutputSafety
     end
 
-    linkable_accounts = status.mentions.map(&:account)
+    linkable_accounts = status.active_mentions.map(&:account)
     linkable_accounts << status.account
 
     html = raw_content
diff --git a/app/lib/ostatus/atom_serializer.rb b/app/lib/ostatus/atom_serializer.rb
index 1a0a635b3..7a181fb40 100644
--- a/app/lib/ostatus/atom_serializer.rb
+++ b/app/lib/ostatus/atom_serializer.rb
@@ -354,7 +354,7 @@ class OStatus::AtomSerializer
     append_element(entry, 'summary', status.spoiler_text, 'xml:lang': status.language) if status.spoiler_text?
     append_element(entry, 'content', Formatter.instance.format(status).to_str || '.', type: 'html', 'xml:lang': status.language)
 
-    status.mentions.sort_by(&:id).each do |mentioned|
+    status.active_mentions.sort_by(&:id).each do |mentioned|
       append_element(entry, 'link', nil, rel: :mentioned, 'ostatus:object-type': OStatus::TagManager::TYPES[:person], href: OStatus::TagManager.instance.uri_for(mentioned.account))
     end
 
diff --git a/app/models/account_conversation.rb b/app/models/account_conversation.rb
index a7205ec1a..b7447d805 100644
--- a/app/models/account_conversation.rb
+++ b/app/models/account_conversation.rb
@@ -10,6 +10,7 @@
 #  status_ids              :bigint(8)        default([]), not null, is an Array
 #  last_status_id          :bigint(8)
 #  lock_version            :integer          default(0), not null
+#  unread                  :boolean          default(FALSE), not null
 #
 
 class AccountConversation < ApplicationRecord
@@ -58,6 +59,7 @@ class AccountConversation < ApplicationRecord
     def add_status(recipient, status)
       conversation = find_or_initialize_by(account: recipient, conversation_id: status.conversation_id, participant_account_ids: participants_from_status(recipient, status))
       conversation.status_ids << status.id
+      conversation.unread = status.account_id != recipient.id
       conversation.save
       conversation
     rescue ActiveRecord::StaleObjectError
@@ -85,7 +87,7 @@ class AccountConversation < ApplicationRecord
     private
 
     def participants_from_status(recipient, status)
-      ((status.mentions.pluck(:account_id) + [status.account_id]).uniq - [recipient.id]).sort
+      ((status.active_mentions.pluck(:account_id) + [status.account_id]).uniq - [recipient.id]).sort
     end
   end
 
diff --git a/app/models/domain_block.rb b/app/models/domain_block.rb
index 93658793b..b828a9d71 100644
--- a/app/models/domain_block.rb
+++ b/app/models/domain_block.rb
@@ -3,12 +3,13 @@
 #
 # Table name: domain_blocks
 #
-#  id           :bigint(8)        not null, primary key
-#  domain       :string           default(""), not null
-#  created_at   :datetime         not null
-#  updated_at   :datetime         not null
-#  severity     :integer          default("silence")
-#  reject_media :boolean          default(FALSE), not null
+#  id             :bigint(8)        not null, primary key
+#  domain         :string           default(""), not null
+#  created_at     :datetime         not null
+#  updated_at     :datetime         not null
+#  severity       :integer          default("silence")
+#  reject_media   :boolean          default(FALSE), not null
+#  reject_reports :boolean          default(FALSE), not null
 #
 
 class DomainBlock < ApplicationRecord
diff --git a/app/models/mention.rb b/app/models/mention.rb
index 8ab886b18..d01a88e32 100644
--- a/app/models/mention.rb
+++ b/app/models/mention.rb
@@ -8,6 +8,7 @@
 #  created_at :datetime         not null
 #  updated_at :datetime         not null
 #  account_id :bigint(8)
+#  silent     :boolean          default(FALSE), not null
 #
 
 class Mention < ApplicationRecord
@@ -18,10 +19,17 @@ class Mention < ApplicationRecord
 
   validates :account, uniqueness: { scope: :status }
 
+  scope :active, -> { where(silent: false) }
+  scope :silent, -> { where(silent: true) }
+
   delegate(
     :username,
     :acct,
     to: :account,
     prefix: true
   )
+
+  def active?
+    !silent?
+  end
 end
diff --git a/app/models/notification.rb b/app/models/notification.rb
index b9bec0808..78b180301 100644
--- a/app/models/notification.rb
+++ b/app/models/notification.rb
@@ -24,7 +24,7 @@ class Notification < ApplicationRecord
     favourite:      'Favourite',
   }.freeze
 
-  STATUS_INCLUDES = [:account, :application, :stream_entry, :media_attachments, :tags, mentions: :account, reblog: [:stream_entry, :account, :application, :media_attachments, :tags, mentions: :account]].freeze
+  STATUS_INCLUDES = [:account, :application, :media_attachments, :tags, active_mentions: :account, reblog: [:account, :application, :media_attachments, :tags, active_mentions: :account]].freeze
 
   belongs_to :account, optional: true
   belongs_to :from_account, class_name: 'Account', optional: true
diff --git a/app/models/status.rb b/app/models/status.rb
index ad25cc8df..438863589 100644
--- a/app/models/status.rb
+++ b/app/models/status.rb
@@ -39,7 +39,7 @@ class Status < ApplicationRecord
 
   update_index('statuses#status', :proper) if Chewy.enabled?
 
-  enum visibility: [:public, :unlisted, :private, :direct], _suffix: :visibility
+  enum visibility: [:public, :unlisted, :private, :direct, :limited], _suffix: :visibility
 
   belongs_to :application, class_name: 'Doorkeeper::Application', optional: true
 
@@ -54,7 +54,8 @@ class Status < ApplicationRecord
   has_many :bookmarks, inverse_of: :status, dependent: :destroy
   has_many :reblogs, foreign_key: 'reblog_of_id', class_name: 'Status', inverse_of: :reblog, dependent: :destroy
   has_many :replies, foreign_key: 'in_reply_to_id', class_name: 'Status', inverse_of: :thread
-  has_many :mentions, dependent: :destroy
+  has_many :mentions, dependent: :destroy, inverse_of: :status
+  has_many :active_mentions, -> { active }, class_name: 'Mention', inverse_of: :status
   has_many :media_attachments, dependent: :nullify
 
   has_and_belongs_to_many :tags
@@ -94,7 +95,7 @@ class Status < ApplicationRecord
                    :status_stat,
                    :tags,
                    :stream_entry,
-                   mentions: :account,
+                   active_mentions: :account,
                    reblog: [
                      :account,
                      :application,
@@ -103,7 +104,7 @@ class Status < ApplicationRecord
                      :media_attachments,
                      :conversation,
                      :status_stat,
-                     mentions: :account,
+                     active_mentions: :account,
                    ],
                    thread: :account
 
@@ -176,7 +177,11 @@ class Status < ApplicationRecord
   end
 
   def hidden?
-    private_visibility? || direct_visibility?
+    private_visibility? || direct_visibility? || limited_visibility?
+  end
+
+  def distributable?
+    public_visibility? || unlisted_visibility?
   end
 
   def with_media?
@@ -240,6 +245,10 @@ class Status < ApplicationRecord
       left_outer_joins(:status_stat).select('statuses.id, greatest(statuses.updated_at, status_stats.updated_at) AS updated_at')
     end
 
+    def selectable_visibilities
+      visibilities.keys - %w(direct limited)
+    end
+
     def in_chosen_languages(account)
       where(language: nil).or where(language: account.chosen_languages)
     end
diff --git a/app/models/stream_entry.rb b/app/models/stream_entry.rb
index dd383eb81..edd30487e 100644
--- a/app/models/stream_entry.rb
+++ b/app/models/stream_entry.rb
@@ -48,7 +48,7 @@ class StreamEntry < ApplicationRecord
   end
 
   def mentions
-    orphaned? ? [] : status.mentions.map(&:account)
+    orphaned? ? [] : status.active_mentions.map(&:account)
   end
 
   private
diff --git a/app/policies/status_policy.rb b/app/policies/status_policy.rb
index fcf19db62..5e3282681 100644
--- a/app/policies/status_policy.rb
+++ b/app/policies/status_policy.rb
@@ -14,7 +14,7 @@ class StatusPolicy < ApplicationPolicy
   def show?
     return false if local_only? && (current_account.nil? || !current_account.local?)
 
-    if direct?
+    if requires_mention?
       owned? || mention_exists?
     elsif private?
       owned? || following_author? || mention_exists?
@@ -24,7 +24,7 @@ class StatusPolicy < ApplicationPolicy
   end
 
   def reblog?
-    !direct? && (!private? || owned?) && show? && !blocking_author?
+    !requires_mention? && (!private? || owned?) && show? && !blocking_author?
   end
 
   def favourite?
@@ -43,8 +43,8 @@ class StatusPolicy < ApplicationPolicy
 
   private
 
-  def direct?
-    record.direct_visibility?
+  def requires_mention?
+    record.direct_visibility? || record.limited_visibility?
   end
 
   def owned?
diff --git a/app/serializers/activitypub/note_serializer.rb b/app/serializers/activitypub/note_serializer.rb
index 82b7ffe95..c9d23e25f 100644
--- a/app/serializers/activitypub/note_serializer.rb
+++ b/app/serializers/activitypub/note_serializer.rb
@@ -68,7 +68,7 @@ class ActivityPub::NoteSerializer < ActiveModel::Serializer
   end
 
   def virtual_tags
-    object.mentions.to_a.sort_by(&:id) + object.tags + object.emojis
+    object.active_mentions.to_a.sort_by(&:id) + object.tags + object.emojis
   end
 
   def atom_uri
diff --git a/app/serializers/initial_state_serializer.rb b/app/serializers/initial_state_serializer.rb
index ac08a3f1e..5b88cb9a8 100644
--- a/app/serializers/initial_state_serializer.rb
+++ b/app/serializers/initial_state_serializer.rb
@@ -21,6 +21,7 @@ class InitialStateSerializer < ActiveModel::Serializer
       search_enabled: Chewy.enabled?,
       version: Mastodon::Version.to_s,
       invites_enabled: Setting.min_invite_role == 'user',
+      mascot: instance_presenter.mascot&.file&.url,
     }
 
     if object.current_account
@@ -63,4 +64,10 @@ class InitialStateSerializer < ActiveModel::Serializer
   def media_attachments
     { accept_content_types: MediaAttachment::IMAGE_FILE_EXTENSIONS + MediaAttachment::VIDEO_FILE_EXTENSIONS + MediaAttachment::AUDIO_FILE_EXTENSIONS + MediaAttachment::IMAGE_MIME_TYPES + MediaAttachment::VIDEO_MIME_TYPES + MediaAttachment::AUDIO_MIME_TYPES }
   end
+
+  private
+
+  def instance_presenter
+    @instance_presenter ||= InstancePresenter.new
+  end
 end
diff --git a/app/serializers/rest/conversation_serializer.rb b/app/serializers/rest/conversation_serializer.rb
index 08cea47d2..b09ca6341 100644
--- a/app/serializers/rest/conversation_serializer.rb
+++ b/app/serializers/rest/conversation_serializer.rb
@@ -1,7 +1,12 @@
 # frozen_string_literal: true
 
 class REST::ConversationSerializer < ActiveModel::Serializer
-  attribute :id
+  attributes :id, :unread
+
   has_many :participant_accounts, key: :accounts, serializer: REST::AccountSerializer
   has_one :last_status, serializer: REST::StatusSerializer
+
+  def id
+    object.id.to_s
+  end
 end
diff --git a/app/serializers/rest/status_serializer.rb b/app/serializers/rest/status_serializer.rb
index 89776b1fc..07839c5ae 100644
--- a/app/serializers/rest/status_serializer.rb
+++ b/app/serializers/rest/status_serializer.rb
@@ -37,6 +37,17 @@ class REST::StatusSerializer < ActiveModel::Serializer
     !current_user.nil?
   end
 
+  def visibility
+    # This visibility is masked behind "private"
+    # to avoid API changes because there are no
+    # UX differences
+    if object.limited_visibility?
+      'private'
+    else
+      object.visibility
+    end
+  end
+
   def uri
     OStatus::TagManager.instance.uri_for(object)
   end
@@ -97,7 +108,7 @@ class REST::StatusSerializer < ActiveModel::Serializer
   end
 
   def ordered_mentions
-    object.mentions.to_a.sort_by(&:id)
+    object.active_mentions.to_a.sort_by(&:id)
   end
 
   class ApplicationSerializer < ActiveModel::Serializer
diff --git a/app/services/batched_remove_status_service.rb b/app/services/batched_remove_status_service.rb
index ebb4034aa..b7296cf7c 100644
--- a/app/services/batched_remove_status_service.rb
+++ b/app/services/batched_remove_status_service.rb
@@ -12,7 +12,7 @@ class BatchedRemoveStatusService < BaseService
   def call(statuses)
     statuses = Status.where(id: statuses.map(&:id)).includes(:account, :stream_entry).flat_map { |status| [status] + status.reblogs.includes(:account, :stream_entry).to_a }
 
-    @mentions = statuses.map { |s| [s.id, s.mentions.includes(:account).to_a] }.to_h
+    @mentions = statuses.map { |s| [s.id, s.active_mentions.includes(:account).to_a] }.to_h
     @tags     = statuses.map { |s| [s.id, s.tags.pluck(:name)] }.to_h
 
     @stream_entry_batches  = []
diff --git a/app/services/fan_out_on_write_service.rb b/app/services/fan_out_on_write_service.rb
index ab520276b..63cab8403 100644
--- a/app/services/fan_out_on_write_service.rb
+++ b/app/services/fan_out_on_write_service.rb
@@ -14,6 +14,8 @@ class FanOutOnWriteService < BaseService
       deliver_to_mentioned_followers(status)
       deliver_to_direct_timelines(status)
       deliver_to_own_conversation(status)
+    elsif status.limited_visibility?
+      deliver_to_mentioned_followers(status)
     else
       deliver_to_followers(status)
       deliver_to_lists(status)
@@ -57,7 +59,7 @@ class FanOutOnWriteService < BaseService
   end
 
   def deliver_to_mentioned_followers(status)
-    Rails.logger.debug "Delivering status #{status.id} to mentioned followers"
+    Rails.logger.debug "Delivering status #{status.id} to limited followers"
 
     status.mentions.includes(:account).each do |mention|
       mentioned_account = mention.account
diff --git a/app/services/notify_service.rb b/app/services/notify_service.rb
index 63bf8f17a..49022a844 100644
--- a/app/services/notify_service.rb
+++ b/app/services/notify_service.rb
@@ -59,9 +59,14 @@ class NotifyService < BaseService
     @notification.target_status.in_reply_to_account_id == @recipient.id && @notification.target_status.thread&.direct_visibility?
   end
 
+  def from_staff?
+    @notification.from_account.local? && @notification.from_account.user.present? && @notification.from_account.user.staff?
+  end
+
   def optional_non_following_and_direct?
     direct_message? &&
       @recipient.user.settings.interactions['must_be_following_dm'] &&
+      !from_staff? &&
       !following_sender? &&
       !response_to_recipient?
   end
diff --git a/app/services/remove_status_service.rb b/app/services/remove_status_service.rb
index 1a53093b8..4bee86c8a 100644
--- a/app/services/remove_status_service.rb
+++ b/app/services/remove_status_service.rb
@@ -8,7 +8,7 @@ class RemoveStatusService < BaseService
     @status       = status
     @account      = status.account
     @tags         = status.tags.pluck(:name).to_a
-    @mentions     = status.mentions.includes(:account).to_a
+    @mentions     = status.active_mentions.includes(:account).to_a
     @reblogs      = status.reblogs.to_a
     @stream_entry = status.stream_entry
     @options      = options
diff --git a/app/views/admin/accounts/show.html.haml b/app/views/admin/accounts/show.html.haml
index f2c53e3fe..17f1f224d 100644
--- a/app/views/admin/accounts/show.html.haml
+++ b/app/views/admin/accounts/show.html.haml
@@ -106,7 +106,7 @@
       - if @account.user&.otp_required_for_login?
         = link_to t('admin.accounts.disable_two_factor_authentication'), admin_user_two_factor_authentication_path(@account.user.id), method: :delete, class: 'button' if can?(:disable_2fa, @account.user)
       - unless @account.memorial?
-        = link_to t('admin.accounts.memorialize'), memorialize_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button' if can?(:memorialize, @account)
+        = link_to t('admin.accounts.memorialize'), memorialize_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button button--destructive' if can?(:memorialize, @account)
     - else
       = link_to t('admin.accounts.redownload'), redownload_admin_account_path(@account.id), method: :post, class: 'button' if can?(:redownload, @account)
 
@@ -114,7 +114,7 @@
     - if @account.silenced?
       = link_to t('admin.accounts.undo_silenced'), admin_account_silence_path(@account.id), method: :delete, class: 'button' if can?(:unsilence, @account)
     - else
-      = link_to t('admin.accounts.silence'), admin_account_silence_path(@account.id), method: :post, class: 'button' if can?(:silence, @account)
+      = link_to t('admin.accounts.silence'), admin_account_silence_path(@account.id), method: :post, class: 'button button--destructive' if can?(:silence, @account)
 
     - if @account.local?
       - unless @account.user_confirmed?
@@ -123,7 +123,7 @@
     - if @account.suspended?
       = link_to t('admin.accounts.undo_suspension'), admin_account_suspension_path(@account.id), method: :delete, class: 'button' if can?(:unsuspend, @account)
     - else
-      = link_to t('admin.accounts.perform_full_suspension'), new_admin_account_suspension_path(@account.id), class: 'button' if can?(:suspend, @account)
+      = link_to t('admin.accounts.perform_full_suspension'), new_admin_account_suspension_path(@account.id), class: 'button button--destructive' if can?(:suspend, @account)
 
 - if !@account.local? && @account.hub_url.present?
   %hr.spacer/
diff --git a/app/views/admin/domain_blocks/_domain_block.html.haml b/app/views/admin/domain_blocks/_domain_block.html.haml
index 17a3de81c..7bfea3574 100644
--- a/app/views/admin/domain_blocks/_domain_block.html.haml
+++ b/app/views/admin/domain_blocks/_domain_block.html.haml
@@ -1,10 +1,13 @@
 %tr
-  %td.domain
+  %td
     %samp= domain_block.domain
   %td.severity
     = t("admin.domain_blocks.severities.#{domain_block.severity}")
   %td.reject_media
     - if domain_block.reject_media? || domain_block.suspend?
       %i.fa.fa-check
+  %td.reject_reports
+    - if domain_block.reject_reports? || domain_block.suspend?
+      %i.fa.fa-check
   %td
     = table_link_to 'undo', t('admin.domain_blocks.undo'), admin_domain_block_path(domain_block)
diff --git a/app/views/admin/domain_blocks/index.html.haml b/app/views/admin/domain_blocks/index.html.haml
index 42b8ca53f..4c5221c42 100644
--- a/app/views/admin/domain_blocks/index.html.haml
+++ b/app/views/admin/domain_blocks/index.html.haml
@@ -8,6 +8,7 @@
         %th= t('admin.domain_blocks.domain')
         %th= t('admin.domain_blocks.severity')
         %th= t('admin.domain_blocks.reject_media')
+        %th= t('admin.domain_blocks.reject_reports')
         %th
     %tbody
       = render @domain_blocks
diff --git a/app/views/admin/domain_blocks/new.html.haml b/app/views/admin/domain_blocks/new.html.haml
index 6e514f833..3a4963489 100644
--- a/app/views/admin/domain_blocks/new.html.haml
+++ b/app/views/admin/domain_blocks/new.html.haml
@@ -14,5 +14,8 @@
   .fields-group
     = f.input :reject_media, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_media'), hint: I18n.t('admin.domain_blocks.reject_media_hint')
 
+  .fields-group
+    = f.input :reject_reports, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_reports'), hint: I18n.t('admin.domain_blocks.reject_reports_hint')
+
   .actions
     = f.button :button, t('.create'), type: :submit
diff --git a/app/views/admin/email_domain_blocks/_email_domain_block.html.haml b/app/views/admin/email_domain_blocks/_email_domain_block.html.haml
index 61cff9395..bf66c9001 100644
--- a/app/views/admin/email_domain_blocks/_email_domain_block.html.haml
+++ b/app/views/admin/email_domain_blocks/_email_domain_block.html.haml
@@ -1,5 +1,5 @@
 %tr
-  %td.domain
+  %td
     %samp= email_domain_block.domain
   %td
     = table_link_to 'trash', t('admin.email_domain_blocks.delete'), admin_email_domain_block_path(email_domain_block), method: :delete
diff --git a/app/views/admin/instances/_instance.html.haml b/app/views/admin/instances/_instance.html.haml
index 6efbbbe60..e36ebae47 100644
--- a/app/views/admin/instances/_instance.html.haml
+++ b/app/views/admin/instances/_instance.html.haml
@@ -1,5 +1,5 @@
 %tr
-  %td.domain
+  %td
     = link_to instance.domain, admin_accounts_path(by_domain: instance.domain)
   %td.count
     = instance.accounts_count
diff --git a/app/views/admin/reports/show.html.haml b/app/views/admin/reports/show.html.haml
index ae0bf81f8..133ca4eca 100644
--- a/app/views/admin/reports/show.html.haml
+++ b/app/views/admin/reports/show.html.haml
@@ -4,8 +4,10 @@
 %div{ style: 'overflow: hidden; margin-bottom: 20px' }
   - if @report.unresolved?
     %div{ style: 'float: right' }
-      = link_to t('admin.reports.silence_account'), admin_report_path(@report, outcome: 'silence'), method: :put, class: 'button'
-      = link_to t('admin.reports.suspend_account'), new_admin_account_suspension_path(@report.target_account_id, report_id: @report.id), class: 'button'
+      - if @report.target_account.local?
+        = link_to t('admin.accounts.disable'), admin_report_path(@report, outcome: 'disable'), method: :put, class: 'button button--destructive'
+      = link_to t('admin.accounts.silence'), admin_report_path(@report, outcome: 'silence'), method: :put, class: 'button button--destructive'
+      = link_to t('admin.accounts.perform_full_suspension'), new_admin_account_suspension_path(@report.target_account_id, report_id: @report.id), class: 'button button--destructive'
     %div{ style: 'float: left' }
       = link_to t('admin.reports.mark_as_resolved'), admin_report_path(@report, outcome: 'resolve'), method: :put, class: 'button'
   - else
diff --git a/app/views/admin/settings/edit.html.haml b/app/views/admin/settings/edit.html.haml
index b82555534..7c378bf73 100644
--- a/app/views/admin/settings/edit.html.haml
+++ b/app/views/admin/settings/edit.html.haml
@@ -26,6 +26,8 @@
       = f.input :thumbnail, as: :file, wrapper: :with_block_label, label: t('admin.settings.thumbnail.title'), hint: t('admin.settings.thumbnail.desc_html')
     .fields-row__column.fields-row__column-6.fields-group
       = f.input :hero, as: :file, wrapper: :with_block_label, label: t('admin.settings.hero.title'), hint: t('admin.settings.hero.desc_html')
+
+  .fields-row
     .fields-row__column.fields-row__column-6.fields-group
       = f.input :mascot, as: :file, wrapper: :with_block_label, label: t('admin.settings.mascot.title'), hint: t('admin.settings.mascot.desc_html')
 
diff --git a/app/views/layouts/embedded.html.haml b/app/views/layouts/embedded.html.haml
index 2443e3410..33e3714f8 100644
--- a/app/views/layouts/embedded.html.haml
+++ b/app/views/layouts/embedded.html.haml
@@ -4,6 +4,12 @@
     %meta{ charset: 'utf-8' }/
     %meta{ name: 'robots', content: 'noindex' }/
 
+    - if cdn_host?
+      %link{ rel: 'dns-prefetch', href: cdn_host }/
+
+    - if storage_host?
+      %link{ rel: 'dns-prefetch', href: storage_host }/
+
     = javascript_pack_tag "locales", integrity: true, crossorigin: 'anonymous'
     - if @theme
       - if @theme[:supported_locales].include? I18n.locale.to_s
@@ -12,4 +18,6 @@
         = javascript_pack_tag "locales/#{@theme[:flavour]}/en", integrity: true, crossorigin: 'anonymous'
     = render partial: 'layouts/theme', object: @core
     = render partial: 'layouts/theme', object: @theme
+
+  %body.embed
     = yield
diff --git a/app/views/settings/preferences/show.html.haml b/app/views/settings/preferences/show.html.haml
index 751a6e50b..45f9fd178 100644
--- a/app/views/settings/preferences/show.html.haml
+++ b/app/views/settings/preferences/show.html.haml
@@ -22,7 +22,7 @@
   %hr#settings_publishing/
 
   .fields-group
-    = f.input :setting_default_privacy, collection: Status.visibilities.keys - ['direct'], wrapper: :with_floating_label, include_blank: false, label_method: lambda { |visibility| safe_join([I18n.t("statuses.visibilities.#{visibility}"), content_tag(:span, I18n.t("statuses.visibilities.#{visibility}_long"), class: 'hint')]) }, required: false, as: :radio_buttons, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li'
+    = f.input :setting_default_privacy, collection: Status.selectable_visibilities, wrapper: :with_floating_label, include_blank: false, label_method: lambda { |visibility| safe_join([I18n.t("statuses.visibilities.#{visibility}"), content_tag(:span, I18n.t("statuses.visibilities.#{visibility}_long"), class: 'hint')]) }, required: false, as: :radio_buttons, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li'
 
     = f.input :setting_default_sensitive, 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 6cedfb337..6e6d0eda8 100644
--- a/app/views/stream_entries/_detailed_status.html.haml
+++ b/app/views/stream_entries/_detailed_status.html.haml
@@ -1,16 +1,17 @@
 .detailed-status.detailed-status--flex
-  = link_to TagManager.instance.url_for(status.account), class: 'detailed-status__display-name p-author h-card', target: stream_link_target, rel: 'noopener' do
-    .detailed-status__display-avatar
-      - if current_account&.user&.setting_auto_play_gif || autoplay
-        = image_tag status.account.avatar_original_url, width: 48, height: 48, alt: '', class: 'account__avatar u-photo'
-      - else
-        = image_tag status.account.avatar_static_url, width: 48, height: 48, alt: '', class: 'account__avatar u-photo'
-    %span.display-name
-      %bdi
-        %strong.display-name__html.p-name.emojify= display_name(status.account, custom_emojify: true, autoplay: autoplay)
-      %span.display-name__account
-        = acct(status.account)
-        = fa_icon('lock') if status.account.locked?
+  .p-author.h-card
+    = link_to TagManager.instance.url_for(status.account), class: 'detailed-status__display-name u-url', target: stream_link_target, rel: 'noopener' do
+      .detailed-status__display-avatar
+        - if current_account&.user&.setting_auto_play_gif || autoplay
+          = image_tag status.account.avatar_original_url, width: 48, height: 48, alt: '', class: 'account__avatar u-photo'
+        - else
+          = image_tag status.account.avatar_static_url, width: 48, height: 48, alt: '', class: 'account__avatar u-photo'
+      %span.display-name
+        %bdi
+          %strong.display-name__html.p-name.emojify= display_name(status.account, custom_emojify: true, autoplay: autoplay)
+        %span.display-name__account
+          = acct(status.account)
+          = fa_icon('lock') if status.account.locked?
 
   = account_action_button(status.account)
 
@@ -50,7 +51,7 @@
     - if status.direct_visibility?
       %span.detailed-status__link<
         = fa_icon('envelope')
-    - elsif status.private_visibility?
+    - elsif status.private_visibility? || status.limited_visibility?
       %span.detailed-status__link<
         = fa_icon('lock')
     - else
diff --git a/app/views/stream_entries/_simple_status.html.haml b/app/views/stream_entries/_simple_status.html.haml
index 5d7e2ad82..cd0531ba2 100644
--- a/app/views/stream_entries/_simple_status.html.haml
+++ b/app/views/stream_entries/_simple_status.html.haml
@@ -4,19 +4,20 @@
       %time.time-ago{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at)
     %data.dt-published{ value: status.created_at.to_time.iso8601 }
 
-    = link_to TagManager.instance.url_for(status.account), class: 'status__display-name p-author h-card', target: stream_link_target, rel: 'noopener' do
-      .status__avatar
-        %div
-          - if current_account&.user&.setting_auto_play_gif || autoplay
-            = image_tag status.account.avatar_original_url, width: 48, height: 48, alt: '', class: 'u-photo account__avatar'
-          - else
-            = image_tag status.account.avatar_static_url, width: 48, height: 48, alt: '', class: 'u-photo account__avatar'
-      %span.display-name
-        %bdi
-          %strong.display-name__html.p-name.emojify= display_name(status.account, custom_emojify: true, autoplay: autoplay)
-        %span.display-name__account
-          = acct(status.account)
-          = fa_icon('lock') if status.account.locked?
+    .p-author.h-card
+      = link_to TagManager.instance.url_for(status.account), class: 'status__display-name u-url', target: stream_link_target, rel: 'noopener' do
+        .status__avatar
+          %div
+            - if current_account&.user&.setting_auto_play_gif || autoplay
+              = image_tag status.account.avatar_original_url, width: 48, height: 48, alt: '', class: 'u-photo account__avatar'
+            - else
+              = image_tag status.account.avatar_static_url, width: 48, height: 48, alt: '', class: 'u-photo account__avatar'
+        %span.display-name
+          %bdi
+            %strong.display-name__html.p-name.emojify= display_name(status.account, custom_emojify: true, autoplay: autoplay)
+          %span.display-name__account
+            = acct(status.account)
+            = fa_icon('lock') if status.account.locked?
   .status__content.emojify<
     - if status.spoiler_text?
       %p{ :style => ('margin-bottom: 0' unless current_account&.user&.setting_expand_spoilers) }<
diff --git a/app/views/stream_entries/show.html.haml b/app/views/stream_entries/show.html.haml
index 2edc155bf..0e81c4f68 100644
--- a/app/views/stream_entries/show.html.haml
+++ b/app/views/stream_entries/show.html.haml
@@ -12,7 +12,7 @@
   = opengraph 'og:site_name', site_title
   = opengraph 'og:type', 'article'
   = opengraph 'og:title', "#{display_name(@account)} (@#{@account.local_username_and_domain})"
-  = opengraph 'og:url', short_account_status_url(@account, @stream_entry)
+  = opengraph 'og:url', short_account_status_url(@account, @stream_entry.activity)
 
   = render 'stream_entries/og_description', activity: @stream_entry.activity
   = render 'stream_entries/og_image', activity: @stream_entry.activity, account: @account
diff --git a/app/workers/activitypub/distribution_worker.rb b/app/workers/activitypub/distribution_worker.rb
index c2bfd4f2f..17c1ef7ff 100644
--- a/app/workers/activitypub/distribution_worker.rb
+++ b/app/workers/activitypub/distribution_worker.rb
@@ -23,7 +23,7 @@ class ActivityPub::DistributionWorker
   private
 
   def skip_distribution?
-    @status.direct_visibility?
+    @status.direct_visibility? || @status.limited_visibility?
   end
 
   def relayable?
diff --git a/app/workers/activitypub/reply_distribution_worker.rb b/app/workers/activitypub/reply_distribution_worker.rb
index fe99fc05f..c0ed3a1f4 100644
--- a/app/workers/activitypub/reply_distribution_worker.rb
+++ b/app/workers/activitypub/reply_distribution_worker.rb
@@ -9,7 +9,7 @@ class ActivityPub::ReplyDistributionWorker
     @status  = Status.find(status_id)
     @account = @status.thread&.account
 
-    return if @account.nil? || skip_distribution?
+    return unless @account.present? && @status.distributable?
 
     ActivityPub::DeliveryWorker.push_bulk(inboxes) do |inbox_url|
       [signed_payload, @status.account_id, inbox_url]
@@ -20,10 +20,6 @@ class ActivityPub::ReplyDistributionWorker
 
   private
 
-  def skip_distribution?
-    @status.private_visibility? || @status.direct_visibility?
-  end
-
   def inboxes
     @inboxes ||= @account.followers.inboxes
   end
diff --git a/config/environments/production.rb b/config/environments/production.rb
index bff423f7f..7a07a8eb0 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -13,7 +13,7 @@ Rails.application.configure do
   # Full error reports are disabled and caching is turned on.
   config.consider_all_requests_local       = false
   config.action_controller.perform_caching = true
-  config.action_controller.asset_host      = ENV['CDN_HOST'] if ENV.key?('CDN_HOST')
+  config.action_controller.asset_host      = ENV['CDN_HOST'] if ENV['CDN_HOST'].present?
 
   # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
   # or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb
index b3b9efb2a..76236aa21 100644
--- a/config/initializers/content_security_policy.rb
+++ b/config/initializers/content_security_policy.rb
@@ -31,7 +31,6 @@ if Rails.env.production?
   end
 end
 
-
 # Report CSP violations to a specified URI
 # For further information see the following documentation:
 # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb
index c77387ed4..2a963b32b 100644
--- a/config/initializers/doorkeeper.rb
+++ b/config/initializers/doorkeeper.rb
@@ -59,6 +59,7 @@ Doorkeeper.configure do
                   :'write:accounts',
                   :'write:blocks',
                   :'write:bookmarks',
+                  :'write:conversations',
                   :'write:favourites',
                   :'write:filters',
                   :'write:follows',
@@ -78,7 +79,6 @@ Doorkeeper.configure do
                   :'read:lists',
                   :'read:mutes',
                   :'read:notifications',
-                  :'read:reports',
                   :'read:search',
                   :'read:statuses',
                   :follow,
diff --git a/config/locales/ar.yml b/config/locales/ar.yml
index dd434c373..4499830f9 100644
--- a/config/locales/ar.yml
+++ b/config/locales/ar.yml
@@ -48,6 +48,7 @@ ar:
       other: مُتابِعون
     following: مُتابَع
     joined: انضم·ت في %{date}
+    link_verified_on: تم التحقق مِن مالك هذا الرابط بتاريخ %{date}
     media: الوسائط
     moved_html: "%{name} إنتقلَ إلى %{new_profile_link} :"
     network_hidden: إنّ المعطيات غير متوفرة
@@ -120,6 +121,7 @@ ar:
       moderation_notes: ملاحظات الإشراف
       most_recent_activity: آخر نشاط حديث
       most_recent_ip: أحدث عنوان إيبي
+      no_limits_imposed: مِن دون حدود مشروطة
       not_subscribed: غير مشترك
       order:
         alphabetic: أبجديًا
@@ -155,8 +157,10 @@ ar:
         report: التقرير
         targeted_reports: التقريرات التي أُنشِأت ضد هذا الحساب
       silence: سكتهم
+      silenced: تم كتمه
       statuses: المنشورات
       subscribe: اشترك
+      suspended: تم تعليقه
       title: الحسابات
       unconfirmed_email: البريد الإلكتروني غير المؤكد
       undo_silenced: رفع الصمت
@@ -300,7 +304,12 @@ ar:
       title: الدعوات
     relays:
       add_new: إضافة مُرحّل جديد
+      delete: حذف
+      disable: تعطيل
+      disabled: مُعطَّل
+      enable: تشغيل
       enable_hint: عندما تقوم بتنشيط هذه الميزة، سوف يشترك خادومك في جميع التبويقات القادمة مِن هذا المُرحِّل و سيشرع كذلك بإرسال كافة التبويقات العمومية إليه.
+      enabled: مُشغَّل
       inbox_url: رابط المُرحّل
       pending: في انتظار تسريح المُرحِّل
       save_and_enable: حفظ وتشغيل
@@ -337,9 +346,7 @@ ar:
       reported_by: أبلغ عنه من طرف
       resolved: معالجة
       resolved_msg: تم حل تقرير بنجاح!
-      silence_account: كتم و إخفاء الحساب
       status: الحالة
-      suspend_account: فرض تعليق على الحساب
       title: التقارير
       unassign: إلغاء تعيين
       unresolved: غير معالجة
@@ -452,7 +459,7 @@ ar:
     warning: كن حذرا مع هذه البيانات. لا تقم أبدا بمشاركتها مع الآخَرين !
     your_token: رمز نفاذك
   auth:
-    agreement_html: بقبولك التسجيل فإنك تُصرِّح قبول <a href="%{rules_path}">قواعد مثيل الخادوم</a> و <a href="%{terms_path}">شروط الخدمة التي نوفرها لك</a>.
+    agreement_html: بمجرد النقر على "التسجيل" أسفله، فإنك تُصرِّح قبول <a href="%{rules_path}">قواعد مثيل الخادوم</a> و <a href="%{terms_path}">شروط الخدمة التي نوفرها لك</a>.
     change_password: الكلمة السرية
     confirm_email: تأكيد عنوان البريد الإلكتروني
     delete_account: حذف حساب
diff --git a/config/locales/ca.yml b/config/locales/ca.yml
index 4332920f5..42f657fd5 100644
--- a/config/locales/ca.yml
+++ b/config/locales/ca.yml
@@ -336,9 +336,7 @@ ca:
       reported_by: Reportat per
       resolved: Resolt
       resolved_msg: Informe resolt amb èxit!
-      silence_account: Silencia el compte
       status: Estat
-      suspend_account: Suspèn el compte
       title: Informes
       unassign: Treure assignació
       unresolved: No resolt
diff --git a/config/locales/co.yml b/config/locales/co.yml
index 0172fba8d..7b810e2ed 100644
--- a/config/locales/co.yml
+++ b/config/locales/co.yml
@@ -48,6 +48,7 @@ co:
       other: Abbunati
     following: Abbunamenti
     joined: Quì dapoi %{date}
+    link_verified_on: A pruprietà d'issu ligame hè stata verificata u %{date}
     media: Media
     moved_html: "%{name} hà cambiatu di contu, avà hè nant’à %{new_profile_link}:"
     network_hidden: St'infurmazione ùn hè micca dispunibule
@@ -120,6 +121,7 @@ co:
       moderation_notes: Note di muderazione
       most_recent_activity: Attività più ricente
       most_recent_ip: IP più ricente
+      no_limits_imposed: Nisuna limita imposta
       not_subscribed: Micca abbunatu
       order:
         alphabetic: Alfabeticu
@@ -155,8 +157,10 @@ co:
         report: Signalamentu
         targeted_reports: Signalamenti creati contr’à stu contu
       silence: Silenzà
+      silenced: Silenzatu
       statuses: Statuti
       subscribe: Abbunassi
+      suspended: Suspesu
       title: Conti
       unconfirmed_email: E-mail micca cunfirmatu
       undo_silenced: Ùn silenzà più
@@ -300,8 +304,13 @@ co:
       title: Invitazione
     relays:
       add_new: Aghjustà un ripetitore
+      delete: Sguassà
       description_html: Un <strong>ripetitore di federazione</strong> ghjè un servore intermediariu chì manda statuti pubblichi trà l'istanze abbunate. <strong>Pò aiutà l'istanze chjuche è mezane à scuprì u cuntinutu di u fediverse</strong> senza chì l'utilizatori appianu bisognu di seguità tutti i conti di l'altri servori.
+      disable: Disattivà
+      disabled: Disattivatu
+      enable: Attivà
       enable_hint: Quandu sarà attivatu, u vostru servore hà da seguità i statuti pubblichi di u ripetitore, è mandarà i so statuti pubblichi quallà.
+      enabled: Attivatu
       inbox_url: URL di u ripetitore
       pending: In attesa di l'apprubazione di u ripetitore
       save_and_enable: Salvà è attivà
@@ -336,9 +345,7 @@ co:
       reported_by: Palisatu da
       resolved: Scioltu è chjosu
       resolved_msg: Signalamentu scioltu!
-      silence_account: Silenzà u contu
       status: Statutu
-      suspend_account: Suspende u contu
       title: Signalamenti
       unassign: Disassignà
       unresolved: Micca sciolti
@@ -452,7 +459,7 @@ co:
     warning: Abbadate à quessi dati. Ùn i date à nisunu!
     your_token: Rigenerà a fiscia d’accessu
   auth:
-    agreement_html: Arregistrassi vole dì chì site d’accunsentu per siguità <a href="%{rules_path}">e regule di l’istanza</a> è <a href="%{terms_path}">e cundizione d’usu</a>.
+    agreement_html: Cliccà "Arregistrassi" quì sottu vole dì chì site d’accunsentu per siguità <a href="%{rules_path}">e regule di l’istanza</a> è <a href="%{terms_path}">e cundizione d’usu</a>.
     change_password: Chjave d’accessu
     confirm_email: Cunfirmà l’e-mail
     delete_account: Sguassà u contu
@@ -913,3 +920,6 @@ co:
     otp_lost_help_html: S’è voi avete persu i dui, pudete cuntattà %{email}
     seamless_external_login: Site cunnettatu·a dapoi un serviziu esternu, allora i parametri di chjave d’accessu è d’indirizzu e-mail ùn so micca dispunibili.
     signed_in_as: 'Cunnettatu·a cum’è:'
+  verification:
+    explanation_html: 'Pudete <strong>verificavi cum''è u pruprietariu di i ligami in i metadati di u vostru prufile</strong>. Per quessa, u vostru situ deve avè un ligame versu a vostra pagina Mastodon. U ligame <strong>deve</strong> avè un''attributu <code>rel="me"</code>. U cuntenutu di u testu di u ligame ùn hè micca impurtante. Eccu un''esempiu:'
+    verification: Verificazione
diff --git a/config/locales/cs.yml b/config/locales/cs.yml
index 5408c2472..67bda70f1 100644
--- a/config/locales/cs.yml
+++ b/config/locales/cs.yml
@@ -1,13 +1,13 @@
 ---
 cs:
   about:
-    about_hashtag_html: Toto jsou veřejné tooty označené hashtagem <strong>#%{hashtag}</strong>. Pokud máte účet kdekoliv na fediverse, můžete s nimi interagovat.
+    about_hashtag_html: Tohle jsou veřejné tooty označené hashtagem <strong>#%{hashtag}</strong>. Pokud máte účet kdekoliv na fediverse, můžete s nimi interagovat.
     about_mastodon_html: Mastodon je sociální síť založená na otevřených webových protokolech a svobodném, otevřeném softwaru. Je decentrovalizovaná jako e-mail.
     about_this: O této instanci
-    administered_by: 'Server spravuje:'
+    administered_by: 'Instanci spravuje:'
     api: API
     apps: Mobilní aplikace
-    closed_registrations: Registrace na této instanci jsou momentálně uzavřené. Můžete si však najít jinou instanci, vytvořit si na ní účet a získat z ní přístup do naprosto stejné sítě.
+    closed_registrations: Registrace na této instanci jsou momentálně uzavřené. Ale pozor! Můžete si najít jinou instanci, vytvořit si na ní účet a získat z ní přístup do naprosto stejné sítě.
     contact: Kontakt
     contact_missing: Nenastaveno
     contact_unavailable: Neuvedeno
@@ -46,8 +46,9 @@ cs:
     followers:
       one: Sledovatel
       other: Sledovatelé
-    following: Sleduje
+    following: Sledovaní
     joined: Připojil/a se v %{date}
+    link_verified_on: Vlastnictví tohoto odkazu bylo zkontrolováno %{date}
     media: Média
     moved_html: 'Účet %{name} byl přesunut na %{new_profile_link}:'
     network_hidden: Tato informace není k dispozici
@@ -114,12 +115,13 @@ cs:
       memorialize: Změnit na "in memoriam"
       moderation:
         all: Vše
-        silenced: Utišen
-        suspended: Suspendován
+        silenced: Utišen/a
+        suspended: Suspendován/a
         title: Moderace
       moderation_notes: Moderační poznámky
       most_recent_activity: Nejnovější aktivita
       most_recent_ip: Nejnovější IP
+      no_limits_imposed: Nejsou nastavena žádná omezení
       not_subscribed: Neodebírá
       order:
         alphabetic: Abecedně
@@ -155,8 +157,10 @@ cs:
         report: nahlášení
         targeted_reports: Nahlášení vytvořena o tomto účtu
       silence: Utišit
+      silenced: Utišen/a
       statuses: Příspěvky
       subscribe: Odebírat
+      suspended: Suspendován/a
       title: Účty
       unconfirmed_email: Nepotvrzený e-mail
       undo_silenced: Zrušit utišení
@@ -300,8 +304,13 @@ cs:
       title: Pozvánky
     relays:
       add_new: Přidat nový most
+      delete: Smazat
       description_html: "<strong>Federovací most</strong> je přechodný server, který vyměňuje velká množství veřejných tootů mezi servery, které z něj odebírají a poblikují na něj. <strong>Může pomoci malým a středně velkým serverům objevovat obsah z fediverse</strong>, což by jinak vyžadovalo, aby místní uživatelé manuálně sledovali jiné lidi na vzdálených serverech."
+      disable: Zakázat
+      disabled: Zakázáno
+      enable: Povolit
       enable_hint: Je-li tohle povoleno, začne váš server odebírat všechny veřejné tooty z tohoto mostu a odesílat na něj své vlastní veřejné tooty.
+      enabled: Povoleno
       inbox_url: URL mostu
       pending: Čekám na souhlas mostu
       save_and_enable: Uložit a povolit
@@ -336,9 +345,7 @@ cs:
       reported_by: Nahlášeno uživatelem
       resolved: Vyřešeno
       resolved_msg: Nahlášení úspěšně vyřešeno!
-      silence_account: Utišit účet
       status: Stav
-      suspend_account: Suspendovat účet
       title: Nahlášení
       unassign: Odebrat
       unresolved: Nevyřešeno
@@ -452,7 +459,7 @@ cs:
     warning: Buďte s těmito daty velmi opatrní. Nikdy je s nikým nesdílejte!
     your_token: Váš přístupový token
   auth:
-    agreement_html: Registrací souhlasíte s následováním <a href="%{rules_path}">pravidel této instance</a> a <a href="%{terms_path}">našich podmínek používání</a>.
+    agreement_html: Kliknutím na tlačítko „Registrovat“ souhlasíte s následováním <a href="%{rules_path}">pravidel této instance</a> a <a href="%{terms_path}">našich podmínek používání</a>.
     change_password: Heslo
     confirm_email: Potvrdit e-mail
     delete_account: Odstranit účet
@@ -759,7 +766,7 @@ cs:
     over_character_limit: limit %{max} znaků byl překročen
     pin_errors:
       limit: Už jste si připnul/a maximální počet tootů
-      ownership: Nelže připnout toot někoho jiného
+      ownership: Nelze připnout toot někoho jiného
       private: Nelze připnout neveřejné tooty
       reblog: Nelze připnout boostnutí
     show_more: Zobrazit více
@@ -912,3 +919,6 @@ cs:
     otp_lost_help_html: Pokud jste ztratil/a přístup k oběma, můžete se spojit %{email}
     seamless_external_login: Jste přihlášen/a přes externí službu, nastavení hesla a e-mailu proto nejsou dostupná.
     signed_in_as: 'Přihlášen/a jako:'
+  verification:
+    explanation_html: 'Můžete se <strong>ověřit jako vlastník odkazů v metadatech profilu</strong>. Pro tento účel musí stránka v odkazu obsahovat odkaz zpět na váš profil na Mastodonu. Odkaz zpět <strong>musí</strong> mít atribut <code>rel="me"</code>. Na textu odkazu nezáleží. Zde je příklad:'
+    verification: Ověření
diff --git a/config/locales/cy.yml b/config/locales/cy.yml
index 8b923ec87..8b16949a5 100644
--- a/config/locales/cy.yml
+++ b/config/locales/cy.yml
@@ -7,7 +7,7 @@ cy:
     administered_by: 'Gweinyddir gan:'
     api: API
     apps: Apiau symudol
-    closed_registrations: Mae Mastodon yn rwydwaith cymdeithasol sy'n seiliedig ar brotocolau gwe a meddalwedd cod agored rhad ac am ddim. Mae'n ddatganoledig fel e-bost.
+    closed_registrations: ''
     contact: Cyswllt
     contact_missing: Heb ei osod
     contact_unavailable: Ddim yn berthnasol
@@ -155,7 +155,7 @@ cy:
         report: adrodd
         targeted_reports: Adroddiadau am y cyfri hwn
       silence: Tawelu
-      statuses: ''
+      statuses: Statysau
       subscribe: Tanysgrifio
       title: Cyfrifon
       unconfirmed_email: E-bost heb ei gadarnhau
@@ -192,7 +192,7 @@ cy:
         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}
+        update_status: Diweddarodd %{name} statws gan %{target}
       deleted_status: "(statws wedi ei ddileu)"
       title: Log archwilio
     custom_emojis:
@@ -287,7 +287,7 @@ cy:
       domain_name: Parth
       reset: Ailosod
       search: Chwilio
-      title: INSTANCES hysbys
+      title: Achosion hysbys
     invites:
       filter:
         all: Pob
@@ -311,6 +311,8 @@ cy:
         report: adroddiad
       action_taken_by: Gwnathpwyd hyn gan
       are_you_sure: Ydych chi'n sicr?
+      assign_to_self: Aseinio i mi
+      assigned: Cymedrolwr wedi'i aseinio
       comment:
         none: Dim
       created_at: Adroddwyd
@@ -327,7 +329,6 @@ cy:
       reported_by: Adroddwyd gan
       resolved: Wedi ei ddatrys
       resolved_msg: Llwyddwyd i ddatrys yr adroddiad!
-      silence_account: Tawelwch y cyfrif
       status: Statws
       title: Adroddiadau
       unassign: Dadneilltuo
@@ -336,10 +337,19 @@ cy:
     settings:
       activity_api_enabled:
         title: Cyhoeddwch ystatedgau agregau am weithgaredd defnyddwyr
+      bootstrap_timeline_accounts:
+        title: Dilyn diofyn i ddefnyddwyr newydd
       contact_information:
         email: E-bost busnes
+        username: Enw defnyddiwr cyswllt
+      custom_css:
+        desc_html: Addaswch wedd gyda CSS wedi lwytho ar bob tudalen
       hero:
+        desc_html: Yn cael ei arddangos ar y dudadlen flaen. Awgrymir 600x100px oleia. Pan nad yw wedi ei osod, mae'n ymddangos fel mân-lun yr achos
         title: Delwedd arwr
+      peers_api_enabled:
+        desc_html: Enwau parth y mae'r achos hwn wedi dod ar ei draws yn y ffedysawd
+        title: Cyhoeddi rhestr o achosion dargynfyddiedig
       registrations:
         deletion:
           desc_html: Caniatewch i unrhywun i ddileu eu cyfrif
@@ -351,6 +361,15 @@ cy:
           title: Agorwch cofrestru
       show_staff_badge:
         title: Dangos bathodyn staff
+      site_description:
+        title: Disgrifiad achos
+      site_description_extended:
+        desc_html: Lle da ar gyfer eich côd ymddygiad, rheolau, canllawiau a phethau eraill sy'n gwneud eich achos yn whanol. Mae modd i chi ddefnyddio tagiau HTML
+      site_short_description:
+        title: Disgrifiad byr o'r achos
+      site_title: Enw'r achos
+      thumbnail:
+        title: Mân-lun yr achos
       timeline_preview:
         title: Rhagolwg o'r ffrwd
       title: Gosodiadau'r wefan
@@ -493,6 +512,8 @@ cy:
       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:
+    preface: Mae modd mewnforio data yr ydych wedi allforio o achos arall, megis rhestr o bobl yr ydych yn ei ddilyn neu yn blocio.
+    success: Uwchlwyddwyd eich data yn llwyddiannus ac fe fydd yn cael ei brosesu mewn da bryd
     types:
       blocking: Rhestr blocio
       following: Rhestr dilyn
@@ -504,9 +525,11 @@ cy:
     expires_in:
       '86400': 1 dydd
     max_uses_prompt: Dim terfyn
+    prompt: Cynhyrchwch a rhannwch ddolenni gyda eraill i ganiatau mynediad i'r achos hwn
     table:
       uses: Defnyddiau
   migrations:
+    currently_redirecting: ''
     proceed: Cadw
   moderation:
     title: Cymedroli
diff --git a/config/locales/da.yml b/config/locales/da.yml
index 7cda5cbca..0cd3e78f7 100644
--- a/config/locales/da.yml
+++ b/config/locales/da.yml
@@ -336,9 +336,7 @@ da:
       reported_by: Anmeldt af
       resolved: Løst
       resolved_msg: Anmeldelse er sat til at være løst!
-      silence_account: Dæmp konto
       status: Status
-      suspend_account: Udeluk konto
       title: Anmeldelser
       unassign: Utildel
       unresolved: Uløst
diff --git a/config/locales/de.yml b/config/locales/de.yml
index efd350e98..67166f31c 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -36,8 +36,8 @@ de:
     status_count_before: mit
     terms: Nutzungsbedingungen
     user_count_after:
-      one: Benutzer
-      other: Benutzer
+      one: Benutzer:in
+      other: Benutzer:innen
     user_count_before: Zuhause für
     what_is_mastodon: Was ist Mastodon?
   accounts:
@@ -48,6 +48,7 @@ de:
       other: Follower
     following: Folgt
     joined: Beigetreten am %{date}
+    link_verified_on: Besitz des Links wurde überprüft am %{date}
     media: Medien
     moved_html: "%{name} ist auf %{new_profile_link} umgezogen:"
     network_hidden: Diese Informationen sind nicht verfügbar
@@ -135,7 +136,7 @@ de:
       redownload: Avatar neu laden
       remove_avatar: Profilbild entfernen
       resend_confirmation:
-        already_confirmed: Dieser Benutzer wurde bereits bestätigt
+        already_confirmed: Diese:r Benutzer:in wurde bereits bestätigt
         send: Bestätigungsmail erneut senden
         success: Bestätigungs-E-Mail erfolgreich gesendet!
       reset: Zurücksetzen
@@ -144,7 +145,7 @@ de:
       role: Berechtigungen
       roles:
         admin: Administrator
-        moderator: Moderator
+        moderator: Moderator:in
         staff: Mitarbeiter
         user: Nutzer
       salmon_url: Salmon-URL
@@ -155,8 +156,10 @@ de:
         report: Meldung
         targeted_reports: Meldungen über dieses Konto
       silence: Stummschalten
+      silenced: Stummgeschaltet
       statuses: Beiträge
       subscribe: Abonnieren
+      suspended: Gesperrt
       title: Konten
       unconfirmed_email: Unbestätigte E-Mail-Adresse
       undo_silenced: Stummschaltung zurücknehmen
@@ -172,20 +175,20 @@ de:
         create_custom_emoji: "%{name} hat neues Emoji %{target} hochgeladen"
         create_domain_block: "%{name} hat die Domain %{target} blockiert"
         create_email_domain_block: "%{name} hat die E-Mail-Domain %{target} geblacklistet"
-        demote_user: "%{name} stufte Benutzer %{target} herunter"
+        demote_user: "%{name} stufte Benutzer:in %{target} herunter"
         destroy_domain_block: "%{name} hat die Domain %{target} entblockt"
         destroy_email_domain_block: "%{name} hat die E-Mail-Domain %{target} gewhitelistet"
         destroy_status: "%{name} hat Status von %{target} entfernt"
-        disable_2fa_user: "%{name} hat Zwei-Faktor-Anforderung für Benutzer %{target} deaktiviert"
+        disable_2fa_user: "%{name} hat Zwei-Faktor-Anforderung für Benutzer:in %{target} deaktiviert"
         disable_custom_emoji: "%{name} hat das %{target} Emoji deaktiviert"
-        disable_user: "%{name} hat den Login für Benutzer  %{target} deaktiviert"
+        disable_user: "%{name} hat den Login für Benutzer:in  %{target} deaktiviert"
         enable_custom_emoji: "%{name} hat das %{target} Emoji aktiviert"
-        enable_user: "%{name} hat die Anmeldung für den Benutzer %{target} aktiviert"
+        enable_user: "%{name} hat die Anmeldung für di:en Benutzer:in %{target} aktiviert"
         memorialize_account: "%{name} hat %{target}s Profil in eine Gedenkseite umgewandelt"
         promote_user: "%{name} hat %{target} befördert"
         remove_avatar_user: "%{name} hat das Profilbild von %{target} entfernt"
         reopen_report: "%{name} hat die Meldung %{target} wieder geöffnet"
-        reset_password_user: "%{name} hat das Passwort für den Benutzer %{target} zurückgesetzt"
+        reset_password_user: "%{name} hat das Passwort für di:en Benutzer:in %{target} zurückgesetzt"
         resolve_report: "%{name} hat die Meldung %{target} bearbeitet"
         silence_account: "%{name} hat %{target}s Account stummgeschaltet"
         suspend_account: "%{name} hat %{target}s Account gesperrt"
@@ -237,11 +240,11 @@ de:
       software: Software
       space: Speicherverbrauch
       title: Übersicht
-      total_users: Benutzer Insgesamt
+      total_users: Benutzer:innen insgesamt
       trends: Trends
       week_interactions: Interaktionen diese Woche
       week_users_active: Aktiv diese Woche
-      week_users_new: Benutzer diese Woche
+      week_users_new: Benutzer:innen diese Woche
     domain_blocks:
       add_new: Neu hinzufügen
       created_msg: Die Domain-Blockade wird nun durchgeführt
@@ -300,8 +303,13 @@ de:
       title: Einladungen
     relays:
       add_new: Neues Relay hinzufügen
+      delete: Löschen
       description_html: Ein <strong>Föderierungsrelay</strong> ist ein vermittelnder Server, der eine große Anzahl öffentlicher Beiträge zwischen Servern austauscht, die es abonnieren und zu ihm veröffentlichen.<strong> Es kann kleinen und mittleren Servern dabei helfen, Inhalte des Fediverse zu entdecken</strong>, was andernfalls das manuelle Folgen anderer Leute auf entfernten Servern durch lokale Nutzer erfordern würde.
+      disable: Ausschalten
+      disabled: Ausgeschaltet
+      enable: Einschalten
       enable_hint: Sobald aktiviert wird dein Server alle öffentlichen Beiträge dieses Relays abonnieren und wird alle öffentlichen Beiträge dieses Servers an es senden.
+      enabled: Eingeschaltet
       inbox_url: Relay-URL
       pending: Warte auf Zustimmung des Relays
       save_and_enable: Speichern und aktivieren
@@ -336,9 +344,7 @@ de:
       reported_by: Gemeldet von
       resolved: Gelöst
       resolved_msg: Meldung erfolgreich gelöst!
-      silence_account: Konto stummschalten
       status: Status
-      suspend_account: Konto sperren
       title: Meldungen
       unassign: Zuweisung entfernen
       unresolved: Ungelöst
@@ -452,7 +458,7 @@ de:
     warning: Sei mit diesen Daten sehr vorsichtig. Teile sie mit niemandem!
     your_token: Dein Zugangs-Token
   auth:
-    agreement_html: Indem du dich registrierst, erklärst du dich mit den Regeln, die <a href="%{rules_path}">auf dieser Instanz gelten</a> und der <a href="%{terms_path}">Datenschutzerklärung</a> einverstanden.
+    agreement_html: Indem du dich registrierst, erklärst du dich mit den untenstehenden <a href="%{rules_path}">Regeln dieser Instanz</a> und der <a href="%{terms_path}">Datenschutzerklärung</a> einverstanden.
     change_password: Passwort
     confirm_email: E-Mail bestätigen
     delete_account: Konto löschen
@@ -783,9 +789,9 @@ de:
       <h3 id="collect">Welche Informationen sammeln wir?</h3>
 
       <ul>
-        <li><em>Grundlegende Kontoinformationen</em>: Wenn du dich auf diesem Server registrierst, wirst du darum gebeten, einen Benutzernamen, eine E-Mail-Adresse und ein Passwort einzugeben. Du kannst auch zusätzliche Profilinformationen wie etwa einen Anzeigenamen oder eine Biografie eingeben und ein Profilbild oder ein Headerbild hochladen. Der Benutzername, der Anzeigename, die Biografie, das Profilbild und das Headerbild werden immer öffentlich angezeigt.</li>
+        <li><em>Grundlegende Kontoinformationen</em>: Wenn du dich auf diesem Server registrierst, wirst du darum gebeten, einen Benutzer:innen-Namen, eine E-Mail-Adresse und ein Passwort einzugeben. Du kannst auch zusätzliche Profilinformationen wie etwa einen Anzeigenamen oder eine Biografie eingeben und ein Profilbild oder ein Headerbild hochladen. Der Benutzer:innen-Name, der Anzeigename, die Biografie, das Profilbild und das Headerbild werden immer öffentlich angezeigt.</li>
         <li><em>Beiträge, Folge- und andere öffentliche Informationen</em>: Die Liste der Leute, denen du folgst, wird öffentlich gezeigt, das gleiche gilt für deine Folgenden (Follower). Sobald du eine Nachricht übermittelst, wird das Datum und die Uhrzeit gemeinsam mit der Information, welche Anwendung du dafür verwendet hast, gespeichert. Nachricht können Medienanhänge enthalten, etwa Bilder und Videos. Öffentliche und ungelistete Beiträge sind öffentlich verfügbar. Sobald du einen Beitrag auf deinem Profil featurest, sind dies auch öffentlich verfügbare Informationen. Deine Beiträge werden an deine Folgenden ausgeliefert, was in manchen Fällen bedeutet, dass sie an andere Server ausgeliefert werden und dort Kopien gespeichert werden. Sobald du Beiträge löschst, wird dies ebenso an deine Follower ausgeliefert. Die Handlungen des Teilens und Favorisieren eines anderen Beitrages ist immer öffentlich.</li>
-        <li><em>Direkte und "Nur Folgende"-Beiträge</em>: Alle Beiträge werden auf dem Server gespeichert und verarbeitet. "Nur Folgende"-Beiträge werden an deine Folgenden und an Benutzer, die du in ihnen erwähnst, ausgeliefert, direkte Beiträge nur an in ihnen erwähnte Benutzer. In manchen Fällen bedeutet dass, dass sie an andere Server ausgeliefert werden und dort Kopien gespeichert werden. Wir bemühen uns nach bestem Wissen und Gewissen, den Zugriff auf diese Beiträge auf nur autorisierte Personen einzuschränken, jedoch könnten andere Server dabei scheitern. Deswegen ist es wichtig, die Server, zu denen deine Folgenden gehören, zu überprüfen. Du kannst eine Option in den Einstellungen umschalten, um neue Folgenden manuell anzunehmen oder abzuweisen. <em>Bitte beachte, dass die Betreiber des Server und jedes empfangenden Servers solche Nachrichten anschauen könnten</em> und dass Empfänger von diesen eine Bildschirmkopie erstellen könnten, sie kopieren oder anderweitig weiterverteilen könnten. <em>Teile nicht irgendwelche gefährlichen Informationen über Mastodon.</em></li>
+        <li><em>Direkte und "Nur Folgende"-Beiträge</em>: Alle Beiträge werden auf dem Server gespeichert und verarbeitet. "Nur Folgende"-Beiträge werden an deine Folgenden und an Benutzer:innen, die du in ihnen erwähnst, ausgeliefert, direkte Beiträge nur an in ihnen erwähnte Benutzer:innen. In manchen Fällen bedeutet dass, dass sie an andere Server ausgeliefert werden und dort Kopien gespeichert werden. Wir bemühen uns nach bestem Wissen und Gewissen, den Zugriff auf diese Beiträge auf nur autorisierte Personen einzuschränken, jedoch könnten andere Server dabei scheitern. Deswegen ist es wichtig, die Server, zu denen deine Folgenden gehören, zu überprüfen. Du kannst eine Option in den Einstellungen umschalten, um neue Folgenden manuell anzunehmen oder abzuweisen. <em>Bitte beachte, dass die Betreiber des Server und jedes empfangenden Servers solche Nachrichten anschauen könnten</em> und dass Empfänger von diesen eine Bildschirmkopie erstellen könnten, sie kopieren oder anderweitig weiterverteilen könnten. <em>Teile nicht irgendwelche gefährlichen Informationen über Mastodon.</em></li>
         <li><em>Internet Protocol-Adressen (IP-Adressen) und andere Metadaten</em>: Sobald du dich anmeldest, erfassen wir sowohl die IP-Adresse, von der aus du dich anmeldest, als auch den Namen deine Browseranwendung. Alle angemeldeten Sitzungen (Sessions) sind für deine Überprüfung und Widerruf in den Einstellungen verfügbar. Die letzte verwendete IP-Adresse wird bis zu 12 Monate lang gespeichert. Wir könnten auch Serverprotokoll behalten, welche die IP-Adresse von jeder Anfrage an unseren Server enthalten.</li>
       </ul>
 
@@ -815,7 +821,7 @@ de:
 
       <ul>
         <li>Serverprotokolle, die IP-Adressen von allen deinen Anfragen an diesen Server, falls solche Protokolle behalten werden, für nicht mehr als 90 Tage behalten.</li>
-        <li>registrierten Benutzern zu geordnete IP-Adressen nicht länger als 12 Monate behalten.</li>
+        <li>registrierten Benutzer:innen zugeordnete IP-Adressen nicht länger als 12 Monate behalten.</li>
       </ul>
 
       <p>Du kannst ein Archiv deines Inhalts anfordern und herunterladen, inkludierend deiner Beiträge, Medienanhänge, Profilbilder und Headerbilder.</p>
@@ -914,3 +920,5 @@ de:
     otp_lost_help_html: Wenn Du beides nicht mehr weißt, melde Dich bei uns unter der E-Mailadresse %{email}
     seamless_external_login: Du bist angemeldet über einen Drittanbieter-Dienst, weswegen Passwort- und E-Maileinstellungen nicht verfügbar sind.
     signed_in_as: 'Angemeldet als:'
+  verification:
+    explanation_html: 'Du kannst <strong>bestätigen, dass die Links in deinen Profil-Metadaten dir gehören</strong>. Dafür muss die verlinkte Website einen Link zurück auf dein Mastodon-Profil enthalten. Dieser Link <strong>muss</strong> ein <code>rel="me"</code>-Attribut enthalten. Der Linktext is dabei egal. Hier ist ein Beispiel:'
diff --git a/config/locales/el.yml b/config/locales/el.yml
index fc14d62cd..fbd8a6461 100644
--- a/config/locales/el.yml
+++ b/config/locales/el.yml
@@ -48,6 +48,7 @@ el:
       other: Ακόλουθοι
     following: Ακολουθεί
     joined: Εγγράφηκε στις %{date}
+    link_verified_on: Η κυριότητα αυτού του συνδέσμου ελέγχθηκε στις %{date}
     media: Πολυμέσα
     moved_html: 'Ο/Η %{name} μετακόμισε στο %{new_profile_link}:'
     network_hidden: Αυτή η πληροφορία δεν είναι διαθέσιμη
@@ -120,6 +121,7 @@ el:
       moderation_notes: Σημειώσεις μεσολάβησης
       most_recent_activity: Πιο πρόσφατη δραστηριότητα
       most_recent_ip: Πιο πρόσφατη IP
+      no_limits_imposed: Χωρίς όρια
       not_subscribed: Άνευ συνδρομής
       order:
         alphabetic: Αλφαβητικά
@@ -155,8 +157,10 @@ el:
         report: καταγγελία
         targeted_reports: Αναφορές για αυτόν το λογαριασμό
       silence: Αποσιώπησε
+      silenced: Αποσιωπημένοι
       statuses: Καταστάσεις
       subscribe: Εγγραφή
+      suspended: Σε αναστολή
       title: Λογαριασμοί
       unconfirmed_email: Ανεπιβεβαίωτο email
       undo_silenced: Αναίρεση αποσιώπησης
@@ -300,8 +304,13 @@ el:
       title: Προσκλήσεις
     relays:
       add_new: Πρόσθεσε νέο ανταποκριτή (relay)
+      delete: Διαγραφή
       description_html: Ο <strong>ομοσπονδιακός ανταποκριτής</strong> είναι ένας ενδιάμεσος εξυπηρετητής (server) που ανταλλάσσει μεγάλους όγκους δημόσιων τουτ μεταξύ εξυπηρετητών που εγγράφονται και δημοσιεύουν σε αυτόν. <strong>Βοηθάει μικρούς και μεσαίους εξυπηρετητές να ανακαλύψουν περιεχόμενο στο fediverse</strong>, που υπό άλλες συνθήκες θα χρειαζόταν κάποιους τοπικούς χρήστες που να ακολουθούν χρήστες σε απομακρυσμένους εξυπηρετητές.
+      disable: Απενεργοποίηση
+      disabled: Απενεργοποιημένο
+      enable: Ενεργοποίηση
       enable_hint: Μόλις ενεργοποιηθεί, ο εξυπηρετητής (server) σου θα εγγραφεί σε όλα τα δημόσια τουτ αυτού του ανταποκριτή (relay) και θα αρχίσει να προωθεί τα δικά του δημόσια τουτ σε αυτόν.
+      enabled: Ενεργοποιημένο
       inbox_url: URL ανταποκριτή
       pending: Περιμένοντας την έγκριση του ανταποκριτή
       save_and_enable: Αποθήκευση και ενεργοποίηση
@@ -336,9 +345,7 @@ el:
       reported_by: Αναφέρθηκε από
       resolved: Επιλύθηκε
       resolved_msg: Η καταγγελία επιλύθηκε επιτυχώς!
-      silence_account: Αποσιώπηση λογαριασμού
       status: Κατάσταση
-      suspend_account: Ανέστειλε λογαριασμό
       title: Αναφορές
       unassign: Αποσύνδεση
       unresolved: Άλυτη
@@ -912,3 +919,6 @@ el:
     otp_lost_help_html: Αν χάσεις και τα δύο, μπορείς να επικοινωνήσεις με τον/την %{email}
     seamless_external_login: Επειδή έχεις συνδεθεί μέσω τρίτης υπηρεσίας, οι ρυθμίσεις συνθηματικού και email δεν είναι διαθέσιμες.
     signed_in_as: 'Έχεις συνδεθεί ως:'
+  verification:
+    explanation_html: 'Μπορείς να <strong>πιστοποιήσεις τον εαυτό σου ως ιδιοκτήτη των συνδέσμων που εμφανίζεις στα μεταδεδομένα του προφίλ σου</strong>. Για να συμβεί αυτό, ο συνδεδεμένος ιστότοπος πρέπει να περιέχει ένα σύνδεσμο που να επιστρέφει προς το προφίλ σου στο Mastodon. Ο σύνδεσμος επιστροφής <strong>πρέπει</strong> περιέχει την ιδιότητα (attribute) <code>rel="me"</code>. Το κείμενο κειμένου δεν έχει σημασία. Για παράδειγμα:'
+    verification: Πιστοποίηση
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 6172af1b8..2c679061e 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -128,7 +128,7 @@ en:
         most_recent: Most recent
         title: Order
       outbox_url: Outbox URL
-      perform_full_suspension: Perform full suspension
+      perform_full_suspension: Suspend
       profile_url: Profile URL
       promote: Promote
       protocol: Protocol
@@ -177,6 +177,7 @@ en:
         create_domain_block: "%{name} blocked domain %{target}"
         create_email_domain_block: "%{name} blacklisted e-mail domain %{target}"
         demote_user: "%{name} demoted user %{target}"
+        destroy_custom_emoji: "%{name} destroyed emoji %{target}"
         destroy_domain_block: "%{name} unblocked domain %{target}"
         destroy_email_domain_block: "%{name} whitelisted e-mail domain %{target}"
         destroy_status: "%{name} removed status by %{target}"
@@ -262,6 +263,8 @@ en:
         title: New domain block
       reject_media: Reject media files
       reject_media_hint: Removes locally stored media files and refuses to download any in the future. Irrelevant for suspensions
+      reject_reports: Reject reports
+      reject_reports_hint: Ignore all reports coming from this domain. Irrelevant for suspensions
       severities:
         noop: None
         silence: Silence
@@ -345,9 +348,7 @@ en:
       reported_by: Reported by
       resolved: Resolved
       resolved_msg: Report successfully resolved!
-      silence_account: Silence account
       status: Status
-      suspend_account: Suspend account
       title: Reports
       unassign: Unassign
       unresolved: Unresolved
@@ -369,7 +370,7 @@ en:
         desc_html: Displayed on the frontpage. At least 600x100px recommended. When not set, falls back to instance thumbnail
         title: Hero image
       mascot:
-        desc_html: Displayed on multiple pages. At least 293×205px recommended. When not set, falls back to instance thumbnail
+        desc_html: Displayed on multiple pages. At least 293×205px recommended. When not set, falls back to default mascot
         title: Mascot image
       peers_api_enabled:
         desc_html: Domain names this instance has encountered in the fediverse
diff --git a/config/locales/eo.yml b/config/locales/eo.yml
index 454eeae9d..72628a944 100644
--- a/config/locales/eo.yml
+++ b/config/locales/eo.yml
@@ -325,9 +325,7 @@ eo:
       reported_by: Signalita de
       resolved: Solvita
       resolved_msg: Signalo sukcese solvita!
-      silence_account: Kaŝi konton
       status: Mesaĝoj
-      suspend_account: Haltigi konton
       title: Signaloj
       unassign: Malasigni
       unresolved: Nesolvita
diff --git a/config/locales/es.yml b/config/locales/es.yml
index 3b9e93947..da8febd19 100644
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -336,9 +336,7 @@ es:
       reported_by: Reportado por
       resolved: Resuelto
       resolved_msg: "¡La denuncia se ha resuelto correctamente!"
-      silence_account: Silenciar cuenta
       status: Estado
-      suspend_account: Suspender cuenta
       title: Reportes
       unassign: Desasignar
       unresolved: No resuelto
diff --git a/config/locales/eu.yml b/config/locales/eu.yml
index 1a6558d9f..f0ddb6adb 100644
--- a/config/locales/eu.yml
+++ b/config/locales/eu.yml
@@ -336,9 +336,7 @@ eu:
       reported_by: Salatzailea
       resolved: Konponduta
       resolved_msg: Salaketa ongi konpondu da!
-      silence_account: Isilarazi kontua
       status: Mezua
-      suspend_account: Kanporatu kontua
       title: Salaketak
       unassign: Kendu esleipena
       unresolved: Konpondu gabea
diff --git a/config/locales/fa.yml b/config/locales/fa.yml
index d620dcf4b..a9cf5868f 100644
--- a/config/locales/fa.yml
+++ b/config/locales/fa.yml
@@ -336,9 +336,7 @@ fa:
       reported_by: گزارش از طرف
       resolved: حل‌شده
       resolved_msg: گزارش با موفقیت حل شد!
-      silence_account: بی‌صدا کردن حساب
       status: نوشته
-      suspend_account: معلق‌کردن حساب
       title: گزارش‌ها
       unassign: پس‌گرفتن مسئولیت
       unresolved: حل‌نشده
diff --git a/config/locales/fi.yml b/config/locales/fi.yml
index c2552b539..e62931129 100644
--- a/config/locales/fi.yml
+++ b/config/locales/fi.yml
@@ -282,9 +282,7 @@ fi:
       reported_by: Raportoija
       resolved: Ratkaistut
       resolved_msg: Raportti onnistuneesti ratkaistu!
-      silence_account: Hiljennä tili
       status: Tila
-      suspend_account: Siirrä tili jäähylle
       title: Raportit
       unresolved: Ratkaisemattomat
       updated_at: Päivitetty
@@ -609,7 +607,7 @@ fi:
       uc_browser: UCBrowser
       weibo: Weibo
     current_session: Nykyinen istunto
-    description: "%{selain}, %{platform}"
+    description: "%{browser}, %{platform}"
     explanation: Nämä verkkoselaimet ovat tällä hetkellä kirjautuneet Mastodon-tilillesi.
     ip: IP
     platforms:
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index ba3c90195..f0eaf8d3f 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -48,6 +48,7 @@ fr:
       other: Abonné⋅e⋅s
     following: Abonnements
     joined: Inscrit·e en %{date}
+    link_verified_on: La propriété de ce lien a été vérifiée le %{date}
     media: Médias
     moved_html: "%{name} a changé de compte pour %{new_profile_link} :"
     network_hidden: Cette information n’est pas disponible
@@ -120,6 +121,7 @@ fr:
       moderation_notes: Notes de modération
       most_recent_activity: Dernière activité
       most_recent_ip: Adresse IP la plus récente
+      no_limits_imposed: Aucune limite imposée
       not_subscribed: Non abonné
       order:
         alphabetic: Alphabétique
@@ -155,8 +157,10 @@ fr:
         report: signalement
         targeted_reports: Signalements créés visant ce compte
       silence: Masquer
+      silenced: Silencié
       statuses: Statuts
       subscribe: S’abonner
+      suspended: Suspendu
       title: Comptes
       unconfirmed_email: Courriel non-confirmé
       undo_silenced: Démasquer
@@ -300,8 +304,13 @@ fr:
       title: Invitations
     relays:
       add_new: Ajouter un nouveau relais
+      delete: Effacer
       description_html: Un <strong>relai de fédération</strong> est un serveur intermédiaire qui échange de grandes quantités de pouets entre les serveurs qui publient dessus et ceux qui y sont abonnés. <strong>Il peut aider les petites et moyennes instances à découvrir du contenu sur le fediverse</strong>, ce qui normalement nécessiterait que les membres locaux suivent des gens inscrits sur des serveurs distants.
+      disable: Désactiver
+      disabled: Désactivé
+      enable: Activé
       enable_hint: Une fois activé, votre serveur souscrira à tous les pouets publics présents sur ce relais et y enverra ses propres pouets publics.
+      enabled: Activé
       inbox_url: URL de relais
       pending: En attente de l'approbation du relai
       save_and_enable: Sauvegarder et activer
@@ -336,9 +345,7 @@ fr:
       reported_by: Signalé par
       resolved: Résolus
       resolved_msg: Signalement résolu avec succès !
-      silence_account: Masquer le compte
       status: Statut
-      suspend_account: Suspendre le compte
       title: Signalements
       unassign: Dés-assigner
       unresolved: Non résolus
@@ -452,7 +459,7 @@ fr:
     warning: Soyez prudent⋅e avec ces données. Ne les partagez pas !
     your_token: Votre jeton d’accès
   auth:
-    agreement_html: En vous inscrivant, vous souscrivez <a href="%{rules_path}">aux règles de l’instance</a> et à <a href="%{terms_path}">nos conditions d’utilisation</a>.
+    agreement_html: En cliquant sur "S'inscrire" ci-dessous, vous souscrivez <a href="%{rules_path}">aux règles de l’instance</a> et à <a href="%{terms_path}">nos conditions d’utilisation</a>.
     change_password: Mot de passe
     confirm_email: Confirmer mon adresse mail
     delete_account: Supprimer le compte
@@ -619,7 +626,7 @@ fr:
   notification_mailer:
     digest:
       action: Voir toutes les notifications
-      body: 'Voici ce que vous avez raté sur ${instance} depuis votre dernière visite le %{since} :'
+      body: Voici un bref résumé des messages que vous auriez raté depuis votre dernière visite le %{since}
       mention: "%{name} vous a mentionné⋅e dans :"
       new_followers_summary:
         one: Vous avez un⋅e nouvel⋅le abonné⋅e ! Youpi !
@@ -913,3 +920,6 @@ fr:
     otp_lost_help_html: Si vous perdez accès aux deux, vous pouvez contacter %{email}
     seamless_external_login: Vous êtes connecté via un service externe, donc les paramètres concernant le mot de passe et le courriel ne sont pas disponibles.
     signed_in_as: 'Connecté·e en tant que :'
+  verification:
+    explanation_html: 'Vous pouvez <strong>vérifier vous-même que vous êtes le propriétaire des liens dans les métadonnées de votre profil</strong>. Pour cela, le site Web lié doit contenir un lien vers votre profil Mastodon. Le lien de retour <strong>doit</strong>avoir un attribut <code>rel="me"</code>. Le contenu textuel du lien n''a pas d''importance. En voici un exemple :'
+    verification: Vérification
diff --git a/config/locales/gl.yml b/config/locales/gl.yml
index ad7dbf502..44eda815b 100644
--- a/config/locales/gl.yml
+++ b/config/locales/gl.yml
@@ -48,6 +48,7 @@ gl:
       other: Seguidoras
     following: Seguindo
     joined: Uneuse %{date}
+    link_verified_on: A propiedade de esta ligazón foi comprobada en %{date}
     media: Medios
     moved_html: "%{name} mudouse a %{new_profile_link}:"
     network_hidden: A información non está dispoñible
@@ -120,6 +121,7 @@ gl:
       moderation_notes: Notas de moderación
       most_recent_activity: Actividade máis recente
       most_recent_ip: IP máis recente
+      no_limits_imposed: Sen límites impostos
       not_subscribed: Non suscrita
       order:
         alphabetic: Alfabética
@@ -155,8 +157,10 @@ gl:
         report: informar
         targeted_reports: Informes feitos sobre esta conta
       silence: Acalar
+      silenced: Acalada
       statuses: Estados
       subscribe: Subscribir
+      suspended: Suspendida
       title: Contas
       unconfirmed_email: Correo-e non confirmado
       undo_silenced: Desfacer acalar
@@ -300,8 +304,13 @@ gl:
       title: Convida
     relays:
       add_new: Engadir un novo repetidor
+      delete: Eliminar
       description_html: Un <strong>repetidor da federación</strong> é un servidor intermedio que intercambia grandes volumes de toots públicos entre servidores que se suscriban e publiquen nel. <strong>Pode axudar a servidores pequenos e medios a descubrir contido no fediverso</strong>, o que de outro xeito precisaría que as usuarias locais seguisen a outra xente en servidores remotos.
+      disable: Desactivar
+      disabled: Desactivada
+      enable: Activar
       enable_hint: Unha vez activado, o seu servidor suscribirase a todos os toots públicos de este servidor, e tamén comezará a eviar a el os toots públicos do servidor.
+      enabled: Activada
       inbox_url: URL do repetidor
       pending: Agardando polo permiso do repetidor
       save_and_enable: Gardar e activar
@@ -336,9 +345,7 @@ gl:
       reported_by: Reportada por
       resolved: Resolto
       resolved_msg: Resolveuse con éxito o informe!
-      silence_account: Acalar conta
       status: Estado
-      suspend_account: Suspender conta
       title: Informes
       unassign: Non asignar
       unresolved: Non resolto
@@ -452,7 +459,7 @@ gl:
     warning: Teña moito tino con estos datos. Nunca os comparta con ninguén!
     your_token: O seu testemuño de acceso
   auth:
-    agreement_html: Rexistrándose acorda seguir <a href="%{rules_path}">as normas da instancia</a> e <a href="%{terms_path}">os termos do servizo</a>.
+    agreement_html: Ao pulsar "Rexistrar" vostede acorda seguir <a href="%{rules_path}">as normas da instancia</a> e <a href="%{terms_path}">os termos do servizo</a>.
     change_password: Contrasinal
     confirm_email: Confirmar correo-e
     delete_account: Eliminar conta
@@ -912,3 +919,6 @@ gl:
     otp_lost_help_html: Si perde o acceso a ambos, pode contactar con %{email}
     seamless_external_login: Está conectado a través de un servizo externo, polo que os axustes de contrasinal e correo-e non están dispoñibles.
     signed_in_as: 'Rexistrada como:'
+  verification:
+    explanation_html: 'Pode <strong>validarse a vostede mesma como a dona das ligazóns nos metadatos do seu perfil</strong>. Para esto, o sitio web ligado debe conter unha ligazón de retorno ao perfil de Mastodon. Esta ligazón de retorno <strong>ten que</strong> ter un atributo <code>rel="me"</code>. O texto da ligazón non importa. Aquí ten un exemplo:'
+    verification: Validación
diff --git a/config/locales/he.yml b/config/locales/he.yml
index 3d24f22d2..09d57da3b 100644
--- a/config/locales/he.yml
+++ b/config/locales/he.yml
@@ -189,9 +189,7 @@ he:
       reported_account: חשבון מדווח
       reported_by: דווח על ידי
       resolved: פתור
-      silence_account: השתקת חשבון
       status: הודעה
-      suspend_account: השעיית חשבון
       title: דיווחים
       unresolved: לא פתור
     settings:
diff --git a/config/locales/hu.yml b/config/locales/hu.yml
index 0c4046785..92d11f0d8 100644
--- a/config/locales/hu.yml
+++ b/config/locales/hu.yml
@@ -249,9 +249,7 @@ hu:
       reported_account: Bejelentett fiók
       reported_by: 'Jelentette:'
       resolved: Megoldott
-      silence_account: Felhasználó némítása
       status: Állapot
-      suspend_account: Felhasználó felfüggesztése
       title: Jelentések
       unresolved: Megoldatlan
     settings:
diff --git a/config/locales/id.yml b/config/locales/id.yml
index b186b7652..3da3583f6 100644
--- a/config/locales/id.yml
+++ b/config/locales/id.yml
@@ -114,9 +114,7 @@ id:
       reported_account: Akun yang dilaporkan
       reported_by: Dilaporkan oleh
       resolved: Terseleseikan
-      silence_account: Akun yang didiamkan
       status: Status
-      suspend_account: Akun yang disuspen
       title: Laporan
       unresolved: Belum Terseleseikan
     settings:
diff --git a/config/locales/io.yml b/config/locales/io.yml
index be8a87acd..b739df3af 100644
--- a/config/locales/io.yml
+++ b/config/locales/io.yml
@@ -107,9 +107,7 @@ io:
       reported_account: Reported account
       reported_by: Reported by
       resolved: Resolved
-      silence_account: Silence account
       status: Status
-      suspend_account: Suspend account
       title: Reports
       unresolved: Unresolved
     settings:
diff --git a/config/locales/it.yml b/config/locales/it.yml
index 5780f1e0c..6a831ab2c 100644
--- a/config/locales/it.yml
+++ b/config/locales/it.yml
@@ -324,9 +324,7 @@ it:
       report: 'Rapporto #%{id}'
       reported_by: Inviato da
       resolved: Risolto
-      silence_account: Silenzia account
       status: Stato
-      suspend_account: Sospendi account
       title: Rapporti
       unassign: Non assegnare
       unresolved: Non risolto
@@ -535,6 +533,7 @@ it:
     generate: Genera
     invited_by: 'Sei stato invitato da:'
     max_uses:
+      one: un uso
       other: "%{count} utilizzi"
     max_uses_prompt: Nessun limite
     prompt: Genera e condividi dei link ad altri per garantire l'accesso a questa istanza
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index 630898104..60e1109c5 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -48,6 +48,7 @@ ja:
       other: フォロワー
     following: フォロー中
     joined: "%{date} に登録"
+    link_verified_on: このリンクの所有権は %{date} に確認されました
     media: メディア
     moved_html: "%{name} さんは引っ越しました %{new_profile_link}:"
     network_hidden: この情報は利用できません
@@ -176,6 +177,7 @@ ja:
         create_domain_block: "%{name} さんがドメイン %{target} をブロックしました"
         create_email_domain_block: "%{name} さんがドメイン %{target} をメールアドレス用ブラックリストに追加しました"
         demote_user: "%{name} さんが %{target} さんを降格しました"
+        destroy_custom_emoji: "%{name} さんがカスタム絵文字 %{target} を削除しました"
         destroy_domain_block: "%{name} さんがドメイン %{target} のブロックを外しました"
         destroy_email_domain_block: "%{name} さんがドメイン %{target} をメールアドレス用ブラックリストから外しました"
         destroy_status: "%{name} さんが %{target} さんの投稿を削除しました"
@@ -344,9 +346,7 @@ ja:
       reported_by: 報告者
       resolved: 解決済み
       resolved_msg: レポートを解決済みにしました!
-      silence_account: アカウントをサイレンス
       status: ステータス
-      suspend_account: アカウントを停止
       title: レポート
       unassign: 担当を外す
       unresolved: 未解決
@@ -368,7 +368,7 @@ ja:
         desc_html: フロントページに表示されます。サイズは600x100px以上推奨です。未設定の場合、インスタンスのサムネイルが使用されます
         title: ヒーローイメージ
       mascot:
-        desc_html: 複数のページに表示されます。サイズは293x205px以上推奨です。未設定の場合、インスタンスのサムネイルが使用されます
+        desc_html: 複数のページに表示されます。サイズは293x205px以上推奨です。未設定の場合、標準のマスコットが使用されます
         title: マスコットイメージ
       peers_api_enabled:
         desc_html: 連合内でこのインスタンスが遭遇したドメインの名前
@@ -463,7 +463,7 @@ ja:
     warning: このデータは気をつけて取り扱ってください。他の人と共有しないでください!
     your_token: アクセストークン
   auth:
-    agreement_html: 登録すると <a href="%{rules_path}">インスタンスのルール</a> と <a href="%{terms_path}">プライバシーポリシー</a> に従うことに同意したことになります。
+    agreement_html: 登録するをクリックすると <a href="%{rules_path}">インスタンスのルール</a> と <a href="%{terms_path}">プライバシーポリシー</a> に従うことに同意したことになります。
     change_password: パスワード
     confirm_email: メールアドレスの確認
     delete_account: アカウントの削除
@@ -926,3 +926,6 @@ ja:
     otp_lost_help_html: どちらも使用できない場合、%{email} に連絡を取ると解決できるかもしれません
     seamless_external_login: あなたは外部サービスを介してログインしているため、パスワードとメールアドレスの設定は利用できません。
     signed_in_as: '下記でログイン中:'
+  verification:
+    explanation_html: <strong>プロフィール内のリンクの所有者であることを認証することができます</strong>。そのためにはリンクされたウェブサイトにMastodonプロフィールへのリンクが含まれている必要があります。リンクには<code>rel="me"</code>属性を<strong>必ず</strong>与えなければなりません。リンクのテキストについては重要ではありません。以下は例です:
+    verification: 認証
diff --git a/config/locales/ka.yml b/config/locales/ka.yml
index f782db09b..5ac254df4 100644
--- a/config/locales/ka.yml
+++ b/config/locales/ka.yml
@@ -325,9 +325,7 @@ ka:
       reported_by: დაარეპორტა
       resolved: გადაწყვეტილი
       resolved_msg: რეპორტი წარმატებით გადაწყდა!
-      silence_account: ანგარიშის გაჩუმება
       status: სტატუსი
-      suspend_account: ანგარიშის შეჩერება
       title: რეპორტები
       unassign: გადაყენება
       unresolved: გადაუწყვეტელი
diff --git a/config/locales/ko.yml b/config/locales/ko.yml
index 6f281a302..9f9875a16 100644
--- a/config/locales/ko.yml
+++ b/config/locales/ko.yml
@@ -338,9 +338,7 @@ ko:
       reported_by: 신고자
       resolved: 해결됨
       resolved_msg: 리포트가 성공적으로 해결되었습니다!
-      silence_account: 계정을 침묵 처리
       status: 상태
-      suspend_account: 계정을 정지
       title: 신고
       unassign: 할당 해제
       unresolved: 미해결
diff --git a/config/locales/nl.yml b/config/locales/nl.yml
index 6a27602d0..0c1add32a 100644
--- a/config/locales/nl.yml
+++ b/config/locales/nl.yml
@@ -336,9 +336,7 @@ nl:
       reported_by: Gerapporteerd door
       resolved: Opgelost
       resolved_msg: Rapportage succesvol opgelost!
-      silence_account: Account negeren
       status: Toot
-      suspend_account: Account opschorten
       title: Rapportages
       unassign: Niet langer toewijzen
       unresolved: Onopgelost
diff --git a/config/locales/no.yml b/config/locales/no.yml
index bbfa9b5da..61466fa20 100644
--- a/config/locales/no.yml
+++ b/config/locales/no.yml
@@ -249,9 +249,7 @@
       reported_account: Rapportert konto
       reported_by: Rapportert av
       resolved: Løst
-      silence_account: Målbind konto
       status: Status
-      suspend_account: Utvis konto
       title: Rapporter
       unresolved: Uløst
     settings:
diff --git a/config/locales/oc.yml b/config/locales/oc.yml
index 373d2ed44..22d0775f9 100644
--- a/config/locales/oc.yml
+++ b/config/locales/oc.yml
@@ -144,7 +144,6 @@ oc:
       role: Permissions
       roles:
         admin: Administrator
-        bot: Robòt
         moderator: Moderador
         staff: Personnal
         user: Uitlizaire
@@ -337,9 +336,7 @@ oc:
       reported_by: Senhalat per
       resolved: Resolgut
       resolved_msg: Rapòrt corrèctament resolgut  !
-      silence_account: Metre lo compte en silenci
       status: Estatut
-      suspend_account: Suspendre lo compte
       title: Senhalament
       unassign: Levar
       unresolved: Pas resolgut
diff --git a/config/locales/pl.yml b/config/locales/pl.yml
index 703ec0c26..c75f3ebc8 100644
--- a/config/locales/pl.yml
+++ b/config/locales/pl.yml
@@ -354,9 +354,7 @@ pl:
       reported_by: Zgłaszający
       resolved: Rozwiązane
       resolved_msg: Pomyślnie rozwiązano zgłoszenie.
-      silence_account: Wycisz konto
       status: Stan
-      suspend_account: Zawieś konto
       title: Zgłoszenia
       unassign: Cofnij przypisanie
       unresolved: Nierozwiązane
diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml
index 9eb0d7968..d6593baa1 100644
--- a/config/locales/pt-BR.yml
+++ b/config/locales/pt-BR.yml
@@ -334,9 +334,7 @@ pt-BR:
       reported_by: Denunciada por
       resolved: Resolvido
       resolved_msg: Denúncia resolvida com sucesso!
-      silence_account: Silenciar conta
       status: Status
-      suspend_account: Suspender conta
       title: Denúncias
       unassign: Desatribuir
       unresolved: Não resolvido
diff --git a/config/locales/pt.yml b/config/locales/pt.yml
index 2bada74fe..5f532ea37 100644
--- a/config/locales/pt.yml
+++ b/config/locales/pt.yml
@@ -249,9 +249,7 @@ pt:
       reported_account: Conta denunciada
       reported_by: Denúnciada por
       resolved: Resolvido
-      silence_account: Conta silenciada
       status: Estado
-      suspend_account: Conta suspensa
       title: Denúncias
       unresolved: Por resolver
     settings:
diff --git a/config/locales/ru.yml b/config/locales/ru.yml
index e8bbb94ca..2eef00170 100644
--- a/config/locales/ru.yml
+++ b/config/locales/ru.yml
@@ -345,9 +345,7 @@ ru:
       reported_by: Отправитель жалобы
       resolved: Разрешено
       resolved_msg: Жалоба успешно обработана!
-      silence_account: Заглушить аккаунт
       status: Статус
-      suspend_account: Блокировать аккаунт
       title: Жалобы
       unassign: Снять назначение
       unresolved: Неразрешенные
diff --git a/config/locales/simple_form.ar.yml b/config/locales/simple_form.ar.yml
index 783e545e1..dcdc1ffc1 100644
--- a/config/locales/simple_form.ar.yml
+++ b/config/locales/simple_form.ar.yml
@@ -9,6 +9,7 @@ ar:
         context: واحد أو أكثر من السياقات التي يجب أن ينطبق عليها عامل التصفية
         digest: تُرسَل إليك بعد مُضيّ مدة مِن خمول نشاطك و فقط إذا ما تلقيت رسائل شخصية مباشِرة أثناء فترة غيابك مِن الشبكة
         display_name: <span class="name-counter">%{count}</span> حرف باق
+        email: سوف تتلقى رسالة إلكترونية للتأكيد
         fields: يُمكنك عرض 4 عناصر على شكل جدول في ملفك الشخصي
         header: ملف PNG أو GIF أو JPG. حجمه على أقصى تصدير %{size}. سيتم تصغيره إلى %{dimensions}px
         inbox_url: نسخ العنوان الذي تريد استخدامه مِن صفحة الإستقبال للمُرحَّل
@@ -16,12 +17,17 @@ ar:
         locale: لغة واجهة المستخدم و الرسائل الإلكترونية و الإشعارات
         locked: يتطلب منك الموافقة يدويا على طلبات المتابعة
         note: <span class="note-counter">%{count}</span> حرف باق
+        password: يُنصح باستخدام 8 أحرف على الأقل
         phrase: سوف يتم العثور عليه مهما كان نوع النص أو حتى و إن كان داخل الويب فيه تحذير عن المحتوى
         scopes: ما هي المجالات المسموح بها في التطبيق ؟ إن قمت باختيار أعلى المجالات فيمكنك الإستغناء عن الخَيار اليدوي.
         setting_default_language: يمكن الكشف التلقائي للّغة اللتي استخدمتها في تحرير تبويقاتك ، غيرَ أنّ العملية ليست دائما دقيقة
+        setting_display_media_default: إخفاء الوسائط المُعيَّنة كحساسة
+        setting_display_media_hide_all: إخفاء كافة الوسائط دائمًا
+        setting_display_media_show_all: دائمًا عرض الوسائط المُعيَّنة كحساسة
         setting_hide_network: الحسابات التي تُتابعها و التي تُتابِعك على حد سواء لن تُعرَض على صفحتك الشخصية
         setting_noindex: ذلك يؤثر على حالة ملفك الشخصي و صفحاتك
         setting_theme: ذلك يؤثر على الشكل الذي سيبدو عليه ماستدون عندما تقوم بالدخول مِن أي جهاز.
+        username: اسم المستخدم الخاص بك سوف يكون فريدا مِن نوعه على %{domain}
       imports:
         data: ملف CSV تم تصديره مِن مثيل خادوم ماستدون آخر
       sessions:
@@ -64,6 +70,11 @@ ar:
         setting_default_privacy: خصوصية المنشور
         setting_default_sensitive: إعتبر الوسائط دائما كمحتوى حساس
         setting_delete_modal: إظهار مربع حوار للتأكيد قبل حذف أي تبويق
+        setting_display_media: عرض الوسائط
+        setting_display_media_default: افتراضي
+        setting_display_media_hide_all: اخفاء الكل
+        setting_display_media_show_all: عرض الكل
+        setting_expand_spoilers: توسيع التبويقات التي تحتوي على تحذيرات عن المحتوى تلقائيا
         setting_hide_network: إخفِ شبكتك
         setting_noindex: عدم السماح لمحركات البحث بفهرسة ملفك الشخصي
         setting_reduce_motion: تخفيض عدد الصور في الوسائط المتحركة
diff --git a/config/locales/simple_form.co.yml b/config/locales/simple_form.co.yml
index 6f1630e6a..c4a6bd169 100644
--- a/config/locales/simple_form.co.yml
+++ b/config/locales/simple_form.co.yml
@@ -11,6 +11,7 @@ co:
         display_name:
           one: Ci ferma <span class="name-counter">1</span> caratteru
           other: Ci fermanu <span class="name-counter">%{count}</span> caratteri
+        email: Avete da riceve un'e-mail di cunfirmazione
         fields: Pudete avè fin’à 4 elementi mustrati cum’un tavulone nant’à u vostru prufile
         header: Furmatu PNG, GIF o JPG. 2Mo o menu. Sarà ridottu à %{dimensions}px
         inbox_url: Cupiate l'URL di a pagina d'accolta di u ripetitore chì vulete utilizà
@@ -20,12 +21,17 @@ co:
         note:
           one: Ci ferma <span class="name-counter">1</span> caratteru
           other: Ci fermanu <span class="name-counter">%{count}</span> caratteri
+        password: Ci volenu almenu 8 caratteri
         phrase: Sarà trovu senza primura di e maiuscule o di l'avertimenti
         scopes: L'API à quelle l'applicazione averà accessu. S'è voi selezziunate un parametru d'altu livellu, un c'hè micca bisognu di selezziunà quell'individuali.
         setting_default_language: A lingua di i vostri statuti pò esse induvinata autumaticamente, mà ùn marchja micca sempre bè
+        setting_display_media_default: Piattà i media marcati cum'è sensibili
+        setting_display_media_hide_all: Sempre piattà tutti i media
+        setting_display_media_show_all: Sempre affissà i media marcati cum'è sensibili
         setting_hide_network: I vostri abbunati è abbunamenti ùn saranu micca mustrati nant’à u vostru prufile
         setting_noindex: Tocca à u vostru prufile pubblicu è i vostri statuti
         setting_theme: Tocca à l’apparenza di Mastodon quandu site cunnettatu·a da qualch’apparechju.
+        username: U vostru cugnome sarà unicu nant'à %{domain}
         whole_word: Quandu a parolla o a frasa sana hè alfanumerica, sarà applicata solu s'ella currisponde à a parolla sana
       imports:
         data: Un fugliale CSV da un’altr’istanza di Mastodon
@@ -69,6 +75,11 @@ 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_media: Affissera di i media
+        setting_display_media_default: Predefinitu
+        setting_display_media_hide_all: Piattà tuttu
+        setting_display_media_show_all: Affissà tuttu
+        setting_expand_spoilers: Sempre slibrà i statutu marcati cù un'avertimentu CW
         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 dbff52644..ed50e13ff 100644
--- a/config/locales/simple_form.cs.yml
+++ b/config/locales/simple_form.cs.yml
@@ -11,6 +11,7 @@ cs:
         display_name:
           one: Zbývá <span class="name-counter">1</span> znak
           other: Zbývá vám <span class="name-counter">%{count}</span> znaků
+        email: Bude vám poslán potvrzovací e-mail
         fields: Na profilu můžete mít až 4 položky zobrazené jako tabulka
         header: PNG, GIF či JPG. Maximálně %{size}. Bude zmenšena na %{dimensions} px
         inbox_url: Zkopírujte URL z hlavní stránky mostu, který chcete použít
@@ -20,12 +21,17 @@ cs:
         note:
           one: Zbývá <span class="note-counter">1</span>znak
           other: Zbývá <span class="note-counter">%{count}</span> znaků
+        password: Použijte alespoň 8 znaků
         phrase: Shoda bude nalezena bez ohledu na velikost písmen v těle tootu či varování o obsahu
         scopes: Které API bude aplikace povolena používat. Pokud vyberete rozsah nejvyššího stupně, nebudete je muset vybírat po jednom.
         setting_default_language: Jazyk vašich tootů může být detekován automaticky, není to však vždy přesné
+        setting_display_media_default: Skrývat média označená jako citlivá
+        setting_display_media_hide_all: Vždy skrývat všechna média
+        setting_display_media_show_all: Vždy zobrazovat média označená jako citlivá
         setting_hide_network: Koho sledujete a kdo sleduje vás nebude zobrazeno na vašem profilu
         setting_noindex: Ovlivňuje váš veřejný profil a stránky příspěvků
         setting_theme: Ovlivňuje jak Mastodon vypadá, jste-li přihlášen na libovolném zařízení.
+        username: Vaše uživatelské jméno bude na %{domain} unikátní
         whole_word: Je-li klíčové slovo či fráze pouze alfanumerická, bude aplikována pouze, pokud se shoduje s celým slovem
       imports:
         data: Soubor CSV exportován z jiné instance Mastodon
@@ -69,6 +75,11 @@ 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_media: Zobrazování médií
+        setting_display_media_default: Výchozí
+        setting_display_media_hide_all: Skrýt vše
+        setting_display_media_show_all: Zobrazit vše
+        setting_expand_spoilers: Vždy rozbalit tooty označené varováními o obsahu
         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.de.yml b/config/locales/simple_form.de.yml
index e13eece79..cca9361e4 100644
--- a/config/locales/simple_form.de.yml
+++ b/config/locales/simple_form.de.yml
@@ -11,6 +11,7 @@ de:
         display_name:
           one: <span class="name-counter">1</span> Zeichen verbleibt
           other: <span class="name-counter">%{count}</span> Zeichen verbleiben
+        email: Du wirst ein Bestätigungs-E-Mail erhalten
         fields: Du kannst bis zu 4 Elemente als Tabelle dargestellt auf deinem Profil anzeigen lassen
         header: PNG, GIF oder JPG. Maximal %{size}. Wird auf 700×335 px herunterskaliert
         inbox_url: Kopiere die URL von der Startseite des gewünschten Relays
@@ -20,12 +21,17 @@ de:
         note:
           one: <span class="note-counter">1</span> Zeichen verbleibt
           other: <span class="note-counter">%{count}</span> Zeichen verbleiben
+        password: Verwende mindestens 8 Zeichen
         phrase: Wird unabhängig vom umgebenen Text oder Inhaltswarnung eines Beitrags verglichen
         scopes: Welche Schnittstellen der Applikation erlaubt sind. Wenn du einen Top-Level-Scope auswählst, dann musst du nicht jeden einzelnen darunter auswählen.
         setting_default_language: Die Sprache der Beiträge kann automatisch erkannt werden, aber dies ist nicht immer genau
+        setting_display_media_default: Verstecke Medien, die als sensibel markiert sind
+        setting_display_media_hide_all: Alle Medien immer verstecken
+        setting_display_media_show_all: Medien, die als sensibel markiert sind, immer anzeigen
         setting_hide_network: Wem du folgst und wer dir folgt wird in deinem Profil nicht angezeigt
         setting_noindex: Betrifft dein öffentliches Profil und deine Beiträge
         setting_theme: Wirkt sich darauf aus, wie Mastodon aussieht, egal auf welchem Gerät du eingeloggt bist.
+        username: Dein Benutzer:innen-Name wird auf %{domain} nur einmal vorkommen
         whole_word: Wenn das Schlüsselwort oder -phrase nur Buchstaben und Zahlen enthält, wird es nur angewendet werden, wenn es dem ganzen Wort entspricht
       imports:
         data: CSV-Datei, die aus einer anderen Mastodon-Instanz exportiert wurde
@@ -69,6 +75,11 @@ 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_media: Medien-Anzeige
+        setting_display_media_default: Standard
+        setting_display_media_hide_all: Alle verstecken
+        setting_display_media_show_all: Alle anzeigen
+        setting_expand_spoilers: Toots mit Inhaltswarnungen immer ausklappen
         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 96a7547e4..823f25330 100644
--- a/config/locales/simple_form.el.yml
+++ b/config/locales/simple_form.el.yml
@@ -11,6 +11,7 @@ el:
         display_name:
           one: απομένει <span class="name-counter">1</span> χαρακτήρας
           other: απομένουν <span class="name-counter">%{count}</span> χαρακτήρες
+        email: Θα σου σταλεί email επιβεβαίωσης
         fields: Μπορείς να έχεις έως 4 σημειώσεις σε μορφή πίνακα στο προφίλ σου
         header: PNG, GIF ή JPG. Έως %{size}. Θα περιοριστεί σε διάσταση %{dimensions}px
         inbox_url: Αντέγραψε το URL της αρχικής σελίδας του ανταποκριτή (relay) που θέλεις να χρησιμοποιήσεις
@@ -20,12 +21,17 @@ el:
         note:
           one: απομένει <span class="note-counter">1</span> χαρακτήρας
           other: απομένουν <span class="note-counter">%{count}</span> χαρακτήρες
+        password: Χρησιμοποίησε τουλάχιστον 8 χαρακτήρες
         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: Επηρεάζει την εμφάνιση του Mastodon όταν συνδέεται από οποιαδήποτε συσκευή.
+        username: Το όνομα χρήστη σου θα είναι μοναδικό στο %{domain}
         whole_word: Όταν η λέξη ή η φράση κλειδί είναι μόνο αλφαριθμητική, θα εφαρμοστεί μόνο αν ταιριάζει με ολόκληρη τη λέξη
       imports:
         data: Αρχείο CSV που έχει εξαχθεί από διαφορετικό κόμβο Mastodon
@@ -69,6 +75,11 @@ el:
         setting_default_privacy: Ιδιωτικότητα δημοσιεύσεων
         setting_default_sensitive: Σημείωνε πάντα τα πολυμέσα ως ευαίσθητου περιεχομένου
         setting_delete_modal: Εμφάνιση ερώτησης επιβεβαίωσης πριν διαγράψεις ένα τουτ
+        setting_display_media: Εμφάνιση πολυμέσων
+        setting_display_media_default: Προκαθορισμένο
+        setting_display_media_hide_all: Απόκρυψη όλων
+        setting_display_media_show_all: Εμφάνιση όλων
+        setting_expand_spoilers: Μόνιμη ανάπτυξη των τουτ με προειδοποίηση περιεχομένου
         setting_hide_network: Κρύψε τις διασυνδέσεις σου
         setting_noindex: Επέλεξε να μην συμμετέχεις στα αποτελέσματα μηχανών αναζήτησης
         setting_reduce_motion: Μείωση κίνησης κινουμένων στοιχείων
diff --git a/config/locales/simple_form.fa.yml b/config/locales/simple_form.fa.yml
index 418b308b1..3e2398d55 100644
--- a/config/locales/simple_form.fa.yml
+++ b/config/locales/simple_form.fa.yml
@@ -11,6 +11,7 @@ fa:
         display_name:
           one: <span class="name-counter">1</span> حرف باقی مانده
           other: <span class="name-counter">%{count}</span> حرف باقی مانده
+        email: به شما ایمیل تأییدی فرستاده خواهد شد
         fields: شما می‌توانید تا چهار مورد را در یک جدول در نمایهٔ خود نمایش دهید
         header: یکی از قالب‌های PNG یا  GIF یا JPG. بیشترین اندازه %{size}. تصویر به اندازهٔ %{dimensions} پیکسل تبدیل خواهد شد
         inbox_url: نشانی صفحهٔ اصلی رله‌ای را که می‌خواهید به کار ببرید کپی کنید
@@ -20,12 +21,17 @@ fa:
         note:
           one: <span class="note-counter">1</span> حرف باقی مانده
           other: <span class="note-counter">%{count}</span> حرف باقی مانده
+        password: دست‌کم باید ۸ نویسه داشته باشد
         phrase: مستقل از کوچکی و بزرگی حروف، با متن اصلی یا هشدار محتوای بوق‌ها مقایسه می‌شود
         scopes: واسط‌های برنامه‌نویسی که این برنامه به آن دسترسی دارد. اگر بالاترین سطح دسترسی را انتخاب کنید، دیگر نیازی به انتخاب سطح‌های پایینی ندارید.
         setting_default_language: زبان نوشته‌های شما به طور خودکار تشخیص داده می‌شود، ولی این تشخصی همیشه دقیق نیست
+        setting_display_media_default: تصویرهایی را که به عنوان حساس علامت زده شده‌اند پنهان کن
+        setting_display_media_hide_all: همیشه همهٔ عکس‌ها و ویدیوها را پنهان کن
+        setting_display_media_show_all: همیشه تصویرهایی را که به عنوان حساس علامت زده شده‌اند را نشان بده
         setting_hide_network: فهرست پیگیران شما و فهرست کسانی که شما پی می‌گیرید روی نمایهٔ شما دیده نخواهد شد
         setting_noindex: روی نمایهٔ عمومی و صفحهٔ نوشته‌های شما تأثیر می‌گذارد
         setting_theme: ظاهر ماستدون را وقتی که از هر دستگاهی به آن وارد می‌شوید تعیین می‌کند.
+        username: نام کاربری شما روی %{domain} یکتا خواهد بود
         whole_word: اگر کلیدواژه فقط دارای حروف و اعداد باشد، تنها وقتی پیدا می‌شود که با کل یک واژه در متن منطبق باشد، نه با بخشی از یک واژه
       imports:
         data: پروندهٔ CSV که از سرور ماستدون دیگری برون‌سپاری شده
@@ -69,6 +75,11 @@ fa:
         setting_default_privacy: حریم خصوصی نوشته‌ها
         setting_default_sensitive: همیشه تصاویر را به عنوان حساس علامت بزن
         setting_delete_modal: نمایش پیغام تأیید پیش از پاک کردن یک نوشته
+        setting_display_media: نمایش عکس و ویدیو
+        setting_display_media_default: پیش‌فرض
+        setting_display_media_hide_all: نهفتن همه
+        setting_display_media_show_all: نمایش همه
+        setting_expand_spoilers: همیشه بوق‌هایی را که هشدار محتوا دارند کامل نشان بده
         setting_hide_network: نهفتن شبکهٔ ارتباطی
         setting_noindex: درخواست از موتورهای جستجوگر برای ظاهر نشدن در نتایج جستجو
         setting_reduce_motion: کاستن از حرکت در پویانمایی‌ها
diff --git a/config/locales/simple_form.fr.yml b/config/locales/simple_form.fr.yml
index 1e0c4d3e6..6403bced3 100644
--- a/config/locales/simple_form.fr.yml
+++ b/config/locales/simple_form.fr.yml
@@ -11,6 +11,7 @@ fr:
         display_name:
           one: <span class="name-counter">1</span> caractère restant
           other: <span class="name-counter">%{count}</span> caractères restants
+        email: Vous recevrez un courriel de confirmation
         fields: Vous pouvez avoir jusqu’à 4 éléments affichés en tant que tableau sur votre profil
         header: Au format PNG, GIF ou JPG. 2 Mo maximum. Sera réduit à %{dimensions}px
         inbox_url: Copiez l’URL depuis la page d’accueil du relais que vous souhaitez utiliser
@@ -20,12 +21,17 @@ fr:
         note:
           one: <span class="note-counter">1</span> caractère restant
           other: <span class="note-counter">%{count}</span> caractères restants
+        password: Utilisez au moins 8 caractères
         phrase: Sera trouvé sans que la case ou l’avertissement de contenu du pouet soit pris en compte
         scopes: À quelles APIs l’application sera autorisée à accéder. Si vous sélectionnez un périmètre de haut-niveau, vous n’avez pas besoin de sélectionner les individuels.
         setting_default_language: La langue de vos pouets peut être détectée automatiquement, mais ça n’est pas toujours pertinent
+        setting_display_media_default: Masquer les supports marqués comme sensibles
+        setting_display_media_hide_all: Toujours masquer tous les médias
+        setting_display_media_show_all: Toujours afficher les médias marqués comme sensibles
         setting_hide_network: Ceux que vous suivez et ceux qui vous suivent ne seront pas affichés sur votre profil
         setting_noindex: Affecte votre profil public ainsi que vos statuts
         setting_theme: Affecte l’apparence de Mastodon quand vous êtes connecté·e depuis n’importe quel appareil.
+        username: Votre nom d'utilisateur sera unique sur %{domain}
         whole_word: Lorsque le mot-clef ou la phrase-clef est uniquement alphanumérique, ça sera uniquement appliqué s’il correspond au mot entier
       imports:
         data: Un fichier CSV généré par une autre instance de Mastodon
@@ -69,6 +75,11 @@ 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_media: Affichage des médias
+        setting_display_media_default: Défaut
+        setting_display_media_hide_all: Masquer tout
+        setting_display_media_show_all: Montrer tout
+        setting_expand_spoilers: Toujours développer les pouëts marqués d'un avertissement de contenu
         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 935545b0e..f81d34610 100644
--- a/config/locales/simple_form.gl.yml
+++ b/config/locales/simple_form.gl.yml
@@ -11,6 +11,7 @@ gl:
         display_name:
           one: <span class="name-counter">1</span> caracter restante
           other: <span class="name-counter">%{count}</span> caracteres restantes
+        email: Enviaráselle un correo-e de confirmación
         fields: Pode ter ate 4 elementos no seu perfil mostrados como unha táboa
         header: PNG, GIF ou JPG. Máximo %{size}. Será reducida a %{dimensions}px
         inbox_url: Copiar o URL desde a páxina de inicio do repetidor que quere utilizar
@@ -20,12 +21,17 @@ gl:
         note:
           one: <span class="note-counter">1</span> caracter restante
           other: <span class="note-counter">%{count}</span> caracteres restantes
+        password: Utilice 8 caracteres ao menos
         phrase: Concordará independentemente das maiúsculas ou avisos de contido no toot
         scopes: A que APIs terá acceso a aplicación. Si selecciona un ámbito de alto nivel, non precisa seleccionar elementos individuais.
         setting_default_language: Pódese detectar automáticamente o idioma dos seus toots, mais non sempre é preciso
+        setting_display_media_default: Ocultar medios marcados como sensibles
+        setting_display_media_hide_all: Ocultar sempre os medios
+        setting_display_media_show_all: Mostrar sempre os medios marcados como sensibles
         setting_hide_network: Non se mostrará no seu perfil quen a segue e quen a está a seguir
         setting_noindex: Afecta ao seu perfil público e páxinas de estado
         setting_theme: Afecta ao aspecto de Mastodon en calquer dispositivo cando está conectada.
+        username: O seu nome de usuaria será único en %{domain}
         whole_word: Si a chave ou frase de paso é só alfanumérica, só se aplicará si concorda a palabra completa
       imports:
         data: Ficheiro CSV exportado desde outra instancia Mastodon
@@ -69,6 +75,11 @@ 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_media: Mostrar medios
+        setting_display_media_default: Por omisión
+        setting_display_media_hide_all: Ocultar todo
+        setting_display_media_show_all: Mostrar todo
+        setting_expand_spoilers: Despregar sempre as mensaxes marcadas con avisos de contido
         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.ja.yml b/config/locales/simple_form.ja.yml
index 71e2f935e..413fe4d41 100644
--- a/config/locales/simple_form.ja.yml
+++ b/config/locales/simple_form.ja.yml
@@ -9,6 +9,7 @@ ja:
         context: フィルターを適用する対象 (複数選択可)
         digest: 長期間使用していない場合と不在時に返信を受けた場合のみ送信されます
         display_name: あと<span class="name-counter">%{count}</span>文字入力できます。
+        email: 確認のメールが送信されます
         fields: プロフィールに表として4つまでの項目を表示することができます
         header: "%{size}までのPNG、GIF、JPGが利用可能です。 %{dimensions}pxまで縮小されます"
         inbox_url: 使用したいリレーサーバーのトップページからURLをコピーします
@@ -16,6 +17,7 @@ ja:
         locale: ユーザーインターフェース、メールやプッシュ通知の言語
         locked: フォロワーを手動で承認する必要があります
         note: あと<span class="note-counter">%{count}</span>文字入力できます。
+        password: 少なくとも8文字は入力してください
         phrase: トゥートの大文字小文字や閲覧注意に関係なく一致
         scopes: アプリの API に許可するアクセス権を選択してください。最上位のスコープを選択する場合、個々のスコープを選択する必要はありません。
         setting_default_language: トゥートの言語は自動的に検出されますが、必ずしも正確とは限りません
@@ -25,6 +27,7 @@ ja:
         setting_hide_network: フォローとフォロワーの情報がプロフィールページで見られないようにします
         setting_noindex: 公開プロフィールおよび各投稿ページに影響します
         setting_theme: ログインしている全てのデバイスで適用されるデザインです。
+        username: あなたのユーザー名は %{domain} の中で重複していない必要があります
         whole_word: キーワードまたはフレーズが英数字のみの場合、単語全体と一致する場合のみ適用されるようになります
       imports:
         data: 他の Mastodon インスタンスからエクスポートしたCSVファイルを選択して下さい
diff --git a/config/locales/sk.yml b/config/locales/sk.yml
index 01100ffb8..024b9ad20 100644
--- a/config/locales/sk.yml
+++ b/config/locales/sk.yml
@@ -337,9 +337,7 @@ sk:
       reported_by: Nahlásené užívateľom
       resolved: Vyriešené
       resolved_msg: Hlásenie úspešne vyriešené!
-      silence_account: Zamĺčať účet
       status: Stav
-      suspend_account: Pozastaviť účet
       title: Reporty
       unassign: Odobrať
       unresolved: Nevyriešené
diff --git a/config/locales/sr-Latn.yml b/config/locales/sr-Latn.yml
index d6800a8fb..ff31203c8 100644
--- a/config/locales/sr-Latn.yml
+++ b/config/locales/sr-Latn.yml
@@ -251,9 +251,7 @@ sr-Latn:
       reported_account: Prijavljeni nalog
       reported_by: Prijavio
       resolved: Rešeni
-      silence_account: Ućutkaj nalog
       status: Status
-      suspend_account: Suspenduj nalog
       title: Prijave
       unresolved: Nerešeni
     settings:
diff --git a/config/locales/sr.yml b/config/locales/sr.yml
index 53981b0f0..36d81886e 100644
--- a/config/locales/sr.yml
+++ b/config/locales/sr.yml
@@ -338,9 +338,7 @@ sr:
       reported_by: Пријавио
       resolved: Решена
       resolved_msg: Пријава успешно разрешена!
-      silence_account: Ућуткај налог
       status: Статус
-      suspend_account: Суспендуј налог
       title: Пријаве
       unassign: Уклони доделу
       unresolved: Нерешене
diff --git a/config/locales/sv.yml b/config/locales/sv.yml
index b7229aebe..4f80a46f1 100644
--- a/config/locales/sv.yml
+++ b/config/locales/sv.yml
@@ -285,9 +285,7 @@ sv:
       reported_by: Anmäld av
       resolved: Löst
       resolved_msg: Anmälan har lösts framgångsrikt!
-      silence_account: Tysta ner konto
       status: Status
-      suspend_account: Suspendera konto
       title: Anmälningar
       unassign: Otilldela
       unresolved: Olösta
diff --git a/config/locales/th.yml b/config/locales/th.yml
index 8c411f252..3ed73c7f5 100644
--- a/config/locales/th.yml
+++ b/config/locales/th.yml
@@ -116,9 +116,7 @@ th:
       reported_account: รายงานแอคเคาท์
       reported_by: รายงานโดย
       resolved: จัดการแล้ว
-      silence_account: แอคเค๊าท์ที่ปิดเสียง
       status: สถานะ
-      suspend_account: แอคเค๊าท์ที่หยุดไว้
       title: รายงาน
       unresolved: Unresolved
     settings:
diff --git a/config/locales/tr.yml b/config/locales/tr.yml
index d7ecb480f..99ba89397 100644
--- a/config/locales/tr.yml
+++ b/config/locales/tr.yml
@@ -115,9 +115,7 @@ tr:
       reported_account: Şikayet edilen hesap
       reported_by: Şikayet eden
       resolved: Giderildi
-      silence_account: Hesabı sustur
       status: Durum
-      suspend_account: Hesabı uzaklaştır
       title: Şikayetler
       unresolved: Giderilmedi
     settings:
diff --git a/config/locales/uk.yml b/config/locales/uk.yml
index 22d5e98df..83a315a37 100644
--- a/config/locales/uk.yml
+++ b/config/locales/uk.yml
@@ -313,9 +313,7 @@ uk:
       reported_by: Відправник скарги
       resolved: Вирішено
       resolved_msg: Скаргу успішно вирішено!
-      silence_account: Заглушити акаунт
       status: Статус
-      suspend_account: Заблокувати акаунт
       title: Скарги
       unassign: Зняти призначення
       unresolved: Невирішені
diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml
index 9a1b47fdb..0ce1a0ed7 100644
--- a/config/locales/zh-CN.yml
+++ b/config/locales/zh-CN.yml
@@ -332,9 +332,7 @@ zh-CN:
       reported_by: 举报人
       resolved: 已处理
       resolved_msg: 举报处理成功!
-      silence_account: 隐藏用户
       status: 状态
-      suspend_account: 封禁用户
       title: 举报
       unassign: 取消接管
       unresolved: 未处理
diff --git a/config/locales/zh-HK.yml b/config/locales/zh-HK.yml
index abbb1b809..db7c0c47c 100644
--- a/config/locales/zh-HK.yml
+++ b/config/locales/zh-HK.yml
@@ -285,9 +285,7 @@ zh-HK:
       reported_by: 舉報者
       resolved: 已處理
       resolved_msg: 舉報已處理。
-      silence_account: 將用戶靜音
       status: 狀態
-      suspend_account: 將用戶停權
       title: 舉報
       unassign: 取消指派
       unresolved: 未處理
diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml
index 338c40d09..d1b7633f3 100644
--- a/config/locales/zh-TW.yml
+++ b/config/locales/zh-TW.yml
@@ -295,9 +295,7 @@ zh-TW:
       reported_by: 檢舉人
       resolved: 已解決
       resolved_msg: 檢舉已處理!
-      silence_account: 靜音使用者
       status: 狀態
-      suspend_account: 停權使用者
       title: 檢舉
       unassign: 取消指派
       unresolved: 未解決
diff --git a/config/routes.rb b/config/routes.rb
index 84c37b89e..446aad58b 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -267,7 +267,12 @@ Rails.application.routes.draw do
       resources :streaming, only: [:index]
       resources :custom_emojis, only: [:index]
       resources :suggestions, only: [:index, :destroy]
-      resources :conversations, only: [:index]
+
+      resources :conversations, only: [:index, :destroy] do
+        member do
+          post :read
+        end
+      end
 
       get '/search', to: 'search#index', as: :search
 
diff --git a/db/migrate/20181010141500_add_silent_to_mentions.rb b/db/migrate/20181010141500_add_silent_to_mentions.rb
new file mode 100644
index 000000000..dbb4fba26
--- /dev/null
+++ b/db/migrate/20181010141500_add_silent_to_mentions.rb
@@ -0,0 +1,23 @@
+require Rails.root.join('lib', 'mastodon', 'migration_helpers')
+
+class AddSilentToMentions < ActiveRecord::Migration[5.2]
+  include Mastodon::MigrationHelpers
+
+  disable_ddl_transaction!
+
+  def up
+    safety_assured do
+      add_column_with_default(
+        :mentions,
+        :silent,
+        :boolean,
+        allow_null: false,
+        default: false
+      )
+    end
+  end
+
+  def down
+    remove_column :mentions, :silent
+  end
+end
diff --git a/db/migrate/20181017170937_add_reject_reports_to_domain_blocks.rb b/db/migrate/20181017170937_add_reject_reports_to_domain_blocks.rb
new file mode 100644
index 000000000..f05d50fcd
--- /dev/null
+++ b/db/migrate/20181017170937_add_reject_reports_to_domain_blocks.rb
@@ -0,0 +1,17 @@
+require Rails.root.join('lib', 'mastodon', 'migration_helpers')
+
+class AddRejectReportsToDomainBlocks < ActiveRecord::Migration[5.2]
+  include Mastodon::MigrationHelpers
+
+  disable_ddl_transaction!
+
+  def up
+    safety_assured do
+      add_column_with_default :domain_blocks, :reject_reports, :boolean, default: false, allow_null: false
+    end
+  end
+
+  def down
+    remove_column :domain_blocks, :reject_reports
+  end
+end
diff --git a/db/migrate/20181018205649_add_unread_to_account_conversations.rb b/db/migrate/20181018205649_add_unread_to_account_conversations.rb
new file mode 100644
index 000000000..3c28b9a64
--- /dev/null
+++ b/db/migrate/20181018205649_add_unread_to_account_conversations.rb
@@ -0,0 +1,23 @@
+require Rails.root.join('lib', 'mastodon', 'migration_helpers')
+
+class AddUnreadToAccountConversations < ActiveRecord::Migration[5.2]
+  include Mastodon::MigrationHelpers
+
+  disable_ddl_transaction!
+
+  def up
+    safety_assured do
+      add_column_with_default(
+        :account_conversations,
+        :unread,
+        :boolean,
+        allow_null: false,
+        default: false
+      )
+    end
+  end
+
+  def down
+    remove_column :account_conversations, :unread, :boolean
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index f9019e8cf..5bfb2d067 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 2018_10_07_025445) do
+ActiveRecord::Schema.define(version: 2018_10_18_205649) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "plpgsql"
@@ -22,6 +22,7 @@ ActiveRecord::Schema.define(version: 2018_10_07_025445) do
     t.bigint "status_ids", default: [], null: false, array: true
     t.bigint "last_status_id"
     t.integer "lock_version", default: 0, null: false
+    t.boolean "unread", default: false, null: false
     t.index ["account_id", "conversation_id", "participant_account_ids"], name: "index_unique_conversations", unique: true
     t.index ["account_id"], name: "index_account_conversations_on_account_id"
     t.index ["conversation_id"], name: "index_account_conversations_on_conversation_id"
@@ -195,6 +196,7 @@ ActiveRecord::Schema.define(version: 2018_10_07_025445) do
     t.datetime "updated_at", null: false
     t.integer "severity", default: 0
     t.boolean "reject_media", default: false, null: false
+    t.boolean "reject_reports", default: false, null: false
     t.index ["domain"], name: "index_domain_blocks_on_domain", unique: true
   end
 
@@ -311,6 +313,7 @@ ActiveRecord::Schema.define(version: 2018_10_07_025445) do
     t.datetime "created_at", null: false
     t.datetime "updated_at", null: false
     t.bigint "account_id"
+    t.boolean "silent", default: false, null: false
     t.index ["account_id", "status_id"], name: "index_mentions_on_account_id_and_status_id", unique: true
     t.index ["status_id"], name: "index_mentions_on_status_id"
   end
diff --git a/docker-compose.yml b/docker-compose.yml
index 064d5a260..d9f80a38a 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -6,18 +6,16 @@ services:
     image: postgres:9.6-alpine
     networks:
       - internal_network
-### Uncomment to enable DB persistence
-#    volumes:
-#      - ./postgres:/var/lib/postgresql/data
+    volumes:
+      - ./postgres:/var/lib/postgresql/data
 
   redis:
     restart: always
     image: redis:4.0-alpine
     networks:
       - internal_network
-### Uncomment to enable REDIS persistence
-#    volumes:
-#      - ./redis:/data
+    volumes:
+      - ./redis:/data
 
 #  es:
 #    restart: always
@@ -26,9 +24,8 @@ services:
 #      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
 #    networks:
 #      - internal_network
-#### Uncomment to enable ES persistence
-##    volumes:
-##      - ./elasticsearch:/usr/share/elasticsearch/data
+#    volumes:
+#      - ./elasticsearch:/usr/share/elasticsearch/data
 
   web:
     build: .
@@ -68,7 +65,7 @@ services:
     image: tootsuite/mastodon
     restart: always
     env_file: .env.production
-    command: bundle exec sidekiq -q default -q push -q mailers -q pull
+    command: bundle exec sidekiq
     depends_on:
       - db
       - redis
diff --git a/lib/mastodon/accounts_cli.rb b/lib/mastodon/accounts_cli.rb
index 704cf474b..a32bc9533 100644
--- a/lib/mastodon/accounts_cli.rb
+++ b/lib/mastodon/accounts_cli.rb
@@ -223,7 +223,7 @@ module Mastodon
       dry_run           = options[:dry_run] ? ' (DRY RUN)' : ''
 
       Account.remote.where(protocol: :activitypub).partitioned.find_each do |account|
-        next if account.updated_at >= skip_threshold || account.last_webfingered_at >= skip_threshold
+        next if account.updated_at >= skip_threshold || (account.last_webfingered_at.present? && account.last_webfingered_at >= skip_threshold)
 
         unless dead_servers.include?(account.domain)
           begin
@@ -239,7 +239,7 @@ module Mastodon
           end
         end
 
-        if [404, 410].include?(code) || dead_servers.include?(account.domain)
+        if [404, 410].include?(code)
           unless options[:dry_run]
             SuspendAccountService.new.call(account)
             account.destroy
@@ -252,6 +252,18 @@ module Mastodon
         end
       end
 
+      # Remove dead servers
+      unless dead_servers.empty? || options[:dry_run]
+        dead_servers.each do |domain|
+          Account.where(domain: domain).find_each do |account|
+            SuspendAccountService.new.call(account)
+            account.destroy
+            culled += 1
+            say('.', :green, false)
+          end
+        end
+      end
+
       say
       say("Removed #{culled} accounts (#{dead_servers.size} dead servers)#{dry_run}", :green)
 
diff --git a/lib/mastodon/feeds_cli.rb b/lib/mastodon/feeds_cli.rb
index c3fca723e..cca65cf87 100644
--- a/lib/mastodon/feeds_cli.rb
+++ b/lib/mastodon/feeds_cli.rb
@@ -54,6 +54,11 @@ module Mastodon
       elsif username.present?
         account = Account.find_local(username)
 
+        if account.nil?
+          say("Account #{username} is not found", :red)
+          exit(1)
+        end
+
         if options[:background]
           RegenerationWorker.perform_async(account.id) unless options[:dry_run]
         else
diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb
index fc7fa5aca..b4b88dfdc 100644
--- a/lib/mastodon/version.rb
+++ b/lib/mastodon/version.rb
@@ -9,7 +9,7 @@ module Mastodon
     end
 
     def minor
-      5
+      6
     end
 
     def patch
@@ -21,7 +21,7 @@ module Mastodon
     end
 
     def flags
-      ''
+      'rc1'
     end
 
     def to_a
diff --git a/spec/controllers/auth/sessions_controller_spec.rb b/spec/controllers/auth/sessions_controller_spec.rb
index b4f912717..71fcc1a6e 100644
--- a/spec/controllers/auth/sessions_controller_spec.rb
+++ b/spec/controllers/auth/sessions_controller_spec.rb
@@ -55,7 +55,7 @@ RSpec.describe Auth::SessionsController, type: :controller do
       request.env['devise.mapping'] = Devise.mappings[:user]
     end
 
-    context 'using PAM authentication' do
+    context 'using PAM authentication', if: ENV['PAM_ENABLED'] == 'true' do
       context 'using a valid password' do
         before do
           post :create, params: { user: { email: "pam_user1", password: '123456' } }
diff --git a/spec/lib/activitypub/activity/create_spec.rb b/spec/lib/activitypub/activity/create_spec.rb
index 62b9db8c2..cd20b7c7c 100644
--- a/spec/lib/activitypub/activity/create_spec.rb
+++ b/spec/lib/activitypub/activity/create_spec.rb
@@ -105,6 +105,31 @@ RSpec.describe ActivityPub::Activity::Create do
       end
     end
 
+    context 'limited' do
+      let(:recipient) { Fabricate(:account) }
+
+      let(:object_json) do
+        {
+          id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join,
+          type: 'Note',
+          content: 'Lorem ipsum',
+          to: ActivityPub::TagManager.instance.uri_for(recipient),
+        }
+      end
+
+      it 'creates status' do
+        status = sender.statuses.first
+
+        expect(status).to_not be_nil
+        expect(status.visibility).to eq 'limited'
+      end
+
+      it 'creates silent mention' do
+        status = sender.statuses.first
+        expect(status.mentions.first).to be_silent
+      end
+    end
+
     context 'direct' do
       let(:recipient) { Fabricate(:account) }
 
@@ -114,6 +139,10 @@ RSpec.describe ActivityPub::Activity::Create do
           type: 'Note',
           content: 'Lorem ipsum',
           to: ActivityPub::TagManager.instance.uri_for(recipient),
+          tag: {
+            type: 'Mention',
+            href: ActivityPub::TagManager.instance.uri_for(recipient),
+          },
         }
       end
 
diff --git a/streaming/index.js b/streaming/index.js
index debf7c8bf..b4d09d0ad 100644
--- a/streaming/index.js
+++ b/streaming/index.js
@@ -74,6 +74,7 @@ const startMaster = () => {
   if (!process.env.SOCKET && process.env.PORT && isNaN(+process.env.PORT)) {
     log.warn('UNIX domain socket is now supported by using SOCKET. Please migrate from PORT hack.');
   }
+
   log.info(`Starting streaming API server master with ${numWorkers} workers`);
 };
 
@@ -449,6 +450,11 @@ const startWorker = (workerId) => {
     });
   };
 
+  const httpNotFound = res => {
+    res.writeHead(404, { 'Content-Type': 'application/json' });
+    res.end(JSON.stringify({ error: 'Not found' }));
+  };
+
   app.use(setRequestId);
   app.use(setRemoteAddress);
   app.use(allowCrossDomain);
@@ -490,11 +496,25 @@ const startWorker = (workerId) => {
   });
 
   app.get('/api/v1/streaming/hashtag', (req, res) => {
-    streamFrom(`timeline:hashtag:${req.query.tag.toLowerCase()}`, req, streamToHttp(req, res), streamHttpEnd(req), true);
+    const { tag } = req.query;
+
+    if (!tag || tag.length === 0) {
+      httpNotFound(res);
+      return;
+    }
+
+    streamFrom(`timeline:hashtag:${tag.toLowerCase()}`, req, streamToHttp(req, res), streamHttpEnd(req), true);
   });
 
   app.get('/api/v1/streaming/hashtag/local', (req, res) => {
-    streamFrom(`timeline:hashtag:${req.query.tag.toLowerCase()}:local`, req, streamToHttp(req, res), streamHttpEnd(req), true);
+    const { tag } = req.query;
+
+    if (!tag || tag.length === 0) {
+      httpNotFound(res);
+      return;
+    }
+
+    streamFrom(`timeline:hashtag:${tag.toLowerCase()}:local`, req, streamToHttp(req, res), streamHttpEnd(req), true);
   });
 
   app.get('/api/v1/streaming/list', (req, res) => {
@@ -502,8 +522,7 @@ const startWorker = (workerId) => {
 
     authorizeListAccess(listId, req, authorized => {
       if (!authorized) {
-        res.writeHead(404, { 'Content-Type': 'application/json' });
-        res.end(JSON.stringify({ error: 'Not found' }));
+        httpNotFound(res);
         return;
       }
 
@@ -553,9 +572,19 @@ const startWorker = (workerId) => {
       streamFrom(channel, req, streamToWs(req, ws), streamWsEnd(req, ws, subscriptionHeartbeat(channel)), true);
       break;
     case 'hashtag':
+      if (!location.query.tag || location.query.tag.length === 0) {
+        ws.close();
+        return;
+      }
+
       streamFrom(`timeline:hashtag:${location.query.tag.toLowerCase()}`, req, streamToWs(req, ws), streamWsEnd(req, ws), true);
       break;
     case 'hashtag:local':
+      if (!location.query.tag || location.query.tag.length === 0) {
+        ws.close();
+        return;
+      }
+
       streamFrom(`timeline:hashtag:${location.query.tag.toLowerCase()}:local`, req, streamToWs(req, ws), streamWsEnd(req, ws), true);
       break;
     case 'list':
@@ -588,16 +617,9 @@ const startWorker = (workerId) => {
     });
   }, 30000);
 
-  if (process.env.SOCKET || process.env.PORT && isNaN(+process.env.PORT)) {
-    server.listen(process.env.SOCKET || process.env.PORT, () => {
-      fs.chmodSync(server.address(), 0o666);
-      log.info(`Worker ${workerId} now listening on ${server.address()}`);
-    });
-  } else {
-    server.listen(+process.env.PORT || 4000, process.env.BIND || '0.0.0.0', () => {
-      log.info(`Worker ${workerId} now listening on ${server.address().address}:${server.address().port}`);
-    });
-  }
+  attachServerWithConfig(server, address => {
+    log.info(`Worker ${workerId} now listening on ${address}`);
+  });
 
   const onExit = () => {
     log.info(`Worker ${workerId} exiting, bye bye`);
@@ -617,9 +639,48 @@ const startWorker = (workerId) => {
   process.on('uncaughtException', onError);
 };
 
-throng({
-  workers: numWorkers,
-  lifetime: Infinity,
-  start: startWorker,
-  master: startMaster,
+const attachServerWithConfig = (server, onSuccess) => {
+  if (process.env.SOCKET || process.env.PORT && isNaN(+process.env.PORT)) {
+    server.listen(process.env.SOCKET || process.env.PORT, () => {
+      if (onSuccess) {
+        fs.chmodSync(server.address(), 0o666);
+        onSuccess(server.address());
+      }
+    });
+  } else {
+    server.listen(+process.env.PORT || 4000, process.env.BIND || '0.0.0.0', () => {
+      if (onSuccess) {
+        onSuccess(`${server.address().address}:${server.address().port}`);
+      }
+    });
+  }
+};
+
+const onPortAvailable = onSuccess => {
+  const testServer = http.createServer();
+
+  testServer.once('error', err => {
+    onSuccess(err);
+  });
+
+  testServer.once('listening', () => {
+    testServer.once('close', () => onSuccess());
+    testServer.close();
+  });
+
+  attachServerWithConfig(testServer);
+};
+
+onPortAvailable(err => {
+  if (err) {
+    log.error('Could not start server, the port or socket is in use');
+    return;
+  }
+
+  throng({
+    workers: numWorkers,
+    lifetime: Infinity,
+    start: startWorker,
+    master: startMaster,
+  });
 });